aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rw-r--r--.travis.yml26
-rw-r--r--CONTRIBUTING.md1
-rw-r--r--HOWTO/INSTALL.md4
-rw-r--r--Makefile.in15
-rw-r--r--bootstrap/bin/no_dot_erlang.bootbin6374 -> 6445 bytes
-rw-r--r--bootstrap/bin/start.bootbin6374 -> 6445 bytes
-rw-r--r--bootstrap/bin/start_clean.bootbin6374 -> 6445 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_a.beambin2712 -> 3396 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_asm.beambin11328 -> 11232 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_block.beambin12080 -> 2712 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bs.beambin5464 -> 3400 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_bsm.beambin11936 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_clean.beambin6564 -> 3568 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dead.beambin13892 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_dict.beambin5060 -> 4900 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_disasm.beambin21728 -> 21396 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_except.beambin3216 -> 3104 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_flatten.beambin2988 -> 1940 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_jump.beambin9132 -> 10068 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beambin0 -> 32404 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_listing.beambin1332 -> 1612 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_opcodes.beambin7304 -> 7548 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_peep.beambin3036 -> 3840 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_receive.beambin6112 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_record.beambin2236 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_reorder.beambin1904 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_split.beambin2168 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa.beambin0 -> 12296 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_bsm.beambin0 -> 18708 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_codegen.beambin0 -> 38944 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_dead.beambin0 -> 12436 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_funs.beambin0 -> 2556 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_lint.beambin0 -> 7672 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_opt.beambin0 -> 32224 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_pp.beambin0 -> 5500 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beambin0 -> 43428 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_recv.beambin0 -> 4036 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_ssa_type.beambin0 -> 17592 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_trim.beambin7540 -> 7304 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_type.beambin18744 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_utils.beambin22624 -> 10460 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_validator.beambin31848 -> 35496 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/beam_z.beambin3284 -> 3300 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl.beambin30144 -> 28604 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_clauses.beambin2932 -> 2856 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_inline.beambin37800 -> 36700 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_sets.beambin2860 -> 2840 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/cerl_trees.beambin22408 -> 21740 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compile.beambin41384 -> 41628 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.app22
-rw-r--r--bootstrap/lib/compiler/ebin/compiler.appup2
-rw-r--r--bootstrap/lib/compiler/ebin/core_lib.beambin4292 -> 4088 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_lint.beambin12880 -> 12548 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_parse.beambin63104 -> 63300 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_pp.beambin11964 -> 11832 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/core_scan.beambin6672 -> 6452 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/erl_bifs.beambin2204 -> 2076 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/rec_env.beambin4588 -> 4536 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_alias.beambin5984 -> 5796 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_bsm.beambin5120 -> 1680 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_dsetel.beambin6708 -> 6376 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold.beambin47536 -> 48364 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_fold_lists.beambin4408 -> 3900 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_core_inline.beambin3992 -> 3872 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/sys_pre_attributes.beambin2716 -> 2600 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_codegen.beambin65424 -> 0 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_core.beambin57676 -> 55288 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel.beambin55832 -> 53044 bytes
-rw-r--r--bootstrap/lib/compiler/ebin/v3_kernel_pp.beambin12744 -> 12500 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application.beambin3772 -> 3752 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_controller.beambin31400 -> 31152 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_master.beambin6344 -> 6308 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/application_starter.beambin1188 -> 1208 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/auth.beambin6332 -> 6328 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code.beambin13136 -> 13048 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/code_server.beambin24136 -> 23956 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log.beambin32124 -> 31696 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_1.beambin23896 -> 23784 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/disk_log_server.beambin6360 -> 6268 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_ac.beambin24844 -> 24524 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/dist_util.beambin13044 -> 12612 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_boot_server.beambin5744 -> 5712 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_ddll.beambin2864 -> 2812 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_distribution.beambin1620 -> 1624 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_epmd.beambin7248 -> 7164 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_reply.beambin900 -> 892 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erl_signal_handler.beambin1112 -> 1108 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_handler.beambin1596 -> 1596 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/error_logger.beambin6132 -> 6160 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/erts_debug.beambin8220 -> 9392 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file.beambin14052 -> 13724 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_io_server.beambin15708 -> 15344 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/file_server.beambin5096 -> 5096 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_sctp.beambin3188 -> 3228 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_tcp.beambin2076 -> 2096 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/gen_udp.beambin1312 -> 1324 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global.beambin31236 -> 30816 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_group.beambin16916 -> 16540 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/global_search.beambin3076 -> 3036 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group.beambin14948 -> 14800 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/group_history.beambin5720 -> 5668 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/heart.beambin5352 -> 5304 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/hipe_unified_loader.beambin12500 -> 12640 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet.beambin23632 -> 23152 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_sctp.beambin1464 -> 1476 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_tcp.beambin2988 -> 2896 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet6_udp.beambin1752 -> 1724 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_config.beambin7532 -> 7420 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_db.beambin26440 -> 26044 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_dns.beambin19268 -> 18720 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_gethost_native.beambin10084 -> 10044 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_hosts.beambin1976 -> 1952 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_parse.beambin13828 -> 13696 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_res.beambin13784 -> 13560 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_sctp.beambin2180 -> 2192 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp.beambin2680 -> 2656 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_tcp_dist.beambin7700 -> 7708 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/inet_udp.beambin1924 -> 1916 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.app6
-rw-r--r--bootstrap/lib/kernel/ebin/kernel.beambin3596 -> 3616 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel_config.beambin2748 -> 2736 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/kernel_refc.beambin2464 -> 2424 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/local_tcp.beambin2248 -> 2212 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/local_udp.beambin1412 -> 1392 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger.beambin11312 -> 11600 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_backend.beambin2620 -> 2588 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_config.beambin3428 -> 3424 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_disk_log_h.beambin9460 -> 9340 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_filters.beambin1800 -> 1780 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_formatter.beambin7796 -> 9084 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_h_common.beambin5672 -> 5464 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_handler_watcher.beambin0 -> 1368 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_server.beambin10476 -> 10380 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_simple_h.beambin4464 -> 4352 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_std_h.beambin10872 -> 10776 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/logger_sup.beambin524 -> 576 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net.beambin608 -> 608 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_adm.beambin2920 -> 2908 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/net_kernel.beambin25644 -> 25392 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/os.beambin5148 -> 5124 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/pg2.beambin7856 -> 7732 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/ram_file.beambin6248 -> 6168 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io.beambin1724 -> 1716 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_compressed.beambin2364 -> 2360 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_deflate.beambin2704 -> 2684 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_delayed.beambin5428 -> 5352 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_inflate.beambin4240 -> 4324 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/raw_file_io_list.beambin2608 -> 2508 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/rpc.beambin7940 -> 7856 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/seq_trace.beambin1600 -> 1592 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/standard_error.beambin3828 -> 3784 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user.beambin11488 -> 11320 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user_drv.beambin11184 -> 11080 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/user_sup.beambin1736 -> 1720 bytes
-rw-r--r--bootstrap/lib/kernel/ebin/wrap_log_reader.beambin3124 -> 3100 bytes
-rw-r--r--bootstrap/lib/kernel/include/dist.hrl2
-rw-r--r--bootstrap/lib/kernel/include/dist_util.hrl2
-rw-r--r--bootstrap/lib/kernel/include/logger.hrl4
-rw-r--r--bootstrap/lib/stdlib/ebin/array.beambin11844 -> 11788 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/base64.beambin6304 -> 6264 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/beam_lib.beambin19436 -> 19360 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/binary.beambin2952 -> 2932 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/c.beambin17408 -> 17268 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/calendar.beambin7816 -> 7704 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets.beambin48916 -> 47808 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_server.beambin6732 -> 6664 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_utils.beambin27380 -> 26600 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dets_v9.beambin47832 -> 46872 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/dict.beambin9516 -> 9548 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph.beambin7848 -> 7784 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/digraph_utils.beambin6824 -> 6776 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin.beambin10952 -> 11068 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/edlin_expand.beambin3976 -> 3916 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/epp.beambin29720 -> 29448 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_abstract_code.beambin1020 -> 1020 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_anno.beambin3628 -> 3580 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_bits.beambin2452 -> 2464 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_compile.beambin7168 -> 7080 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_error.beambin8368 -> 8472 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_eval.beambin35988 -> 36156 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_expand_records.beambin21760 -> 21688 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_internal.beambin7808 -> 6868 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_lint.beambin91872 -> 90012 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_parse.beambin97468 -> 98044 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_posix_msg.beambin5160 -> 5168 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_pp.beambin26528 -> 26376 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_scan.beambin28204 -> 27000 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/erl_tar.beambin33388 -> 32768 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_file_h.beambin4056 -> 4016 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/error_logger_tty_h.beambin4936 -> 4888 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/escript.beambin16832 -> 16612 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ets.beambin22460 -> 22180 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/eval_bits.beambin8144 -> 7912 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/file_sorter.beambin29136 -> 28820 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filelib.beambin10684 -> 10480 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/filename.beambin15144 -> 14884 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_sets.beambin8376 -> 8324 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gb_trees.beambin5572 -> 5548 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen.beambin5068 -> 4992 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_event.beambin13972 -> 13872 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_fsm.beambin11476 -> 11416 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_server.beambin15012 -> 14996 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/gen_statem.beambin20676 -> 20116 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io.beambin6044 -> 6052 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib.beambin13444 -> 13772 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_format.beambin14840 -> 14584 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_fread.beambin7156 -> 7192 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/io_lib_pretty.beambin21956 -> 21812 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/lists.beambin30004 -> 29528 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/log_mf_h.beambin2468 -> 2412 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/maps.beambin3520 -> 3244 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ms_transform.beambin19532 -> 19420 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/orddict.beambin2928 -> 2932 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/ordsets.beambin1952 -> 1940 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/otp_internal.beambin10596 -> 10176 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/pool.beambin3744 -> 3736 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proc_lib.beambin12448 -> 12124 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/proplists.beambin4708 -> 4628 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc.beambin68896 -> 67720 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/qlc_pt.beambin74944 -> 74520 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/queue.beambin6124 -> 6172 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/rand.beambin22352 -> 22208 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/random.beambin1728 -> 1748 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/re.beambin13240 -> 12800 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sets.beambin6608 -> 6560 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell.beambin29848 -> 29492 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/shell_default.beambin4064 -> 4064 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/slave.beambin4816 -> 4780 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sofs.beambin37312 -> 36564 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/stdlib.app2
-rw-r--r--bootstrap/lib/stdlib/ebin/string.beambin37096 -> 35796 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor.beambin23352 -> 23116 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/supervisor_bridge.beambin2400 -> 2384 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/sys.beambin8728 -> 8708 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/timer.beambin5424 -> 5412 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode.beambin13456 -> 13460 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/unicode_util.beambin194724 -> 204280 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/uri_string.beambin26396 -> 26416 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/win32reg.beambin5356 -> 5276 bytes
-rw-r--r--bootstrap/lib/stdlib/ebin/zip.beambin26156 -> 25960 bytes
-rw-r--r--bootstrap/lib/stdlib/include/assert.hrl6
-rw-r--r--configure.src435
-rw-r--r--erts/aclocal.m4250
-rw-r--r--erts/autoconf/vxworks/sed.general2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_cpu322
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc322
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc6032
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_ppc8602
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simlinux2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_simso2
-rw-r--r--erts/autoconf/vxworks/sed.vxworks_sparc2
-rw-r--r--erts/configure.in926
-rw-r--r--erts/doc/src/absform.xml4
-rw-r--r--erts/doc/src/erl_nif.xml4
-rw-r--r--erts/doc/src/erlang.xml4
-rw-r--r--erts/doc/src/escript.xml26
-rw-r--r--erts/doc/src/match_spec.xml7
-rw-r--r--erts/doc/src/notes.xml619
-rw-r--r--erts/doc/src/time_correction.xml4
-rw-r--r--erts/emulator/Makefile.in6
-rw-r--r--erts/emulator/beam/atom.names2
-rw-r--r--erts/emulator/beam/beam_bif_load.c5
-rw-r--r--erts/emulator/beam/beam_debug.c5
-rw-r--r--erts/emulator/beam/beam_emu.c35
-rw-r--r--erts/emulator/beam/beam_load.c53
-rw-r--r--erts/emulator/beam/bif.c55
-rw-r--r--erts/emulator/beam/bif.tab1
-rw-r--r--erts/emulator/beam/big.h2
-rw-r--r--erts/emulator/beam/break.c1
-rw-r--r--erts/emulator/beam/bs_instrs.tab309
-rw-r--r--erts/emulator/beam/dist.c386
-rw-r--r--erts/emulator/beam/dist.h9
-rw-r--r--erts/emulator/beam/erl_alloc.c7
-rw-r--r--erts/emulator/beam/erl_alloc.types6
-rw-r--r--erts/emulator/beam/erl_bif_binary.c303
-rw-r--r--erts/emulator/beam/erl_bif_ddll.c2
-rw-r--r--erts/emulator/beam/erl_bif_info.c38
-rw-r--r--erts/emulator/beam/erl_bif_lists.c162
-rw-r--r--erts/emulator/beam/erl_bif_re.c64
-rw-r--r--erts/emulator/beam/erl_bif_unique.h6
-rw-r--r--erts/emulator/beam/erl_bits.c36
-rw-r--r--erts/emulator/beam/erl_bits.h13
-rw-r--r--erts/emulator/beam/erl_db.c82
-rw-r--r--erts/emulator/beam/erl_db.h29
-rw-r--r--erts/emulator/beam/erl_db_catree.c2225
-rw-r--r--erts/emulator/beam/erl_db_catree.h133
-rw-r--r--erts/emulator/beam/erl_db_hash.c59
-rw-r--r--erts/emulator/beam/erl_db_tree.c1697
-rw-r--r--erts/emulator/beam/erl_db_tree_util.h158
-rw-r--r--erts/emulator/beam/erl_db_util.c9
-rw-r--r--erts/emulator/beam/erl_db_util.h40
-rw-r--r--erts/emulator/beam/erl_gc.c19
-rw-r--r--erts/emulator/beam/erl_init.c65
-rw-r--r--erts/emulator/beam/erl_lock_check.c100
-rw-r--r--erts/emulator/beam/erl_lock_check.h4
-rw-r--r--erts/emulator/beam/erl_lock_count.h2
-rw-r--r--erts/emulator/beam/erl_lock_flags.h6
-rw-r--r--erts/emulator/beam/erl_map.c57
-rw-r--r--erts/emulator/beam/erl_message.c18
-rw-r--r--erts/emulator/beam/erl_message.h6
-rw-r--r--erts/emulator/beam/erl_nif.c66
-rw-r--r--erts/emulator/beam/erl_node_tables.c80
-rw-r--r--erts/emulator/beam/erl_node_tables.h7
-rw-r--r--erts/emulator/beam/erl_port.h10
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c40
-rw-r--r--erts/emulator/beam/erl_process.c124
-rw-r--r--erts/emulator/beam/erl_process_dump.c6
-rw-r--r--erts/emulator/beam/erl_unicode.c4
-rw-r--r--erts/emulator/beam/external.c80
-rw-r--r--erts/emulator/beam/external.h2
-rw-r--r--erts/emulator/beam/global.h3
-rw-r--r--erts/emulator/beam/instrs.tab17
-rw-r--r--erts/emulator/beam/io.c39
-rw-r--r--erts/emulator/beam/ops.tab139
-rw-r--r--erts/emulator/beam/utils.c4
-rw-r--r--erts/emulator/drivers/common/inet_drv.c831
-rw-r--r--erts/emulator/drivers/unix/ttsl_drv.c2
-rw-r--r--erts/emulator/internal_doc/CarrierMigration.md4
-rw-r--r--erts/emulator/nifs/common/prim_file_nif.c119
-rw-r--r--erts/emulator/nifs/win32/win_prim_file.c157
-rw-r--r--erts/emulator/pcre/LICENCE93
-rw-r--r--erts/emulator/pcre/README.pcre_update.md6
-rw-r--r--erts/emulator/pcre/local_config.h2
-rw-r--r--erts/emulator/pcre/pcre-8.41.tar.bz2bin1561874 -> 0 bytes
-rw-r--r--erts/emulator/pcre/pcre-8.42.tar.bz2bin0 -> 1570171 bytes
-rw-r--r--erts/emulator/pcre/pcre.h12
-rw-r--r--erts/emulator/pcre/pcre_chartables.c2
-rw-r--r--erts/emulator/pcre/pcre_compile.c2
-rw-r--r--erts/emulator/pcre/pcre_dfa_exec.c4
-rw-r--r--erts/emulator/pcre/pcre_exec.c8
-rw-r--r--erts/emulator/pcre/pcre_jit_compile.c407
-rw-r--r--erts/emulator/pcre/pcre_latin_1_table.c3
-rw-r--r--erts/emulator/sys/common/erl_check_io.c1
-rw-r--r--erts/emulator/sys/common/erl_osenv.c2
-rw-r--r--erts/emulator/sys/common/erl_poll.c17
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c3
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c11
-rw-r--r--erts/emulator/sys/unix/sys.c6
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c109
-rw-r--r--erts/emulator/sys/unix/sys_uds.c18
-rw-r--r--erts/emulator/sys/win32/erl_poll.c20
-rw-r--r--erts/emulator/test/call_trace_SUITE.erl2
-rw-r--r--erts/emulator/test/code_SUITE.erl63
-rw-r--r--erts/emulator/test/code_SUITE_data/literals.erl8
-rw-r--r--erts/emulator/test/driver_SUITE.erl24
-rw-r--r--erts/emulator/test/fun_SUITE.erl16
-rw-r--r--erts/emulator/test/map_SUITE.erl11
-rw-r--r--erts/emulator/test/nif_SUITE.erl58
-rw-r--r--erts/emulator/test/node_container_SUITE.erl30
-rw-r--r--erts/emulator/test/num_bif_SUITE.erl1
-rw-r--r--erts/emulator/test/ref_SUITE.erl30
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl6
-rw-r--r--erts/emulator/test/smoke_test_SUITE.erl7
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl4
-rw-r--r--erts/emulator/test/trace_SUITE.erl19
-rw-r--r--erts/emulator/zlib/adler32.c24
-rw-r--r--erts/emulator/zlib/compress.c45
-rw-r--r--erts/emulator/zlib/crc32.c45
-rw-r--r--erts/emulator/zlib/deflate.c805
-rw-r--r--erts/emulator/zlib/deflate.h35
-rw-r--r--erts/emulator/zlib/gzguts.h23
-rw-r--r--erts/emulator/zlib/inffast.c88
-rw-r--r--erts/emulator/zlib/inflate.c126
-rw-r--r--erts/emulator/zlib/inflate.h11
-rw-r--r--erts/emulator/zlib/inftrees.c29
-rw-r--r--erts/emulator/zlib/trees.c102
-rw-r--r--erts/emulator/zlib/uncompr.c101
-rw-r--r--erts/emulator/zlib/zconf.h41
-rw-r--r--erts/emulator/zlib/zlib.h452
-rw-r--r--erts/emulator/zlib/zlib.mk5
-rw-r--r--erts/emulator/zlib/zutil.c52
-rw-r--r--erts/emulator/zlib/zutil.h52
-rw-r--r--erts/etc/common/erlexec.c2
-rw-r--r--erts/etc/unix/cerl.src5
-rw-r--r--erts/etc/unix/run_erl.c6
-rw-r--r--erts/include/internal/gcc/ethr_membar.h2
-rw-r--r--erts/preloaded/ebin/erl_init.beambin0 -> 1716 bytes
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin54452 -> 53664 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2188 -> 2200 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin101860 -> 101360 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin11372 -> 11200 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_signal_handler.beambin2760 -> 2764 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin16676 -> 16636 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3288 -> 3268 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin51428 -> 50628 bytes
-rw-r--r--erts/preloaded/ebin/prim_buffer.beambin3588 -> 3600 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1496 -> 1496 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin27740 -> 27524 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin77932 -> 81176 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22892 -> 22644 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin19760 -> 19720 bytes
-rw-r--r--erts/preloaded/src/Makefile2
-rw-r--r--erts/preloaded/src/erl_init.erl (renamed from erts/preloaded/src/otp_ring0.erl)21
-rw-r--r--erts/preloaded/src/erts.app.src4
-rw-r--r--erts/preloaded/src/init.erl6
-rw-r--r--erts/preloaded/src/prim_file.erl23
-rw-r--r--erts/preloaded/src/prim_inet.erl386
-rw-r--r--erts/test/upgrade_SUITE.erl2
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/Makefile2
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c10
-rw-r--r--lib/asn1/doc/src/notes.xml44
-rw-r--r--lib/asn1/src/asn1ct_check.erl2
-rw-r--r--lib/asn1/test/asn1_SUITE.erl43
-rw-r--r--lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn2
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/Makefile2
-rw-r--r--lib/common_test/doc/src/ct.xml2
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml2
-rw-r--r--lib/common_test/doc/src/notes.xml30
-rw-r--r--lib/common_test/src/ct.erl6
-rw-r--r--lib/common_test/src/ct_framework.erl2
-rw-r--r--lib/common_test/src/ct_release_test.erl20
-rw-r--r--lib/common_test/src/ct_telnet.erl2
-rw-r--r--lib/common_test/src/ct_util.erl5
-rw-r--r--lib/common_test/src/cth_log_redirect.erl3
-rw-r--r--lib/common_test/src/test_server_ctrl.erl4
-rw-r--r--lib/common_test/test/ct_auto_compile_SUITE.erl4
-rw-r--r--lib/common_test/test/ct_config_SUITE.erl12
-rw-r--r--lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl4
-rw-r--r--lib/common_test/test/test_server_SUITE.erl4
-rw-r--r--lib/common_test/test/test_server_test_lib.erl2
-rw-r--r--lib/common_test/test_server/ts_install.erl26
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/doc/src/Makefile2
-rw-r--r--lib/compiler/doc/src/compile.xml18
-rw-r--r--lib/compiler/doc/src/notes.xml135
-rw-r--r--lib/compiler/src/Makefile34
-rw-r--r--lib/compiler/src/beam_a.erl29
-rw-r--r--lib/compiler/src/beam_block.erl604
-rw-r--r--lib/compiler/src/beam_bs.erl141
-rw-r--r--lib/compiler/src/beam_bsm.erl708
-rw-r--r--lib/compiler/src/beam_clean.erl178
-rw-r--r--lib/compiler/src/beam_dead.erl971
-rw-r--r--lib/compiler/src/beam_disasm.erl27
-rw-r--r--lib/compiler/src/beam_except.erl62
-rw-r--r--lib/compiler/src/beam_flatten.erl73
-rw-r--r--lib/compiler/src/beam_jump.erl227
-rw-r--r--lib/compiler/src/beam_kernel_to_ssa.erl1325
-rw-r--r--lib/compiler/src/beam_listing.erl9
-rw-r--r--lib/compiler/src/beam_peep.erl73
-rw-r--r--lib/compiler/src/beam_receive.erl416
-rw-r--r--lib/compiler/src/beam_record.erl131
-rw-r--r--lib/compiler/src/beam_reorder.erl150
-rw-r--r--lib/compiler/src/beam_split.erl94
-rw-r--r--lib/compiler/src/beam_ssa.erl841
-rw-r--r--lib/compiler/src/beam_ssa.hrl66
-rw-r--r--lib/compiler/src/beam_ssa_bsm.erl1043
-rw-r--r--lib/compiler/src/beam_ssa_codegen.erl2034
-rw-r--r--lib/compiler/src/beam_ssa_dead.erl1001
-rw-r--r--lib/compiler/src/beam_ssa_funs.erl149
-rw-r--r--lib/compiler/src/beam_ssa_lint.erl349
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl1765
-rw-r--r--lib/compiler/src/beam_ssa_pp.erl238
-rw-r--r--lib/compiler/src/beam_ssa_pre_codegen.erl2496
-rw-r--r--lib/compiler/src/beam_ssa_recv.erl278
-rw-r--r--lib/compiler/src/beam_ssa_type.erl1195
-rw-r--r--lib/compiler/src/beam_trim.erl2
-rw-r--r--lib/compiler/src/beam_type.erl1117
-rw-r--r--lib/compiler/src/beam_utils.erl643
-rw-r--r--lib/compiler/src/beam_validator.erl594
-rw-r--r--lib/compiler/src/beam_z.erl2
-rw-r--r--lib/compiler/src/compile.erl242
-rw-r--r--lib/compiler/src/compiler.app.src20
-rw-r--r--lib/compiler/src/erl_bifs.erl1
-rwxr-xr-xlib/compiler/src/genop.tab26
-rw-r--r--lib/compiler/src/sys_core_bsm.erl250
-rw-r--r--lib/compiler/src/sys_core_fold.erl108
-rw-r--r--lib/compiler/src/v3_codegen.erl2930
-rw-r--r--lib/compiler/src/v3_core.erl58
-rw-r--r--lib/compiler/src/v3_kernel.erl48
-rw-r--r--lib/compiler/src/v3_kernel.hrl2
-rw-r--r--lib/compiler/test/Makefile24
-rw-r--r--lib/compiler/test/andor_SUITE.erl2
-rw-r--r--lib/compiler/test/apply_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_jump_SUITE.erl49
-rw-r--r--lib/compiler/test/beam_reorder_SUITE.erl2
-rw-r--r--lib/compiler/test/beam_ssa_SUITE.erl471
-rw-r--r--lib/compiler/test/beam_type_SUITE.erl144
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl19
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S2
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S6
-rw-r--r--lib/compiler/test/bif_SUITE.erl2
-rw-r--r--lib/compiler/test/bs_bincomp_SUITE.erl13
-rw-r--r--lib/compiler/test/bs_bit_binaries_SUITE.erl2
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl239
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl2
-rw-r--r--lib/compiler/test/compilation_SUITE.erl8
-rw-r--r--lib/compiler/test/compile_SUITE.erl90
-rw-r--r--lib/compiler/test/core_SUITE.erl5
-rw-r--r--lib/compiler/test/core_SUITE_data/fun_letrec_effect.core25
-rw-r--r--lib/compiler/test/core_alias_SUITE.erl2
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl37
-rw-r--r--lib/compiler/test/error_SUITE.erl2
-rw-r--r--lib/compiler/test/float_SUITE.erl2
-rw-r--r--lib/compiler/test/fun_SUITE.erl7
-rw-r--r--lib/compiler/test/guard_SUITE.erl57
-rw-r--r--lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S30
-rw-r--r--lib/compiler/test/inline_SUITE.erl14
-rw-r--r--lib/compiler/test/map_SUITE.erl120
-rw-r--r--lib/compiler/test/match_SUITE.erl16
-rw-r--r--lib/compiler/test/misc_SUITE.erl118
-rw-r--r--lib/compiler/test/overridden_bif_SUITE.erl2
-rw-r--r--lib/compiler/test/receive_SUITE.erl77
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl38
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S71
-rw-r--r--lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl27
-rw-r--r--lib/compiler/test/record_SUITE.erl2
-rw-r--r--lib/compiler/test/regressions_SUITE.erl2
-rw-r--r--lib/compiler/test/test_lib.erl17
-rw-r--r--lib/compiler/test/warnings_SUITE.erl53
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/configure.in.src62
-rw-r--r--lib/crypto/c_src/Makefile.in60
-rw-r--r--lib/crypto/c_src/crypto.c835
-rw-r--r--lib/crypto/c_src/otp_test_engine.c3
-rw-r--r--lib/crypto/configure.in775
-rw-r--r--lib/crypto/doc/specs/.gitignore1
-rw-r--r--lib/crypto/doc/src/Makefile9
-rw-r--r--lib/crypto/doc/src/algorithm_details.xml341
-rw-r--r--lib/crypto/doc/src/crypto.xml1513
-rw-r--r--lib/crypto/doc/src/engine_keys.xml6
-rw-r--r--lib/crypto/doc/src/engine_load.xml33
-rw-r--r--lib/crypto/doc/src/notes.xml174
-rw-r--r--lib/crypto/doc/src/specs.xml4
-rw-r--r--lib/crypto/doc/src/usersguide.xml1
-rw-r--r--lib/crypto/src/crypto.erl1424
-rw-r--r--lib/crypto/src/crypto_ec_curves.erl36
-rw-r--r--lib/crypto/test/crypto_SUITE.erl873
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT128.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT192.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VADT256.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT128.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT192.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VNT256.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT128.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT192.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/VPT256.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt1589
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt9
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp1823
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp456
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp1383
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp393
-rw-r--r--lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zipbin0 -> 319267 bytes
-rw-r--r--lib/crypto/test/engine_SUITE.erl295
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/doc/src/notes.xml15
-rw-r--r--lib/debugger/src/dbg_icmd.erl2
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/notes.xml15
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl2
-rw-r--r--lib/dialyzer/src/typer.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl4
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/left_assoc2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/maps_sum2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl96
-rw-r--r--lib/dialyzer/vsn.mk2
-rw-r--r--lib/diameter/doc/src/Makefile2
-rw-r--r--lib/diameter/doc/src/notes.xml20
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl4
-rw-r--r--lib/diameter/src/diameter.appup.src6
-rw-r--r--lib/diameter/vsn.mk2
-rw-r--r--lib/edoc/doc/src/notes.xml15
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/README2
-rw-r--r--lib/eldap/doc/src/notes.xml64
-rw-r--r--lib/eldap/src/eldap.erl15
-rw-r--r--lib/eldap/test/make_certs.erl4
-rw-r--r--lib/eldap/vsn.mk2
-rw-r--r--lib/erl_docgen/doc/src/doc-build.xml2
-rw-r--r--lib/erl_docgen/doc/src/notes.xml18
-rw-r--r--lib/erl_docgen/priv/xsl/db_eix.xsl81
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl2
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/configure.in5
-rw-r--r--lib/erl_interface/doc/src/Makefile2
-rw-r--r--lib/erl_interface/doc/src/notes.xml47
-rw-r--r--lib/erl_interface/src/INSTALL4
-rw-r--r--lib/erl_interface/src/README.internal8
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c2
-rw-r--r--lib/erl_interface/src/legacy/erl_marshal.c2
-rw-r--r--lib/erl_interface/src/misc/ei_pthreads.c5
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE.erl9
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c11
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE.erl18
-rw-r--r--lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c14
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE.erl22
-rw-r--r--lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c7
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE.erl8
-rw-r--r--lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c3
-rw-r--r--lib/erl_interface/test/ei_encode_SUITE.erl24
-rw-r--r--lib/erl_interface/test/ei_format_SUITE.erl14
-rw-r--r--lib/erl_interface/test/ei_print_SUITE.erl14
-rw-r--r--lib/erl_interface/test/ei_tmo_SUITE.erl30
-rw-r--r--lib/erl_interface/test/erl_connect_SUITE.erl12
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE.erl80
-rw-r--r--lib/erl_interface/test/erl_ext_SUITE.erl15
-rw-r--r--lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c14
-rw-r--r--lib/erl_interface/test/erl_format_SUITE.erl12
-rw-r--r--lib/erl_interface/test/erl_global_SUITE.erl11
-rw-r--r--lib/erl_interface/test/erl_match_SUITE.erl9
-rw-r--r--lib/erl_interface/test/port_call_SUITE.erl8
-rw-r--r--lib/erl_interface/test/runner.erl56
-rw-r--r--lib/erl_interface/vsn.mk2
-rw-r--r--lib/et/doc/src/et_collector.xml10
-rw-r--r--lib/et/doc/src/et_selector.xml6
-rw-r--r--lib/et/doc/src/notes.xml15
-rw-r--r--lib/et/src/et_collector.erl4
-rw-r--r--lib/et/vsn.mk2
-rw-r--r--lib/eunit/doc/src/notes.xml15
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/ftp/doc/src/ftp.xml4
-rw-r--r--lib/ftp/doc/src/notes.xml17
-rw-r--r--lib/ftp/src/ftp.app.src2
-rw-r--r--lib/ftp/vsn.mk2
-rw-r--r--lib/hipe/doc/src/Makefile2
-rw-r--r--lib/hipe/doc/src/hipe_app.xml11
-rw-r--r--lib/hipe/doc/src/notes.xml15
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl38
-rw-r--r--lib/hipe/icode/hipe_icode_range.erl2
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl12
-rw-r--r--lib/hipe/main/hipe.erl151
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl2
-rw-r--r--lib/hipe/rtl/hipe_rtl_arith.inc4
-rw-r--r--lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl6
-rw-r--r--lib/hipe/test/Makefile1
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_inline_function.erl73
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl2
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/inets/doc/src/httpd.xml2
-rw-r--r--lib/inets/doc/src/mod_security.xml5
-rw-r--r--lib/inets/doc/src/notes.xml114
-rw-r--r--lib/inets/doc/src/notes_history.xml4
-rw-r--r--lib/inets/src/http_client/httpc_cookie.erl2
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl18
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl2
-rw-r--r--lib/inets/src/http_client/httpc_request.erl23
-rw-r--r--lib/inets/src/http_server/httpd_example.erl8
-rw-r--r--lib/inets/src/http_server/httpd_file.erl5
-rw-r--r--lib/inets/src/http_server/httpd_response.erl8
-rw-r--r--lib/inets/src/http_server/mod_esi.erl15
-rw-r--r--lib/inets/src/inets_app/inets.appup.src2
-rw-r--r--lib/inets/test/http_format_SUITE.erl2
-rw-r--r--lib/inets/test/httpc_SUITE.erl117
-rw-r--r--lib/inets/test/httpc_proxy_SUITE.erl2
-rw-r--r--lib/inets/test/httpd_SUITE.erl107
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/jinterface/doc/src/Makefile2
-rw-r--r--lib/jinterface/doc/src/notes.xml17
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java12
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java4
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/code.xml4
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml69
-rw-r--r--lib/kernel/doc/src/gen_tcp.xml28
-rw-r--r--lib/kernel/doc/src/gen_udp.xml35
-rw-r--r--lib/kernel/doc/src/inet.xml336
-rw-r--r--lib/kernel/doc/src/kernel_app.xml39
-rw-r--r--lib/kernel/doc/src/logger.xml119
-rw-r--r--lib/kernel/doc/src/logger_chapter.xml44
-rw-r--r--lib/kernel/doc/src/logger_disk_log_h.xml10
-rw-r--r--lib/kernel/doc/src/logger_formatter.xml21
-rw-r--r--lib/kernel/doc/src/logger_std_h.xml27
-rw-r--r--lib/kernel/doc/src/net_kernel.xml2
-rw-r--r--lib/kernel/doc/src/notes.xml138
-rw-r--r--lib/kernel/src/error_logger.erl29
-rw-r--r--lib/kernel/src/gen_sctp.erl18
-rw-r--r--lib/kernel/src/gen_tcp.erl16
-rw-r--r--lib/kernel/src/gen_udp.erl19
-rw-r--r--lib/kernel/src/inet.erl99
-rw-r--r--lib/kernel/src/inet6_tcp.erl8
-rw-r--r--lib/kernel/src/inet_config.erl2
-rw-r--r--lib/kernel/src/inet_dns.erl2
-rw-r--r--lib/kernel/src/inet_int.hrl8
-rw-r--r--lib/kernel/src/inet_tcp.erl8
-rw-r--r--lib/kernel/src/inet_tcp_dist.erl2
-rw-r--r--lib/kernel/src/kernel.app.src2
-rw-r--r--lib/kernel/src/kernel.appup.src6
-rw-r--r--lib/kernel/src/logger.erl213
-rw-r--r--lib/kernel/src/logger_backend.erl2
-rw-r--r--lib/kernel/src/logger_config.erl23
-rw-r--r--lib/kernel/src/logger_disk_log_h.erl91
-rw-r--r--lib/kernel/src/logger_formatter.erl111
-rw-r--r--lib/kernel/src/logger_h_common.erl28
-rw-r--r--lib/kernel/src/logger_server.erl197
-rw-r--r--lib/kernel/src/logger_std_h.erl77
-rw-r--r--lib/kernel/src/net_kernel.erl134
-rw-r--r--lib/kernel/test/code_SUITE.erl2
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl99
-rw-r--r--lib/kernel/test/erl_distribution_SUITE.erl1
-rw-r--r--lib/kernel/test/file_SUITE.erl35
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl378
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl176
-rw-r--r--lib/kernel/test/global_SUITE.erl30
-rw-r--r--lib/kernel/test/inet_SUITE.erl174
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl2
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl9
-rw-r--r--lib/kernel/test/init_SUITE.erl2
-rw-r--r--lib/kernel/test/logger_SUITE.erl279
-rw-r--r--lib/kernel/test/logger_disk_log_h_SUITE.erl245
-rw-r--r--lib/kernel/test/logger_formatter_SUITE.erl57
-rw-r--r--lib/kernel/test/logger_simple_h_SUITE.erl3
-rw-r--r--lib/kernel/test/logger_std_h_SUITE.erl177
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl3
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl25
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/configure.in115
-rw-r--r--lib/megaco/doc/src/Makefile2
-rw-r--r--lib/megaco/doc/src/book.xml2
-rw-r--r--lib/megaco/doc/src/notes.xml17
-rw-r--r--lib/megaco/src/flex/Makefile.in40
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/mnesia_frag_hash.xml4
-rw-r--r--lib/mnesia/doc/src/notes.xml78
-rw-r--r--lib/mnesia/examples/bench/README4
-rw-r--r--lib/mnesia/src/mnesia.erl22
-rw-r--r--lib/mnesia/src/mnesia_controller.erl30
-rw-r--r--lib/mnesia/src/mnesia_index.erl2
-rw-r--r--lib/mnesia/src/mnesia_lib.erl2
-rw-r--r--lib/mnesia/src/mnesia_loader.erl8
-rw-r--r--lib/mnesia/src/mnesia_tm.erl2
-rw-r--r--lib/mnesia/test/README6
-rw-r--r--lib/mnesia/test/mnesia_durability_test.erl107
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl105
-rw-r--r--lib/mnesia/test/mnesia_isolation_test.erl11
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/notes.xml15
-rw-r--r--lib/observer/src/cdv_bin_cb.erl4
-rw-r--r--lib/observer/src/cdv_term_cb.erl2
-rw-r--r--lib/observer/src/cdv_wx.erl5
-rw-r--r--lib/observer/src/crashdump_viewer.erl155
-rw-r--r--lib/observer/src/observer_tv_wx.erl4
-rw-r--r--lib/observer/src/observer_wx.erl2
-rw-r--r--lib/observer/test/crashdump_helper.erl21
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump24
-rw-r--r--lib/observer/test/observer_SUITE.erl2
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/configure.in6
-rw-r--r--lib/odbc/doc/src/Makefile2
-rw-r--r--lib/odbc/doc/src/databases.xml2
-rw-r--r--lib/odbc/doc/src/error_handling.xml2
-rw-r--r--lib/odbc/doc/src/getting_started.xml2
-rw-r--r--lib/odbc/doc/src/notes.xml19
-rw-r--r--lib/odbc/doc/src/notes_history.xml4
-rw-r--r--lib/odbc/doc/src/odbc.xml2
-rw-r--r--lib/odbc/test/odbc_connect_SUITE.erl2
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/os_mon/Makefile6
-rw-r--r--lib/os_mon/c_src/cpu_sup.c50
-rw-r--r--lib/os_mon/doc/src/Makefile1
-rw-r--r--lib/os_mon/doc/src/notes.xml15
-rw-r--r--lib/os_mon/doc/src/os_mon_app.xml27
-rw-r--r--lib/os_mon/doc/src/os_mon_mib.xml74
-rw-r--r--lib/os_mon/doc/src/ref_man.xml1
-rw-r--r--lib/os_mon/mibs/Makefile101
-rw-r--r--lib/os_mon/mibs/OTP-OS-MON-MIB.funcs5
-rw-r--r--lib/os_mon/mibs/OTP-OS-MON-MIB.mib423
-rw-r--r--lib/os_mon/mibs/v1/.gitignore0
-rw-r--r--lib/os_mon/src/Makefile3
-rw-r--r--lib/os_mon/src/cpu_sup.erl26
-rw-r--r--lib/os_mon/src/memsup.erl1
-rw-r--r--lib/os_mon/src/os_mon.app.src6
-rw-r--r--lib/os_mon/src/os_mon_mib.erl251
-rw-r--r--lib/os_mon/test/Makefile2
-rw-r--r--lib/os_mon/test/os_mon.spec1
-rw-r--r--lib/os_mon/test/os_mon_mib_SUITE.cfg8
-rw-r--r--lib/os_mon/test/os_mon_mib_SUITE.erl578
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/otp_mibs/AUTHORS8
-rw-r--r--lib/otp_mibs/Makefile37
-rw-r--r--lib/otp_mibs/doc/html/.gitignore0
-rw-r--r--lib/otp_mibs/doc/man3/.gitignore0
-rw-r--r--lib/otp_mibs/doc/pdf/.gitignore0
-rw-r--r--lib/otp_mibs/doc/src/Makefile116
-rw-r--r--lib/otp_mibs/doc/src/book.xml49
-rw-r--r--lib/otp_mibs/doc/src/introduction.xml47
-rw-r--r--lib/otp_mibs/doc/src/mibs.xml71
-rw-r--r--lib/otp_mibs/doc/src/notes.xml312
-rw-r--r--lib/otp_mibs/doc/src/otp_mib.xml73
-rw-r--r--lib/otp_mibs/doc/src/part.xml39
-rw-r--r--lib/otp_mibs/doc/src/ref_man.xml38
-rw-r--r--lib/otp_mibs/ebin/.gitignore0
-rw-r--r--lib/otp_mibs/include/.gitignore0
-rw-r--r--lib/otp_mibs/info2
-rw-r--r--lib/otp_mibs/mibs/Makefile89
-rw-r--r--lib/otp_mibs/mibs/OTP-EVA-MIB.mib569
-rw-r--r--lib/otp_mibs/mibs/OTP-MIB.funcs2
-rw-r--r--lib/otp_mibs/mibs/OTP-MIB.mib318
-rw-r--r--lib/otp_mibs/mibs/v1/.gitignore0
-rw-r--r--lib/otp_mibs/priv/bin/.gitignore0
-rw-r--r--lib/otp_mibs/priv/mibs/.gitignore0
-rw-r--r--lib/otp_mibs/priv/obj/.gitignore0
-rw-r--r--lib/otp_mibs/src/Makefile106
-rw-r--r--lib/otp_mibs/src/otp_mib.erl219
-rw-r--r--lib/otp_mibs/src/otp_mibs.app.src30
-rw-r--r--lib/otp_mibs/test/Makefile85
-rw-r--r--lib/otp_mibs/test/otp_mibs_SUITE.cfg15
-rw-r--r--lib/otp_mibs/test/otp_mibs_SUITE.erl255
-rw-r--r--lib/otp_mibs/vsn.mk5
-rw-r--r--lib/parsetools/doc/src/Makefile2
-rw-r--r--lib/parsetools/doc/src/notes.xml15
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn17
-rw-r--r--lib/public_key/doc/specs/.gitignore1
-rw-r--r--lib/public_key/doc/src/Makefile9
-rw-r--r--lib/public_key/doc/src/notes.xml35
-rw-r--r--lib/public_key/doc/src/public_key.xml688
-rw-r--r--lib/public_key/doc/src/specs.xml4
-rw-r--r--lib/public_key/src/public_key.erl445
-rw-r--r--lib/public_key/test/public_key_SUITE.erl15
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/Makefile2
-rw-r--r--lib/reltool/doc/src/notes.xml17
-rw-r--r--lib/reltool/doc/src/reltool.xml4
-rw-r--r--lib/reltool/doc/src/reltool_examples.xml4
-rw-r--r--lib/reltool/src/reltool_server.erl2
-rw-r--r--lib/reltool/test/reltool_server_SUITE.erl4
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/c_src/Makefile.in8
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml4
-rw-r--r--lib/runtime_tools/doc/src/notes.xml17
-rw-r--r--lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat2
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/doc/src/notes.xml15
-rw-r--r--lib/sasl/src/rb.erl2
-rw-r--r--lib/sasl/src/release_handler.erl4
-rw-r--r--lib/sasl/src/release_handler_1.erl2
-rw-r--r--lib/sasl/src/sasl.appup.src8
-rw-r--r--lib/sasl/src/systools_make.erl4
-rw-r--r--lib/sasl/test/installer.erl2
-rw-r--r--lib/sasl/test/rb_SUITE.erl2
-rw-r--r--lib/sasl/test/sasl_report_SUITE.erl3
-rw-r--r--lib/sasl/test/systools_SUITE.erl2
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/Makefile2
-rw-r--r--lib/snmp/doc/src/notes.xml45
-rw-r--r--lib/snmp/doc/src/snmp.xml33
-rw-r--r--lib/snmp/doc/src/snmp_impl_example_agent.xml2
-rw-r--r--lib/snmp/doc/src/snmpa.xml38
-rw-r--r--lib/snmp/doc/src/snmpm.xml38
-rw-r--r--lib/snmp/mibs/Makefile.in36
-rw-r--r--lib/snmp/mibs/OTP-REG.mib (renamed from lib/otp_mibs/mibs/OTP-REG.mib)0
-rw-r--r--lib/snmp/mibs/OTP-TC.mib (renamed from lib/otp_mibs/mibs/OTP-TC.mib)0
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl111
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl6
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl4
-rw-r--r--lib/snmp/src/compile/snmpc.erl6
-rw-r--r--lib/snmp/src/misc/snmp_log.erl334
-rw-r--r--lib/snmp/test/snmp_agent_test.erl2
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl6
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl2
-rw-r--r--lib/snmp/test/test-mibs/ALARM-MIB.mib2
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-TC.mib4
-rw-r--r--lib/snmp/vsn.mk4
-rw-r--r--lib/ssh/doc/src/Makefile3
-rw-r--r--lib/ssh/doc/src/notes.xml41
-rw-r--r--lib/ssh/doc/src/ref_man.xml1
-rw-r--r--lib/ssh/doc/src/specs.xml1
-rw-r--r--lib/ssh/doc/src/ssh.xml74
-rw-r--r--lib/ssh/doc/src/ssh_app.xml15
-rw-r--r--lib/ssh/doc/src/ssh_file.xml275
-rw-r--r--lib/ssh/doc/src/ssh_sftp.xml1
-rw-r--r--lib/ssh/doc/src/terminology.xml185
-rw-r--r--lib/ssh/doc/src/usersguide.xml1
-rw-r--r--lib/ssh/doc/src/using_ssh.xml11
-rw-r--r--lib/ssh/src/ssh.hrl53
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl15
-rw-r--r--lib/ssh/src/ssh_dbg.erl116
-rw-r--r--lib/ssh/src/ssh_file.erl17
-rw-r--r--lib/ssh/src/ssh_message.erl8
-rw-r--r--lib/ssh/src/ssh_transport.erl234
-rw-r--r--lib/ssh/src/ssh_xfer.erl2
-rw-r--r--lib/ssh/test/.gitignore5
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl20
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_server.erl230
-rw-r--r--lib/ssh/test/ssh_bench_SUITE.erl35
-rw-r--r--lib/ssh/test/ssh_dbg_SUITE.erl68
-rw-r--r--lib/ssh/test/ssh_property_test_SUITE.erl7
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/Makefile2
-rw-r--r--lib/ssl/doc/src/notes.xml219
-rw-r--r--lib/ssl/doc/src/ssl.xml52
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml2
-rw-r--r--lib/ssl/examples/src/client_server.erl14
-rw-r--r--lib/ssl/src/Makefile12
-rw-r--r--lib/ssl/src/dtls.erl113
-rw-r--r--lib/ssl/src/dtls_connection.erl75
-rw-r--r--lib/ssl/src/dtls_handshake.erl18
-rw-r--r--lib/ssl/src/dtls_handshake.hrl7
-rw-r--r--lib/ssl/src/dtls_record.erl22
-rw-r--r--lib/ssl/src/dtls_socket.erl10
-rw-r--r--lib/ssl/src/dtls_v1.erl8
-rw-r--r--lib/ssl/src/inet_tls_dist.erl17
-rw-r--r--lib/ssl/src/ssl.app.src6
-rw-r--r--lib/ssl/src/ssl.appup.src4
-rw-r--r--lib/ssl/src/ssl.erl193
-rw-r--r--lib/ssl/src/ssl_alert.erl4
-rw-r--r--lib/ssl/src/ssl_alert.hrl5
-rw-r--r--lib/ssl/src/ssl_api.hrl14
-rw-r--r--lib/ssl/src/ssl_certificate.erl99
-rw-r--r--lib/ssl/src/ssl_cipher.erl1951
-rw-r--r--lib/ssl/src/ssl_cipher.hrl20
-rw-r--r--lib/ssl/src/ssl_cipher_format.erl1854
-rw-r--r--lib/ssl/src/ssl_config.erl6
-rw-r--r--lib/ssl/src/ssl_connection.erl704
-rw-r--r--lib/ssl/src/ssl_connection.hrl4
-rw-r--r--lib/ssl/src/ssl_handshake.erl730
-rw-r--r--lib/ssl/src/ssl_handshake.hrl66
-rw-r--r--lib/ssl/src/ssl_internal.hrl32
-rw-r--r--lib/ssl/src/ssl_logger.erl9
-rw-r--r--lib/ssl/src/ssl_manager.erl16
-rw-r--r--lib/ssl/src/ssl_pem_cache.erl37
-rw-r--r--lib/ssl/src/ssl_pkix_db.erl19
-rw-r--r--lib/ssl/src/ssl_record.erl84
-rw-r--r--lib/ssl/src/ssl_record.hrl3
-rw-r--r--lib/ssl/src/ssl_v3.erl4
-rw-r--r--lib/ssl/src/tls.erl112
-rw-r--r--lib/ssl/src/tls_connection.erl270
-rw-r--r--lib/ssl/src/tls_handshake.erl181
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl153
-rw-r--r--lib/ssl/src/tls_handshake_1_3.hrl226
-rw-r--r--lib/ssl/src/tls_record.erl44
-rw-r--r--lib/ssl/src/tls_record_1_3.erl260
-rw-r--r--lib/ssl/src/tls_record_1_3.hrl58
-rw-r--r--lib/ssl/src/tls_sender.erl432
-rw-r--r--lib/ssl/src/tls_socket.erl9
-rw-r--r--lib/ssl/src/tls_v1.erl85
-rw-r--r--lib/ssl/test/Makefile3
-rw-r--r--lib/ssl/test/make_certs.erl6
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl534
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl23
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl135
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl94
-rw-r--r--lib/ssl/test/ssl_engine_SUITE.erl15
-rw-r--r--lib/ssl/test/ssl_eqc_SUITE.erl58
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl121
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl42
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl52
-rw-r--r--lib/ssl/test/ssl_pem_cache_SUITE.erl47
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl6
-rw-r--r--lib/ssl/test/ssl_test_lib.erl91
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl187
-rw-r--r--lib/stdlib/doc/src/assert_hrl.xml2
-rw-r--r--lib/stdlib/doc/src/beam_lib.xml4
-rw-r--r--lib/stdlib/doc/src/epp.xml8
-rw-r--r--lib/stdlib/doc/src/ets.xml23
-rw-r--r--lib/stdlib/doc/src/filename.xml34
-rw-r--r--lib/stdlib/doc/src/gen_event.xml2
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml232
-rw-r--r--lib/stdlib/doc/src/maps.xml34
-rw-r--r--lib/stdlib/doc/src/notes.xml41
-rw-r--r--lib/stdlib/doc/src/rand.xml110
-rw-r--r--lib/stdlib/doc/src/supervisor.xml14
-rw-r--r--lib/stdlib/include/assert.hrl6
-rw-r--r--lib/stdlib/src/beam_lib.erl2
-rw-r--r--lib/stdlib/src/dets.erl23
-rw-r--r--lib/stdlib/src/epp.erl13
-rw-r--r--lib/stdlib/src/erl_internal.erl2
-rw-r--r--lib/stdlib/src/erl_posix_msg.erl4
-rw-r--r--lib/stdlib/src/filename.erl31
-rw-r--r--lib/stdlib/src/gen_statem.erl261
-rw-r--r--lib/stdlib/src/io_lib.erl49
-rw-r--r--lib/stdlib/src/io_lib_format.erl11
-rw-r--r--lib/stdlib/src/maps.erl157
-rw-r--r--lib/stdlib/src/ms_transform.erl7
-rw-r--r--lib/stdlib/src/otp_internal.erl6
-rw-r--r--lib/stdlib/src/proc_lib.erl93
-rw-r--r--lib/stdlib/src/rand.erl563
-rw-r--r--lib/stdlib/src/stdlib.app.src2
-rw-r--r--lib/stdlib/src/stdlib.appup.src6
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl2
-rw-r--r--lib/stdlib/test/dets_SUITE.erl15
-rw-r--r--lib/stdlib/test/epp_SUITE.erl18
-rw-r--r--lib/stdlib/test/epp_SUITE_data/source_name.erl (renamed from lib/otp_mibs/src/otp_mibs.appup.src)17
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl2
-rw-r--r--lib/stdlib/test/ets_SUITE.erl1864
-rw-r--r--lib/stdlib/test/ets_SUITE_data/visualize_throughput.html253
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl2
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl73
-rw-r--r--lib/stdlib/test/io_SUITE.erl12
-rw-r--r--lib/stdlib/test/lists_SUITE.erl2
-rw-r--r--lib/stdlib/test/rand_SUITE.erl437
-rw-r--r--lib/stdlib/test/rand_Xoroshiro928ss_dev.txt343
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput216
-rw-r--r--lib/stdlib/test/re_SUITE_data/testoutput58
-rw-r--r--lib/stdlib/test/stdlib.spec2
-rw-r--r--lib/stdlib/test/stdlib_bench_SUITE.erl67
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl7
-rw-r--r--lib/stdlib/test/sys_SUITE.erl17
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt1148
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt246
-rw-r--r--lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt52
-rw-r--r--lib/stdlib/uc_spec/CaseFolding.txt85
-rw-r--r--lib/stdlib/uc_spec/CompositionExclusions.txt4
-rw-r--r--lib/stdlib/uc_spec/GraphemeBreakProperty.txt117
-rw-r--r--lib/stdlib/uc_spec/PropList.txt77
-rw-r--r--lib/stdlib/uc_spec/README-UPDATE.txt8
-rw-r--r--lib/stdlib/uc_spec/SpecialCasing.txt8
-rw-r--r--lib/stdlib/uc_spec/UnicodeData.txt778
-rw-r--r--lib/stdlib/uc_spec/emoji-data.txt714
-rwxr-xr-xlib/stdlib/uc_spec/gen_unicode_mod.escript149
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/src/notes.xml52
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl17
-rw-r--r--lib/syntax_tools/src/erl_syntax_lib.erl2
-rw-r--r--lib/syntax_tools/src/igor.erl2
-rw-r--r--lib/syntax_tools/test/merl_SUITE.erl14
-rw-r--r--lib/syntax_tools/test/syntax_tools_SUITE.erl79
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/tftp/doc/src/notes.xml17
-rw-r--r--lib/tftp/doc/src/tftp.xml6
-rw-r--r--lib/tftp/src/tftp.app.src2
-rw-r--r--lib/tftp/vsn.mk2
-rw-r--r--lib/tools/doc/src/cover.xml6
-rw-r--r--lib/tools/doc/src/notes.xml22
-rw-r--r--lib/tools/emacs/Makefile1
-rw-r--r--lib/tools/emacs/erlang-edoc.el1
-rw-r--r--lib/tools/emacs/erlang-eunit.el10
-rw-r--r--lib/tools/emacs/erlang-pkg.el3
-rw-r--r--lib/tools/emacs/erlang-skels.el2
-rw-r--r--lib/tools/emacs/erlang-test.el77
-rw-r--r--lib/tools/emacs/erlang.el72
-rw-r--r--lib/tools/emacs/erlang_appwiz.el13
-rw-r--r--lib/tools/priv/styles.css91
-rw-r--r--lib/tools/src/Makefile7
-rw-r--r--lib/tools/src/cover.erl113
-rw-r--r--lib/tools/test/emacs_SUITE.erl175
-rw-r--r--lib/tools/test/xref_SUITE.erl2
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/wx/c_src/wxe_driver.c165
-rw-r--r--lib/wx/c_src/wxe_driver.h4
-rw-r--r--lib/wx/c_src/wxe_main.cpp15
-rw-r--r--lib/wx/doc/overview.edoc2
-rw-r--r--lib/wx/doc/src/notes.xml15
-rw-r--r--lib/wx/examples/demo/ex_graphicsContext.erl2
-rw-r--r--lib/wx/test/wx_event_SUITE.erl4
-rwxr-xr-xlib/wx/test/wxt6
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/doc/src/notes.xml15
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_base.erlsrc2
-rw-r--r--lib/xmerl/src/xmerl_scan.erl4
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml26
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml26
-rw-r--r--lib/xmerl/vsn.mk2
-rw-r--r--make/configure.in (renamed from configure.in)87
-rwxr-xr-xmake/emd2exml.in2
-rwxr-xr-xmake/fixup_development_runtime_dependencies111
-rw-r--r--make/lazy_configure.mk82
-rw-r--r--make/otp_ded.mk.in25
-rw-r--r--make/otp_patch_solve_forward_merge_version1
-rw-r--r--make/otp_version_tickets1
-rwxr-xr-xotp_build207
-rw-r--r--otp_versions.table22
-rwxr-xr-xscripts/bundle-otp8
-rwxr-xr-xscripts/diffable180
-rw-r--r--system/COPYRIGHT37
-rw-r--r--system/doc/design_principles/des_princ.xml4
-rw-r--r--system/doc/design_principles/statem.xml438
-rw-r--r--system/doc/design_principles/sup_princ.xml11
-rw-r--r--system/doc/efficiency_guide/binaryhandling.xml8
-rw-r--r--system/doc/efficiency_guide/profiling.xml2
-rw-r--r--system/doc/embedded/starting.xml2
-rw-r--r--system/doc/oam/oam_intro.xml55
-rw-r--r--system/doc/reference_manual/expressions.xml7
-rw-r--r--system/doc/reference_manual/typespec.xml26
-rw-r--r--system/doc/system_principles/versions.xml29
1088 files changed, 84263 insertions, 27814 deletions
diff --git a/.gitignore b/.gitignore
index 0e9d07757f..02894c4786 100644
--- a/.gitignore
+++ b/.gitignore
@@ -34,6 +34,7 @@ i686-pc-linux-gnu
x86_64-unknown-linux-gnu
i386-apple-darwin[0-9]*.[0-9]*.[0-9]*
x86_64-apple-darwin[0-9]*.[0-9]*.[0-9]*
+x86_64-unknown-freebsd[0-9]*.[0-9]*
sparc-sun-solaris[0-9]*.[0-9]*
i386-pc-solaris[0-9]*.[0-9]*
i386-unknown-freebsd[0-9]*.[0-9]*
@@ -171,9 +172,10 @@ JAVADOC-GENERATED
/lib/*/doc/pdf/*.pdf
/lib/*/doc/xml/*.xml
-/lib/configure
/lib/config.log
/lib/config.status
+/make/config.log
+/make/config.status
#
# Files generated by configure.
@@ -186,10 +188,12 @@ JAVADOC-GENERATED
# Files generated by "./otp_build autoconf"
#
+/lib/configure
/lib/*/configure
/lib/common_test/test_server/configure
/lib/configure.in
-/aclocal.m4
+/make/aclocal.m4
+/make/configure
/lib/common_test/priv/auxdir/config.guess
/lib/common_test/priv/auxdir/config.sub
/lib/common_test/priv/auxdir/install-sh
@@ -207,6 +211,7 @@ JAVADOC-GENERATED
/lib/wx/autoconf/config.guess
/lib/wx/autoconf/config.sub
/lib/wx/autoconf/install-sh
+/lib/crypto/aclocal.m4
#
# Files generated when building/running tests (especially if
@@ -241,6 +246,7 @@ JAVADOC-GENERATED
/lib/compiler/test/*_no_opt_SUITE.erl
/lib/compiler/test/*_post_opt_SUITE.erl
/lib/compiler/test/*_inline_SUITE.erl
+/lib/compiler/test/*_r21_SUITE.erl
# crypto
/lib/crypto/test/crypto_SUITE_data/*.rsp
diff --git a/.travis.yml b/.travis.yml
index ee724f8947..00fe85fc04 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -36,16 +36,42 @@ matrix:
script:
- ./scripts/build-otp
- ./scripts/run-dialyzer
+
- env: Linux32
services:
- docker
script:
- ./scripts/build-docker-otp 32 sh -c "scripts/build-otp release && ./otp_build tests && scripts/run-smoke-tests && bin/dialyzer --build_plt --apps erts kernel stdlib"
+
- env: Linux64SmokeTest
script:
+ - ERL_COMPILER_OPTIONS=ssalint ./scripts/build-otp
+ - ERL_COMPILER_OPTIONS=ssalint ./otp_build tests
+ - ./scripts/run-smoke-tests
+
+ - env: Linux-ppc64le-SmokeTest
+ os: linux-ppc64le
+ script:
- ./scripts/build-otp
- ./otp_build tests
- ./scripts/run-smoke-tests
+ addons:
+ apt:
+ update: true
+ packages:
+ - autoconf
+ - libncurses-dev
+ - build-essential
+ - libssl-dev
+ - libwxgtk3.0-dev
+ - libgl1-mesa-dev
+ - libglu1-mesa-dev
+ - libpng3
+ - default-jdk
+ - g++
+ - xsltproc
+ - libxml2-utils
+
- env: Linux64Docbuild
script:
- ./scripts/build-otp docs
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 96db464b52..8814e506f9 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -3,6 +3,7 @@
## License
By making a contribution to this project, I certify that:
+
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md
index 2597794496..674454bc8e 100644
--- a/HOWTO/INSTALL.md
+++ b/HOWTO/INSTALL.md
@@ -77,8 +77,6 @@ also find the utilities needed for building the documentation.
Download from <http://www.oracle.com/technetwork/java/javase/downloads>.
We have also tested with IBM's JDK 1.6.0.
-* X Windows -- Development headers and libraries are needed
- to build the Erlang/OTP application `gs` on Unix/Linux.
* `flex` -- Headers and libraries are needed to build the flex
scanner for the `megaco` application on Unix/Linux.
* wxWidgets -- Toolkit for GUI applications.
@@ -340,6 +338,8 @@ use the `--prefix` argument like this: `./configure --prefix=<Dir>`.
Some of the available `configure` options are:
* `--prefix=PATH` - Specify installation prefix.
+* `--disable-parallel-configure` - Disable parallel execution of
+ `configure` scripts (parallel execution is enabled by default)
* `--{enable,disable}-kernel-poll` - Kernel poll support (enabled by
default if possible)
* `--{enable,disable}-hipe` - HiPE support (enabled by default on supported
diff --git a/Makefile.in b/Makefile.in
index d880bfefa2..a07a779f10 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -161,6 +161,8 @@ ERLANG_LIBDIR = $(DESTDIR)$(ERLANG_INST_LIBDIR)
# Must be GNU make!
MAKE = @MAKE_PROG@
+PERL = @PERL@
+
NATIVE_LIBS_ENABLED = @NATIVE_LIBS_ENABLED@
ifeq ($(NATIVE_LIBS_ENABLED),yes)
@@ -327,16 +329,16 @@ ifneq ($(CROSS_COMPILING),yes)
# Not cross compiling
ifeq ($(BOOTSTRAP_ONLY),yes)
-all: bootstrap
+all: bootstrap check_dev_rt_dep
else
# The normal case; not cross compiling, and not bootstrap only build.
-all: bootstrap libs local_setup
+all: bootstrap libs local_setup check_dev_rt_dep
endif
else
# Cross compiling
-all: cross_check_erl depend emulator libs start_scripts
+all: cross_check_erl depend emulator libs start_scripts check_dev_rt_dep
endif
@@ -356,7 +358,10 @@ erlang_inst_libdir_configured:
bootstrap: depend all_bootstraps
-
+check_dev_rt_dep:
+ @if `grep DEVELOPMENT "$(ERL_TOP)/make/otp_version_tickets" 1>/dev/null 2>&1`; then \
+ LANG=C "$(PERL)" "$(ERL_TOP)/make/fixup_development_runtime_dependencies" "$(ERL_TOP)"; \
+ fi
ifeq ($(OTP_STRICT_INSTALL),yes)
@@ -982,7 +987,7 @@ primary_bootstrap_copy:
# To remove modules left by the bootstrap building, but leave (restore)
# the modules in kernel which are needed for an emulator build
-KERNEL_PRELOAD = otp_ring0 init erl_prim_loader prim_inet prim_file zlib prim_zip erlang erts_code_purger
+KERNEL_PRELOAD = erl_init init erl_prim_loader prim_inet prim_file zlib prim_zip erlang erts_code_purger
KERNEL_PRELOAD_BEAMS=$(KERNEL_PRELOAD:%=$(BOOTSTRAP_TOP)/lib/kernel/ebin/%.beam)
start_scripts:
diff --git a/bootstrap/bin/no_dot_erlang.boot b/bootstrap/bin/no_dot_erlang.boot
index 127072b3ed..7562bde377 100644
--- a/bootstrap/bin/no_dot_erlang.boot
+++ b/bootstrap/bin/no_dot_erlang.boot
Binary files differ
diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot
index 127072b3ed..7562bde377 100644
--- a/bootstrap/bin/start.boot
+++ b/bootstrap/bin/start.boot
Binary files differ
diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot
index 127072b3ed..7562bde377 100644
--- a/bootstrap/bin/start_clean.boot
+++ b/bootstrap/bin/start_clean.boot
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_a.beam b/bootstrap/lib/compiler/ebin/beam_a.beam
index 248c6dc0e4..d877b8962c 100644
--- a/bootstrap/lib/compiler/ebin/beam_a.beam
+++ b/bootstrap/lib/compiler/ebin/beam_a.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam
index c0db0d1ac4..6753eda31d 100644
--- a/bootstrap/lib/compiler/ebin/beam_asm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_asm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam
index dc941da6ae..e28b5daeb4 100644
--- a/bootstrap/lib/compiler/ebin/beam_block.beam
+++ b/bootstrap/lib/compiler/ebin/beam_block.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bs.beam b/bootstrap/lib/compiler/ebin/beam_bs.beam
index 1fc68940ac..81b05a3ca7 100644
--- a/bootstrap/lib/compiler/ebin/beam_bs.beam
+++ b/bootstrap/lib/compiler/ebin/beam_bs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam
deleted file mode 100644
index 6bf3b576b2..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_bsm.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_clean.beam b/bootstrap/lib/compiler/ebin/beam_clean.beam
index bc49326e74..c6d3c34e1f 100644
--- a/bootstrap/lib/compiler/ebin/beam_clean.beam
+++ b/bootstrap/lib/compiler/ebin/beam_clean.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam
deleted file mode 100644
index 534eb65372..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_dead.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_dict.beam b/bootstrap/lib/compiler/ebin/beam_dict.beam
index 1e2068b5cb..d04130f560 100644
--- a/bootstrap/lib/compiler/ebin/beam_dict.beam
+++ b/bootstrap/lib/compiler/ebin/beam_dict.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam
index 2d9bc49992..b0b444d886 100644
--- a/bootstrap/lib/compiler/ebin/beam_disasm.beam
+++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam
index 6eed82587a..955220778d 100644
--- a/bootstrap/lib/compiler/ebin/beam_except.beam
+++ b/bootstrap/lib/compiler/ebin/beam_except.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_flatten.beam b/bootstrap/lib/compiler/ebin/beam_flatten.beam
index e039f3c12b..cc245af68a 100644
--- a/bootstrap/lib/compiler/ebin/beam_flatten.beam
+++ b/bootstrap/lib/compiler/ebin/beam_flatten.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam
index 6af8a015c0..cfdb0c7c70 100644
--- a/bootstrap/lib/compiler/ebin/beam_jump.beam
+++ b/bootstrap/lib/compiler/ebin/beam_jump.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam
new file mode 100644
index 0000000000..4f5a916eb2
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_kernel_to_ssa.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_listing.beam b/bootstrap/lib/compiler/ebin/beam_listing.beam
index 87a8791bc4..46d76f72ce 100644
--- a/bootstrap/lib/compiler/ebin/beam_listing.beam
+++ b/bootstrap/lib/compiler/ebin/beam_listing.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_opcodes.beam b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
index 98b2c19b48..52a23f7f6c 100644
--- a/bootstrap/lib/compiler/ebin/beam_opcodes.beam
+++ b/bootstrap/lib/compiler/ebin/beam_opcodes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_peep.beam b/bootstrap/lib/compiler/ebin/beam_peep.beam
index 5f33584fe4..bda44b0926 100644
--- a/bootstrap/lib/compiler/ebin/beam_peep.beam
+++ b/bootstrap/lib/compiler/ebin/beam_peep.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam
deleted file mode 100644
index 909e5403d1..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_receive.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_record.beam b/bootstrap/lib/compiler/ebin/beam_record.beam
deleted file mode 100644
index 188bd82412..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_record.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_reorder.beam b/bootstrap/lib/compiler/ebin/beam_reorder.beam
deleted file mode 100644
index 05562e19ea..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_reorder.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_split.beam b/bootstrap/lib/compiler/ebin/beam_split.beam
deleted file mode 100644
index 476dd53ee6..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_split.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa.beam b/bootstrap/lib/compiler/ebin/beam_ssa.beam
new file mode 100644
index 0000000000..956ece3826
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam
new file mode 100644
index 0000000000..b0c07c6965
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam
new file mode 100644
index 0000000000..4b4a56c18a
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam
new file mode 100644
index 0000000000..9abb8910d8
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_dead.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam b/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam
new file mode 100644
index 0000000000..dc26c2bf66
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_funs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam b/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam
new file mode 100644
index 0000000000..97333674aa
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
new file mode 100644
index 0000000000..5e31165ae6
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_opt.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam
new file mode 100644
index 0000000000..3e30ce48b2
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam
new file mode 100644
index 0000000000..3fc568be02
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_pre_codegen.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam
new file mode 100644
index 0000000000..28b5ede5fc
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_recv.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_ssa_type.beam b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam
new file mode 100644
index 0000000000..a89c962f67
--- /dev/null
+++ b/bootstrap/lib/compiler/ebin/beam_ssa_type.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam
index 32cc6efe88..a5cef23105 100644
--- a/bootstrap/lib/compiler/ebin/beam_trim.beam
+++ b/bootstrap/lib/compiler/ebin/beam_trim.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam
deleted file mode 100644
index 266c04acfd..0000000000
--- a/bootstrap/lib/compiler/ebin/beam_type.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam
index 5648719621..527e8ea2c5 100644
--- a/bootstrap/lib/compiler/ebin/beam_utils.beam
+++ b/bootstrap/lib/compiler/ebin/beam_utils.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam
index 2bcec9ca3c..c90e9a2ae7 100644
--- a/bootstrap/lib/compiler/ebin/beam_validator.beam
+++ b/bootstrap/lib/compiler/ebin/beam_validator.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/beam_z.beam b/bootstrap/lib/compiler/ebin/beam_z.beam
index 57698dbb3b..f2c912f591 100644
--- a/bootstrap/lib/compiler/ebin/beam_z.beam
+++ b/bootstrap/lib/compiler/ebin/beam_z.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam
index 4f8ae7ca43..be3e9ddac7 100644
--- a/bootstrap/lib/compiler/ebin/cerl.beam
+++ b/bootstrap/lib/compiler/ebin/cerl.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
index fdd67aebde..ba92f93751 100644
--- a/bootstrap/lib/compiler/ebin/cerl_clauses.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_clauses.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam
index f0d6063f19..8fae7dc8f7 100644
--- a/bootstrap/lib/compiler/ebin/cerl_inline.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_sets.beam b/bootstrap/lib/compiler/ebin/cerl_sets.beam
index 6905c648c2..4ab7584977 100644
--- a/bootstrap/lib/compiler/ebin/cerl_sets.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_sets.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam
index 4304437799..e0d65a411a 100644
--- a/bootstrap/lib/compiler/ebin/cerl_trees.beam
+++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam
index d1a9058417..c5e1c4701e 100644
--- a/bootstrap/lib/compiler/ebin/compile.beam
+++ b/bootstrap/lib/compiler/ebin/compile.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/compiler.app b/bootstrap/lib/compiler/ebin/compiler.app
index 1506292674..539383e02e 100644
--- a/bootstrap/lib/compiler/ebin/compiler.app
+++ b/bootstrap/lib/compiler/ebin/compiler.app
@@ -19,29 +19,34 @@
{application, compiler,
[{description, "ERTS CXC 138 10"},
- {vsn, "7.1.5"},
+ {vsn, "7.2.6"},
{modules, [
beam_a,
beam_asm,
beam_block,
beam_bs,
- beam_bsm,
beam_clean,
- beam_dead,
beam_dict,
beam_disasm,
beam_except,
beam_flatten,
beam_jump,
+ beam_kernel_to_ssa,
beam_listing,
beam_opcodes,
beam_peep,
- beam_receive,
- beam_reorder,
- beam_record,
- beam_split,
+ beam_ssa,
+ beam_ssa_bsm,
+ beam_ssa_codegen,
+ beam_ssa_dead,
+ beam_ssa_funs,
+ beam_ssa_lint,
+ beam_ssa_opt,
+ beam_ssa_pp,
+ beam_ssa_pre_codegen,
+ beam_ssa_recv,
+ beam_ssa_type,
beam_trim,
- beam_type,
beam_utils,
beam_validator,
beam_z,
@@ -65,7 +70,6 @@
sys_core_fold_lists,
sys_core_inline,
sys_pre_attributes,
- v3_codegen,
v3_core,
v3_kernel,
v3_kernel_pp
diff --git a/bootstrap/lib/compiler/ebin/compiler.appup b/bootstrap/lib/compiler/ebin/compiler.appup
index 350a3924e7..399b1af1bb 100644
--- a/bootstrap/lib/compiler/ebin/compiler.appup
+++ b/bootstrap/lib/compiler/ebin/compiler.appup
@@ -16,7 +16,7 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
-{"7.1.5",
+{"7.2.4",
[{<<".*">>,[{restart_application, compiler}]}],
[{<<".*">>,[{restart_application, compiler}]}]
}.
diff --git a/bootstrap/lib/compiler/ebin/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam
index f3737ecc26..e8dae016cd 100644
--- a/bootstrap/lib/compiler/ebin/core_lib.beam
+++ b/bootstrap/lib/compiler/ebin/core_lib.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam
index 567e381ee8..fdbdd9bcfc 100644
--- a/bootstrap/lib/compiler/ebin/core_lint.beam
+++ b/bootstrap/lib/compiler/ebin/core_lint.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam
index 618668e92e..dde063341d 100644
--- a/bootstrap/lib/compiler/ebin/core_parse.beam
+++ b/bootstrap/lib/compiler/ebin/core_parse.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam
index 6518f3a4ce..e9d9399b4a 100644
--- a/bootstrap/lib/compiler/ebin/core_pp.beam
+++ b/bootstrap/lib/compiler/ebin/core_pp.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam
index bc0190fdb1..b9bb73befa 100644
--- a/bootstrap/lib/compiler/ebin/core_scan.beam
+++ b/bootstrap/lib/compiler/ebin/core_scan.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/erl_bifs.beam b/bootstrap/lib/compiler/ebin/erl_bifs.beam
index 37bd743796..dc3ede0fce 100644
--- a/bootstrap/lib/compiler/ebin/erl_bifs.beam
+++ b/bootstrap/lib/compiler/ebin/erl_bifs.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/rec_env.beam b/bootstrap/lib/compiler/ebin/rec_env.beam
index b0ef249e15..1f37c6dccd 100644
--- a/bootstrap/lib/compiler/ebin/rec_env.beam
+++ b/bootstrap/lib/compiler/ebin/rec_env.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_alias.beam b/bootstrap/lib/compiler/ebin/sys_core_alias.beam
index 52e46da7ad..2829b49dce 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_alias.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_alias.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam
index d14579410c..38ce74115e 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_bsm.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_bsm.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam b/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
index c189549b16..d70e7c0ecc 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_dsetel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
index 073bb041d4..3a7a446886 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam
index 0ad7ab7f9c..db9b195aec 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_fold_lists.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
index ebe35883b5..f05a3f5cb3 100644
--- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam
+++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
index d96bc1913a..695d69276b 100644
--- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
+++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam
deleted file mode 100644
index c537f1e550..0000000000
--- a/bootstrap/lib/compiler/ebin/v3_codegen.beam
+++ /dev/null
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam
index 162105c0bf..309669c70e 100644
--- a/bootstrap/lib/compiler/ebin/v3_core.beam
+++ b/bootstrap/lib/compiler/ebin/v3_core.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam
index 7a155ec05c..ce882eb80e 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
index 4aef1389be..8745529b63 100644
--- a/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
+++ b/bootstrap/lib/compiler/ebin/v3_kernel_pp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application.beam b/bootstrap/lib/kernel/ebin/application.beam
index 58f1681fba..c4c2511632 100644
--- a/bootstrap/lib/kernel/ebin/application.beam
+++ b/bootstrap/lib/kernel/ebin/application.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam
index 4f52e506c2..e03a44a808 100644
--- a/bootstrap/lib/kernel/ebin/application_controller.beam
+++ b/bootstrap/lib/kernel/ebin/application_controller.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_master.beam b/bootstrap/lib/kernel/ebin/application_master.beam
index 55adf9849c..dec8d01cd6 100644
--- a/bootstrap/lib/kernel/ebin/application_master.beam
+++ b/bootstrap/lib/kernel/ebin/application_master.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/application_starter.beam b/bootstrap/lib/kernel/ebin/application_starter.beam
index ca7b77abcb..549515bfb1 100644
--- a/bootstrap/lib/kernel/ebin/application_starter.beam
+++ b/bootstrap/lib/kernel/ebin/application_starter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/auth.beam b/bootstrap/lib/kernel/ebin/auth.beam
index 200a996f96..676c46c01c 100644
--- a/bootstrap/lib/kernel/ebin/auth.beam
+++ b/bootstrap/lib/kernel/ebin/auth.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code.beam b/bootstrap/lib/kernel/ebin/code.beam
index 669efdc50f..5dc1c3bbc1 100644
--- a/bootstrap/lib/kernel/ebin/code.beam
+++ b/bootstrap/lib/kernel/ebin/code.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam
index 93c354bf40..1f2b6ac850 100644
--- a/bootstrap/lib/kernel/ebin/code_server.beam
+++ b/bootstrap/lib/kernel/ebin/code_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam
index 4f0eae4984..7efd785398 100644
--- a/bootstrap/lib/kernel/ebin/disk_log.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam
index 10c7275240..11507078b8 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_1.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam
index 0f0418a911..911467d38b 100644
--- a/bootstrap/lib/kernel/ebin/disk_log_server.beam
+++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam
index 517fa7dfdb..89e81d3698 100644
--- a/bootstrap/lib/kernel/ebin/dist_ac.beam
+++ b/bootstrap/lib/kernel/ebin/dist_ac.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam
index 3956e595f8..9de3831161 100644
--- a/bootstrap/lib/kernel/ebin/dist_util.beam
+++ b/bootstrap/lib/kernel/ebin/dist_util.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_boot_server.beam b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
index 6559fc04c1..d4812bf6a0 100644
--- a/bootstrap/lib/kernel/ebin/erl_boot_server.beam
+++ b/bootstrap/lib/kernel/ebin/erl_boot_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_ddll.beam b/bootstrap/lib/kernel/ebin/erl_ddll.beam
index de9b1cb638..9229ce42ff 100644
--- a/bootstrap/lib/kernel/ebin/erl_ddll.beam
+++ b/bootstrap/lib/kernel/ebin/erl_ddll.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_distribution.beam b/bootstrap/lib/kernel/ebin/erl_distribution.beam
index 8c8cba9068..082b63bbc4 100644
--- a/bootstrap/lib/kernel/ebin/erl_distribution.beam
+++ b/bootstrap/lib/kernel/ebin/erl_distribution.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_epmd.beam b/bootstrap/lib/kernel/ebin/erl_epmd.beam
index 449fd8dff1..cee63495b2 100644
--- a/bootstrap/lib/kernel/ebin/erl_epmd.beam
+++ b/bootstrap/lib/kernel/ebin/erl_epmd.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_reply.beam b/bootstrap/lib/kernel/ebin/erl_reply.beam
index 25b4b6c55e..011e19150a 100644
--- a/bootstrap/lib/kernel/ebin/erl_reply.beam
+++ b/bootstrap/lib/kernel/ebin/erl_reply.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
index 1a1d9d28ee..384d5cf690 100644
--- a/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
+++ b/bootstrap/lib/kernel/ebin/erl_signal_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_handler.beam b/bootstrap/lib/kernel/ebin/error_handler.beam
index 1ce96ca432..24b9ba4a9b 100644
--- a/bootstrap/lib/kernel/ebin/error_handler.beam
+++ b/bootstrap/lib/kernel/ebin/error_handler.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/error_logger.beam b/bootstrap/lib/kernel/ebin/error_logger.beam
index 8dd3c07f71..2b54c327d0 100644
--- a/bootstrap/lib/kernel/ebin/error_logger.beam
+++ b/bootstrap/lib/kernel/ebin/error_logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/erts_debug.beam b/bootstrap/lib/kernel/ebin/erts_debug.beam
index 82641f173a..50a3a21ee5 100644
--- a/bootstrap/lib/kernel/ebin/erts_debug.beam
+++ b/bootstrap/lib/kernel/ebin/erts_debug.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam
index 07a4f410e1..d3c8b7d97c 100644
--- a/bootstrap/lib/kernel/ebin/file.beam
+++ b/bootstrap/lib/kernel/ebin/file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam
index d9ca62a82b..d946cf31f3 100644
--- a/bootstrap/lib/kernel/ebin/file_io_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_io_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam
index 4f1d53cb39..41b2618ea0 100644
--- a/bootstrap/lib/kernel/ebin/file_server.beam
+++ b/bootstrap/lib/kernel/ebin/file_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_sctp.beam b/bootstrap/lib/kernel/ebin/gen_sctp.beam
index dcd81b1c6f..08d07963d2 100644
--- a/bootstrap/lib/kernel/ebin/gen_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_tcp.beam b/bootstrap/lib/kernel/ebin/gen_tcp.beam
index 0e492978d5..c661468df5 100644
--- a/bootstrap/lib/kernel/ebin/gen_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/gen_udp.beam b/bootstrap/lib/kernel/ebin/gen_udp.beam
index 323b6cd4bb..64ac806d7c 100644
--- a/bootstrap/lib/kernel/ebin/gen_udp.beam
+++ b/bootstrap/lib/kernel/ebin/gen_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam
index e138217d25..b417fee3ca 100644
--- a/bootstrap/lib/kernel/ebin/global.beam
+++ b/bootstrap/lib/kernel/ebin/global.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam
index b072f96e5d..724b1b6bf9 100644
--- a/bootstrap/lib/kernel/ebin/global_group.beam
+++ b/bootstrap/lib/kernel/ebin/global_group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/global_search.beam b/bootstrap/lib/kernel/ebin/global_search.beam
index 653d2a8699..907abbc3ab 100644
--- a/bootstrap/lib/kernel/ebin/global_search.beam
+++ b/bootstrap/lib/kernel/ebin/global_search.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam
index 03abd10d20..af8711daf3 100644
--- a/bootstrap/lib/kernel/ebin/group.beam
+++ b/bootstrap/lib/kernel/ebin/group.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/group_history.beam b/bootstrap/lib/kernel/ebin/group_history.beam
index 97f98ebe2f..70f42c4b4e 100644
--- a/bootstrap/lib/kernel/ebin/group_history.beam
+++ b/bootstrap/lib/kernel/ebin/group_history.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/heart.beam b/bootstrap/lib/kernel/ebin/heart.beam
index 0c3caaf969..9ebbe2ed01 100644
--- a/bootstrap/lib/kernel/ebin/heart.beam
+++ b/bootstrap/lib/kernel/ebin/heart.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
index 989fceaa2c..9ea40e3d27 100644
--- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
+++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet.beam b/bootstrap/lib/kernel/ebin/inet.beam
index 7df45ea492..4c6d182f43 100644
--- a/bootstrap/lib/kernel/ebin/inet.beam
+++ b/bootstrap/lib/kernel/ebin/inet.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_sctp.beam b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
index bea47a3591..7a98863920 100644
--- a/bootstrap/lib/kernel/ebin/inet6_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_tcp.beam b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
index db0ead9cdd..0d614e4098 100644
--- a/bootstrap/lib/kernel/ebin/inet6_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet6_udp.beam b/bootstrap/lib/kernel/ebin/inet6_udp.beam
index abc4b650ae..e580be53a6 100644
--- a/bootstrap/lib/kernel/ebin/inet6_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet6_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_config.beam b/bootstrap/lib/kernel/ebin/inet_config.beam
index 5b50b553d7..ace0a62901 100644
--- a/bootstrap/lib/kernel/ebin/inet_config.beam
+++ b/bootstrap/lib/kernel/ebin/inet_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_db.beam b/bootstrap/lib/kernel/ebin/inet_db.beam
index 513a7dc03d..0ffc771f71 100644
--- a/bootstrap/lib/kernel/ebin/inet_db.beam
+++ b/bootstrap/lib/kernel/ebin/inet_db.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam
index f483acd96c..4f07ece7db 100644
--- a/bootstrap/lib/kernel/ebin/inet_dns.beam
+++ b/bootstrap/lib/kernel/ebin/inet_dns.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
index 610d9a2205..2d6c35e45c 100644
--- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
+++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_hosts.beam b/bootstrap/lib/kernel/ebin/inet_hosts.beam
index 63fadee640..0d38089d35 100644
--- a/bootstrap/lib/kernel/ebin/inet_hosts.beam
+++ b/bootstrap/lib/kernel/ebin/inet_hosts.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_parse.beam b/bootstrap/lib/kernel/ebin/inet_parse.beam
index 175649cd81..4c01f59045 100644
--- a/bootstrap/lib/kernel/ebin/inet_parse.beam
+++ b/bootstrap/lib/kernel/ebin/inet_parse.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_res.beam b/bootstrap/lib/kernel/ebin/inet_res.beam
index 463f90fae8..edfdd89e55 100644
--- a/bootstrap/lib/kernel/ebin/inet_res.beam
+++ b/bootstrap/lib/kernel/ebin/inet_res.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_sctp.beam b/bootstrap/lib/kernel/ebin/inet_sctp.beam
index 5107eb63b8..a7fbc642d6 100644
--- a/bootstrap/lib/kernel/ebin/inet_sctp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_sctp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp.beam b/bootstrap/lib/kernel/ebin/inet_tcp.beam
index 304272a20d..1e377b091b 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
index c33a9e7f3a..624600da13 100644
--- a/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
+++ b/bootstrap/lib/kernel/ebin/inet_tcp_dist.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/inet_udp.beam b/bootstrap/lib/kernel/ebin/inet_udp.beam
index d358ee15dc..2a47344012 100644
--- a/bootstrap/lib/kernel/ebin/inet_udp.beam
+++ b/bootstrap/lib/kernel/ebin/inet_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel.app b/bootstrap/lib/kernel/ebin/kernel.app
index 340ed8653f..4bc7cf56f0 100644
--- a/bootstrap/lib/kernel/ebin/kernel.app
+++ b/bootstrap/lib/kernel/ebin/kernel.app
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@
{application, kernel,
[
{description, "ERTS CXC 138 10"},
- {vsn, "5.4.3"},
+ {vsn, "6.0"},
{modules, [application,
application_controller,
application_master,
@@ -67,6 +67,7 @@
logger_filters,
logger_formatter,
logger_h_common,
+ logger_handler_watcher,
logger_server,
logger_simple_h,
logger_std_h,
@@ -129,6 +130,7 @@
kernel_refc,
kernel_sup,
logger,
+ logger_handler_watcher,
logger_sup,
net_kernel,
net_sup,
diff --git a/bootstrap/lib/kernel/ebin/kernel.beam b/bootstrap/lib/kernel/ebin/kernel.beam
index b3f0783d25..429a942c90 100644
--- a/bootstrap/lib/kernel/ebin/kernel.beam
+++ b/bootstrap/lib/kernel/ebin/kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel_config.beam b/bootstrap/lib/kernel/ebin/kernel_config.beam
index 85b517fe0f..fdd3431f84 100644
--- a/bootstrap/lib/kernel/ebin/kernel_config.beam
+++ b/bootstrap/lib/kernel/ebin/kernel_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/kernel_refc.beam b/bootstrap/lib/kernel/ebin/kernel_refc.beam
index 2fca33154c..999adb8bd8 100644
--- a/bootstrap/lib/kernel/ebin/kernel_refc.beam
+++ b/bootstrap/lib/kernel/ebin/kernel_refc.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/local_tcp.beam b/bootstrap/lib/kernel/ebin/local_tcp.beam
index 02c5848f11..023769d6a5 100644
--- a/bootstrap/lib/kernel/ebin/local_tcp.beam
+++ b/bootstrap/lib/kernel/ebin/local_tcp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/local_udp.beam b/bootstrap/lib/kernel/ebin/local_udp.beam
index 400c9ca23b..ae7a9dd029 100644
--- a/bootstrap/lib/kernel/ebin/local_udp.beam
+++ b/bootstrap/lib/kernel/ebin/local_udp.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger.beam b/bootstrap/lib/kernel/ebin/logger.beam
index e6d8f5b2c6..b92ec655f0 100644
--- a/bootstrap/lib/kernel/ebin/logger.beam
+++ b/bootstrap/lib/kernel/ebin/logger.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_backend.beam b/bootstrap/lib/kernel/ebin/logger_backend.beam
index be448bd75c..fdb087887a 100644
--- a/bootstrap/lib/kernel/ebin/logger_backend.beam
+++ b/bootstrap/lib/kernel/ebin/logger_backend.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_config.beam b/bootstrap/lib/kernel/ebin/logger_config.beam
index 52f7847561..cc94f93932 100644
--- a/bootstrap/lib/kernel/ebin/logger_config.beam
+++ b/bootstrap/lib/kernel/ebin/logger_config.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
index cc1b649eb7..9ef562adf2 100644
--- a/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_disk_log_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_filters.beam b/bootstrap/lib/kernel/ebin/logger_filters.beam
index 57197e137c..56489cc160 100644
--- a/bootstrap/lib/kernel/ebin/logger_filters.beam
+++ b/bootstrap/lib/kernel/ebin/logger_filters.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_formatter.beam b/bootstrap/lib/kernel/ebin/logger_formatter.beam
index 7f7d77ab28..cde8151ecf 100644
--- a/bootstrap/lib/kernel/ebin/logger_formatter.beam
+++ b/bootstrap/lib/kernel/ebin/logger_formatter.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_h_common.beam b/bootstrap/lib/kernel/ebin/logger_h_common.beam
index 7d96f2d69e..273a51d90d 100644
--- a/bootstrap/lib/kernel/ebin/logger_h_common.beam
+++ b/bootstrap/lib/kernel/ebin/logger_h_common.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam
new file mode 100644
index 0000000000..91e088c8b9
--- /dev/null
+++ b/bootstrap/lib/kernel/ebin/logger_handler_watcher.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_server.beam b/bootstrap/lib/kernel/ebin/logger_server.beam
index 4885c0992a..def2f5e30f 100644
--- a/bootstrap/lib/kernel/ebin/logger_server.beam
+++ b/bootstrap/lib/kernel/ebin/logger_server.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_simple_h.beam b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
index 890de624b9..ca88d0b9ec 100644
--- a/bootstrap/lib/kernel/ebin/logger_simple_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_simple_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_std_h.beam b/bootstrap/lib/kernel/ebin/logger_std_h.beam
index e8c3bb83d0..9a21e5d44e 100644
--- a/bootstrap/lib/kernel/ebin/logger_std_h.beam
+++ b/bootstrap/lib/kernel/ebin/logger_std_h.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/logger_sup.beam b/bootstrap/lib/kernel/ebin/logger_sup.beam
index 9bef3c861c..32eb526a09 100644
--- a/bootstrap/lib/kernel/ebin/logger_sup.beam
+++ b/bootstrap/lib/kernel/ebin/logger_sup.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net.beam b/bootstrap/lib/kernel/ebin/net.beam
index 29c8bc5dde..3e971eb0e1 100644
--- a/bootstrap/lib/kernel/ebin/net.beam
+++ b/bootstrap/lib/kernel/ebin/net.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_adm.beam b/bootstrap/lib/kernel/ebin/net_adm.beam
index 05aa46dcb8..3cd97ea91e 100644
--- a/bootstrap/lib/kernel/ebin/net_adm.beam
+++ b/bootstrap/lib/kernel/ebin/net_adm.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam
index 0a565d542d..f67541c6c7 100644
--- a/bootstrap/lib/kernel/ebin/net_kernel.beam
+++ b/bootstrap/lib/kernel/ebin/net_kernel.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/os.beam b/bootstrap/lib/kernel/ebin/os.beam
index f2a003d44f..d27da119c5 100644
--- a/bootstrap/lib/kernel/ebin/os.beam
+++ b/bootstrap/lib/kernel/ebin/os.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/pg2.beam b/bootstrap/lib/kernel/ebin/pg2.beam
index a106700e44..cbb3e96d45 100644
--- a/bootstrap/lib/kernel/ebin/pg2.beam
+++ b/bootstrap/lib/kernel/ebin/pg2.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/ram_file.beam b/bootstrap/lib/kernel/ebin/ram_file.beam
index c2f265ede4..613a5bafb5 100644
--- a/bootstrap/lib/kernel/ebin/ram_file.beam
+++ b/bootstrap/lib/kernel/ebin/ram_file.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io.beam b/bootstrap/lib/kernel/ebin/raw_file_io.beam
index 734a051882..ca03dee5df 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam
index 6f07a3c5c3..f3d6221ff1 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_compressed.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
index 222817d912..0310690034 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_deflate.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
index 2c20a06fd1..c17c96eada 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_delayed.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
index 228a8f28a5..15ae6c3230 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_inflate.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam
index 4c69c890cd..8f13c65cd6 100644
--- a/bootstrap/lib/kernel/ebin/raw_file_io_list.beam
+++ b/bootstrap/lib/kernel/ebin/raw_file_io_list.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/rpc.beam b/bootstrap/lib/kernel/ebin/rpc.beam
index 7a1c9e0b31..59ed54d229 100644
--- a/bootstrap/lib/kernel/ebin/rpc.beam
+++ b/bootstrap/lib/kernel/ebin/rpc.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/seq_trace.beam b/bootstrap/lib/kernel/ebin/seq_trace.beam
index 1d1e277bf3..3ab4a7360e 100644
--- a/bootstrap/lib/kernel/ebin/seq_trace.beam
+++ b/bootstrap/lib/kernel/ebin/seq_trace.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/standard_error.beam b/bootstrap/lib/kernel/ebin/standard_error.beam
index c01106ef11..25a9b9c150 100644
--- a/bootstrap/lib/kernel/ebin/standard_error.beam
+++ b/bootstrap/lib/kernel/ebin/standard_error.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam
index 4cbf2174a2..c56303e2a6 100644
--- a/bootstrap/lib/kernel/ebin/user.beam
+++ b/bootstrap/lib/kernel/ebin/user.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user_drv.beam b/bootstrap/lib/kernel/ebin/user_drv.beam
index c5a3330ee1..a569446fb9 100644
--- a/bootstrap/lib/kernel/ebin/user_drv.beam
+++ b/bootstrap/lib/kernel/ebin/user_drv.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/user_sup.beam b/bootstrap/lib/kernel/ebin/user_sup.beam
index 6aa34138c8..96864f4456 100644
--- a/bootstrap/lib/kernel/ebin/user_sup.beam
+++ b/bootstrap/lib/kernel/ebin/user_sup.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
index a0f24625b4..92ce6c3271 100644
--- a/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
+++ b/bootstrap/lib/kernel/ebin/wrap_log_reader.beam
Binary files differ
diff --git a/bootstrap/lib/kernel/include/dist.hrl b/bootstrap/lib/kernel/include/dist.hrl
index 6baaa35d72..003852f1b0 100644
--- a/bootstrap/lib/kernel/include/dist.hrl
+++ b/bootstrap/lib/kernel/include/dist.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/bootstrap/lib/kernel/include/dist_util.hrl b/bootstrap/lib/kernel/include/dist_util.hrl
index eeb0f8dd43..56f775f060 100644
--- a/bootstrap/lib/kernel/include/dist_util.hrl
+++ b/bootstrap/lib/kernel/include/dist_util.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/bootstrap/lib/kernel/include/logger.hrl b/bootstrap/lib/kernel/include/logger.hrl
index 2143ccd297..b09977e0f2 100644
--- a/bootstrap/lib/kernel/include/logger.hrl
+++ b/bootstrap/lib/kernel/include/logger.hrl
@@ -32,6 +32,10 @@
-define(LOG_DEBUG(A,B),?DO_LOG(debug,[A,B])).
-define(LOG_DEBUG(A,B,C),?DO_LOG(debug,[A,B,C])).
+-define(LOG(L,A),?DO_LOG(L,[A])).
+-define(LOG(L,A,B),?DO_LOG(L,[A,B])).
+-define(LOG(L,A,B,C),?DO_LOG(L,[A,B,C])).
+
-define(LOCATION,#{mfa=>{?MODULE,?FUNCTION_NAME,?FUNCTION_ARITY},
line=>?LINE,
file=>?FILE}).
diff --git a/bootstrap/lib/stdlib/ebin/array.beam b/bootstrap/lib/stdlib/ebin/array.beam
index e352b65951..ab8a6721dc 100644
--- a/bootstrap/lib/stdlib/ebin/array.beam
+++ b/bootstrap/lib/stdlib/ebin/array.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/base64.beam b/bootstrap/lib/stdlib/ebin/base64.beam
index 902d8edc6c..abbf3a9dca 100644
--- a/bootstrap/lib/stdlib/ebin/base64.beam
+++ b/bootstrap/lib/stdlib/ebin/base64.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam
index b17a9b1947..d2a3d8bc8c 100644
--- a/bootstrap/lib/stdlib/ebin/beam_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/binary.beam b/bootstrap/lib/stdlib/ebin/binary.beam
index e712319947..2ba8310eda 100644
--- a/bootstrap/lib/stdlib/ebin/binary.beam
+++ b/bootstrap/lib/stdlib/ebin/binary.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/c.beam b/bootstrap/lib/stdlib/ebin/c.beam
index 6c8d14bac1..a72b4818af 100644
--- a/bootstrap/lib/stdlib/ebin/c.beam
+++ b/bootstrap/lib/stdlib/ebin/c.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/calendar.beam b/bootstrap/lib/stdlib/ebin/calendar.beam
index 099ded411d..3780b76e8c 100644
--- a/bootstrap/lib/stdlib/ebin/calendar.beam
+++ b/bootstrap/lib/stdlib/ebin/calendar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam
index 05b575cd05..d379fc99f9 100644
--- a/bootstrap/lib/stdlib/ebin/dets.beam
+++ b/bootstrap/lib/stdlib/ebin/dets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam
index 31f0f2701a..b8cbc51e95 100644
--- a/bootstrap/lib/stdlib/ebin/dets_server.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam
index 2b56a46eb1..bf2feb5926 100644
--- a/bootstrap/lib/stdlib/ebin/dets_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam
index 2fda3ba53f..798dc3a4fe 100644
--- a/bootstrap/lib/stdlib/ebin/dets_v9.beam
+++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/dict.beam b/bootstrap/lib/stdlib/ebin/dict.beam
index 345df4c87f..b2c81270ea 100644
--- a/bootstrap/lib/stdlib/ebin/dict.beam
+++ b/bootstrap/lib/stdlib/ebin/dict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph.beam b/bootstrap/lib/stdlib/ebin/digraph.beam
index 1faf374588..9ac947cadf 100644
--- a/bootstrap/lib/stdlib/ebin/digraph.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/digraph_utils.beam b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
index fa41a7af26..f4e4134bed 100644
--- a/bootstrap/lib/stdlib/ebin/digraph_utils.beam
+++ b/bootstrap/lib/stdlib/ebin/digraph_utils.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin.beam b/bootstrap/lib/stdlib/ebin/edlin.beam
index c8d4cac351..4f5958e043 100644
--- a/bootstrap/lib/stdlib/ebin/edlin.beam
+++ b/bootstrap/lib/stdlib/ebin/edlin.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/edlin_expand.beam b/bootstrap/lib/stdlib/ebin/edlin_expand.beam
index 62e209dcc7..760fca952b 100644
--- a/bootstrap/lib/stdlib/ebin/edlin_expand.beam
+++ b/bootstrap/lib/stdlib/ebin/edlin_expand.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam
index c87665ff86..83329ae3d6 100644
--- a/bootstrap/lib/stdlib/ebin/epp.beam
+++ b/bootstrap/lib/stdlib/ebin/epp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam
index e6042b9715..3a9a74bf4d 100644
--- a/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_abstract_code.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_anno.beam b/bootstrap/lib/stdlib/ebin/erl_anno.beam
index 7a0a4c08d8..68809d69cd 100644
--- a/bootstrap/lib/stdlib/ebin/erl_anno.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_anno.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_bits.beam b/bootstrap/lib/stdlib/ebin/erl_bits.beam
index b9b75ecaef..1d0a526e4e 100644
--- a/bootstrap/lib/stdlib/ebin/erl_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam
index a317ae28a1..81bdd8b8c4 100644
--- a/bootstrap/lib/stdlib/ebin/erl_compile.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_compile.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_error.beam b/bootstrap/lib/stdlib/ebin/erl_error.beam
index dc9d0a8d39..3470493604 100644
--- a/bootstrap/lib/stdlib/ebin/erl_error.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_error.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam
index eea70718c8..d4657d494d 100644
--- a/bootstrap/lib/stdlib/ebin/erl_eval.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
index 9a3daef51e..ccc4d6c08a 100644
--- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_internal.beam b/bootstrap/lib/stdlib/ebin/erl_internal.beam
index c571d9f6f3..827cbc4acb 100644
--- a/bootstrap/lib/stdlib/ebin/erl_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam
index 3fa4a49c24..0b32ca50c3 100644
--- a/bootstrap/lib/stdlib/ebin/erl_lint.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam
index 86876cda96..df1e061f86 100644
--- a/bootstrap/lib/stdlib/ebin/erl_parse.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
index a5d30afed2..5f6c03bcae 100644
--- a/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_posix_msg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_pp.beam b/bootstrap/lib/stdlib/ebin/erl_pp.beam
index f645aea910..df3415e73f 100644
--- a/bootstrap/lib/stdlib/ebin/erl_pp.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_pp.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam
index a7a2910e1b..aac45c66c8 100644
--- a/bootstrap/lib/stdlib/ebin/erl_scan.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam
index b72e4ebf6a..348b064eac 100644
--- a/bootstrap/lib/stdlib/ebin/erl_tar.beam
+++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
index 2f2e54de1a..6515da5411 100644
--- a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
+++ b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
index a6e46e72b4..117f096ebb 100644
--- a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
+++ b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam
index 781484fe0b..ee410f3d01 100644
--- a/bootstrap/lib/stdlib/ebin/escript.beam
+++ b/bootstrap/lib/stdlib/ebin/escript.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam
index ab4996ef4e..c2c8beefe3 100644
--- a/bootstrap/lib/stdlib/ebin/ets.beam
+++ b/bootstrap/lib/stdlib/ebin/ets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/eval_bits.beam b/bootstrap/lib/stdlib/ebin/eval_bits.beam
index 0a3c0b47fb..820db3becc 100644
--- a/bootstrap/lib/stdlib/ebin/eval_bits.beam
+++ b/bootstrap/lib/stdlib/ebin/eval_bits.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam
index 9fb87f4a68..0c91adb5b6 100644
--- a/bootstrap/lib/stdlib/ebin/file_sorter.beam
+++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filelib.beam b/bootstrap/lib/stdlib/ebin/filelib.beam
index d1ec5357fc..fd6842f28d 100644
--- a/bootstrap/lib/stdlib/ebin/filelib.beam
+++ b/bootstrap/lib/stdlib/ebin/filelib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam
index 85d568a8e1..62986a1af7 100644
--- a/bootstrap/lib/stdlib/ebin/filename.beam
+++ b/bootstrap/lib/stdlib/ebin/filename.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_sets.beam b/bootstrap/lib/stdlib/ebin/gb_sets.beam
index 43ba8674b7..bbd7eaf63e 100644
--- a/bootstrap/lib/stdlib/ebin/gb_sets.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam
index 4476889671..b04874d269 100644
--- a/bootstrap/lib/stdlib/ebin/gb_trees.beam
+++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam
index b0e38024c5..57f6de465e 100644
--- a/bootstrap/lib/stdlib/ebin/gen.beam
+++ b/bootstrap/lib/stdlib/ebin/gen.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_event.beam b/bootstrap/lib/stdlib/ebin/gen_event.beam
index ef8d0cd929..e9b3df8f3e 100644
--- a/bootstrap/lib/stdlib/ebin/gen_event.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_event.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
index 3a4df3499c..c70989905f 100644
--- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam
index 1752276cc8..02fe60432d 100644
--- a/bootstrap/lib/stdlib/ebin/gen_server.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_server.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/gen_statem.beam b/bootstrap/lib/stdlib/ebin/gen_statem.beam
index 1c1b93a036..5bb4b27e03 100644
--- a/bootstrap/lib/stdlib/ebin/gen_statem.beam
+++ b/bootstrap/lib/stdlib/ebin/gen_statem.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io.beam b/bootstrap/lib/stdlib/ebin/io.beam
index 197d9b7f9c..215cfbc131 100644
--- a/bootstrap/lib/stdlib/ebin/io.beam
+++ b/bootstrap/lib/stdlib/ebin/io.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam
index a6403bb708..9a64b00de3 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_format.beam b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
index a1acea2cee..0c3bbe4135 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_format.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_format.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
index b33a6bbd72..4a7cd7e4e0 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_fread.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
index dc91c318c5..75434ed111 100644
--- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
+++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/lists.beam b/bootstrap/lib/stdlib/ebin/lists.beam
index a711637e0c..8b31c38ab6 100644
--- a/bootstrap/lib/stdlib/ebin/lists.beam
+++ b/bootstrap/lib/stdlib/ebin/lists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/log_mf_h.beam b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
index b27db50f62..8f3f145399 100644
--- a/bootstrap/lib/stdlib/ebin/log_mf_h.beam
+++ b/bootstrap/lib/stdlib/ebin/log_mf_h.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/maps.beam b/bootstrap/lib/stdlib/ebin/maps.beam
index ec0ebce58a..1cc37072b6 100644
--- a/bootstrap/lib/stdlib/ebin/maps.beam
+++ b/bootstrap/lib/stdlib/ebin/maps.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam
index e465ca8d5d..17e910bed2 100644
--- a/bootstrap/lib/stdlib/ebin/ms_transform.beam
+++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/orddict.beam b/bootstrap/lib/stdlib/ebin/orddict.beam
index 57a23fbe98..66454c60ae 100644
--- a/bootstrap/lib/stdlib/ebin/orddict.beam
+++ b/bootstrap/lib/stdlib/ebin/orddict.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/ordsets.beam b/bootstrap/lib/stdlib/ebin/ordsets.beam
index eac57f960a..9e49566404 100644
--- a/bootstrap/lib/stdlib/ebin/ordsets.beam
+++ b/bootstrap/lib/stdlib/ebin/ordsets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam
index c42b18f6cf..5c46c6fdde 100644
--- a/bootstrap/lib/stdlib/ebin/otp_internal.beam
+++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/pool.beam b/bootstrap/lib/stdlib/ebin/pool.beam
index b056cf44ec..41fb279bcb 100644
--- a/bootstrap/lib/stdlib/ebin/pool.beam
+++ b/bootstrap/lib/stdlib/ebin/pool.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proc_lib.beam b/bootstrap/lib/stdlib/ebin/proc_lib.beam
index ce36bcf6fc..0b65575cd7 100644
--- a/bootstrap/lib/stdlib/ebin/proc_lib.beam
+++ b/bootstrap/lib/stdlib/ebin/proc_lib.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/proplists.beam b/bootstrap/lib/stdlib/ebin/proplists.beam
index cb2e3ddb11..99884551f6 100644
--- a/bootstrap/lib/stdlib/ebin/proplists.beam
+++ b/bootstrap/lib/stdlib/ebin/proplists.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam
index c1cd50f143..30db434bd6 100644
--- a/bootstrap/lib/stdlib/ebin/qlc.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
index 4153598cc7..868e027b9d 100644
--- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam
+++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/queue.beam b/bootstrap/lib/stdlib/ebin/queue.beam
index 8c6b611247..c8636d83c0 100644
--- a/bootstrap/lib/stdlib/ebin/queue.beam
+++ b/bootstrap/lib/stdlib/ebin/queue.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/rand.beam b/bootstrap/lib/stdlib/ebin/rand.beam
index 55f8db7445..6aa7b99ad3 100644
--- a/bootstrap/lib/stdlib/ebin/rand.beam
+++ b/bootstrap/lib/stdlib/ebin/rand.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/random.beam b/bootstrap/lib/stdlib/ebin/random.beam
index 37f12f8a36..c3041437d5 100644
--- a/bootstrap/lib/stdlib/ebin/random.beam
+++ b/bootstrap/lib/stdlib/ebin/random.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam
index 4334fa8dc4..17dc72c040 100644
--- a/bootstrap/lib/stdlib/ebin/re.beam
+++ b/bootstrap/lib/stdlib/ebin/re.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sets.beam b/bootstrap/lib/stdlib/ebin/sets.beam
index c1b7414741..2301e4b999 100644
--- a/bootstrap/lib/stdlib/ebin/sets.beam
+++ b/bootstrap/lib/stdlib/ebin/sets.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell.beam b/bootstrap/lib/stdlib/ebin/shell.beam
index 65ffc775ad..a4ec7785b9 100644
--- a/bootstrap/lib/stdlib/ebin/shell.beam
+++ b/bootstrap/lib/stdlib/ebin/shell.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/shell_default.beam b/bootstrap/lib/stdlib/ebin/shell_default.beam
index b2b955de04..afd0c65921 100644
--- a/bootstrap/lib/stdlib/ebin/shell_default.beam
+++ b/bootstrap/lib/stdlib/ebin/shell_default.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/slave.beam b/bootstrap/lib/stdlib/ebin/slave.beam
index e832637c7c..5f51b0fcf6 100644
--- a/bootstrap/lib/stdlib/ebin/slave.beam
+++ b/bootstrap/lib/stdlib/ebin/slave.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam
index 0acc6b92ba..96c27e075b 100644
--- a/bootstrap/lib/stdlib/ebin/sofs.beam
+++ b/bootstrap/lib/stdlib/ebin/sofs.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/stdlib.app b/bootstrap/lib/stdlib/ebin/stdlib.app
index 20c978670e..b0ead5cd91 100644
--- a/bootstrap/lib/stdlib/ebin/stdlib.app
+++ b/bootstrap/lib/stdlib/ebin/stdlib.app
@@ -20,7 +20,7 @@
%%
{application, stdlib,
[{description, "ERTS CXC 138 10"},
- {vsn, "3.4.5"},
+ {vsn, "3.5.1"},
{modules, [array,
base64,
beam_lib,
diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam
index 57142f539a..0ac544efeb 100644
--- a/bootstrap/lib/stdlib/ebin/string.beam
+++ b/bootstrap/lib/stdlib/ebin/string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam
index 939f385c93..45511a0815 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
index 6cfaa984df..eaf1965280 100644
--- a/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
+++ b/bootstrap/lib/stdlib/ebin/supervisor_bridge.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/sys.beam b/bootstrap/lib/stdlib/ebin/sys.beam
index 599cc20df4..32c2adfea4 100644
--- a/bootstrap/lib/stdlib/ebin/sys.beam
+++ b/bootstrap/lib/stdlib/ebin/sys.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/timer.beam b/bootstrap/lib/stdlib/ebin/timer.beam
index 7baece7eb2..962d6f7cc4 100644
--- a/bootstrap/lib/stdlib/ebin/timer.beam
+++ b/bootstrap/lib/stdlib/ebin/timer.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam
index bdd4374aef..10e4299c03 100644
--- a/bootstrap/lib/stdlib/ebin/unicode.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/unicode_util.beam b/bootstrap/lib/stdlib/ebin/unicode_util.beam
index 7ff215178f..12b9c7312a 100644
--- a/bootstrap/lib/stdlib/ebin/unicode_util.beam
+++ b/bootstrap/lib/stdlib/ebin/unicode_util.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/uri_string.beam b/bootstrap/lib/stdlib/ebin/uri_string.beam
index 36aec511d8..995c1ea5aa 100644
--- a/bootstrap/lib/stdlib/ebin/uri_string.beam
+++ b/bootstrap/lib/stdlib/ebin/uri_string.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/win32reg.beam b/bootstrap/lib/stdlib/ebin/win32reg.beam
index 3194d09463..da98e9bb0e 100644
--- a/bootstrap/lib/stdlib/ebin/win32reg.beam
+++ b/bootstrap/lib/stdlib/ebin/win32reg.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam
index ef7ea86791..d85893bd41 100644
--- a/bootstrap/lib/stdlib/ebin/zip.beam
+++ b/bootstrap/lib/stdlib/ebin/zip.beam
Binary files differ
diff --git a/bootstrap/lib/stdlib/include/assert.hrl b/bootstrap/lib/stdlib/include/assert.hrl
index 2ec89e7d8a..28d25c6589 100644
--- a/bootstrap/lib/stdlib/include/assert.hrl
+++ b/bootstrap/lib/stdlib/include/assert.hrl
@@ -140,7 +140,7 @@
-endif.
%% This is mostly a convenience which gives more detailed reports.
-%% Note: Guard is a guarded pattern, and can not be used for value.
+%% Note: Guard is a guarded pattern, and cannot be used for value.
-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-define(assertMatch(Guard, Expr, Comment), ok).
@@ -289,7 +289,7 @@
end).
-endif.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
-define(assertException(Class, Term, Expr), ok).
@@ -364,7 +364,7 @@
?assertException(throw, Term, Expr, Comment)).
%% This is the inverse case of assertException, for convenience.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Both Class and Term can be guarded patterns.
-ifdef(NOASSERT).
-define(assertNotException(Class, Term, Expr), ok).
diff --git a/configure.src b/configure.src
new file mode 100644
index 0000000000..3849908388
--- /dev/null
+++ b/configure.src
@@ -0,0 +1,435 @@
+#!/bin/sh
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+#
+# This is a handcrafted wrapper script which runs the actual (autoconf)
+# 'configure' scripts in different parts of OTP.
+#
+# The true (autoconf) configure scripts are run in parallel unless
+# --disable-parallel-configure is passed as argument to this script.
+#
+# The config cache feature is disabled since it mostly causes problems
+# and especially when executing multiple configure scripts in parallel.
+# On windows a static cache for each configure is used since it
+# otherwise takes forever to run configure...
+#
+
+OTP_VERSION=@OTP_VERSION@
+
+unset CDPATH
+
+default_cflags="-g -O2"
+
+mXY_build=
+static_cache=
+
+bootstrap_only=no
+parallel_otp_configure=yes
+help=no
+user_srcdir=
+config_arguments=
+while test $# != 0; do
+ case $1 in
+ -srcdir=* | --srcdir=*)
+ user_srcdir=`expr "$1" : '[^=]*=\(.*\)'`
+ if test "$ERL_TOP" != ""; then
+ echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
+ echo "" 1>&2
+ fi
+ ERL_TOP="$user_srcdir"
+ ;;
+ -srcdir | --srcdir)
+ shift
+ test $# != 0 || {
+ echo "ERROR: Missing source dir" 1>&2
+ exit 1
+ }
+ user_srcdir="$1"
+ if test "$ERL_TOP" != ""; then
+ echo "WARNING: Overriding ERL_TOP with $user_srcdir" 1>&2
+ echo "" 1>&2
+ fi
+ ERL_TOP="$user_srcdir"
+ ;;
+ --enable-bootstrap-only)
+ bootstrap_only=yes;;
+ --disable-bootstrap-only)
+ bootstrap_only=no;;
+ --enable-option-checking)
+ echo "ERROR: Cannot enable option checking" 1>&2
+ exit 1;;
+ --disable-option-checking)
+ # Got it...
+ ;;
+ --disable-parallel-configure)
+ parallel_otp_configure=no
+ ;;
+ --config-cache | -C)
+ echo "WARNING: Ignoring config cache file since it will mess up the configuration" 1>&2
+ echo "" 1>&2
+ ;;
+ -cache-file=* | --cache-file=* )
+ static_cache=`expr "$1" : '[^=]*=\(.*\)'`
+ if test "$static_cache" != "/dev/null"; then
+ echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
+ echo "" 1>&2
+ else
+ static_cache=
+ fi
+ ;;
+ -cache-file | --cache-file)
+ shift
+ test $# != 0 || {
+ echo "ERROR: Missing cache file" 1>&2
+ exit 1
+ }
+ static_cache=$1
+ if test "$static_cache" != "/dev/null"; then
+ echo "WARNING: Only using config cache file '$static_cache' as static cache" 1>&2
+ echo "" 1>&2
+ else
+ static_cache=
+ fi
+ ;;
+ --enable-m64-build)
+ mXY_build="-m64"
+ ;;
+ --enable-m32-build)
+ mXY_build="-m32"
+ ;;
+ --disable-m64-build)
+ if test "$mXY_build" = "-m64"; then
+ mXY_build=
+ fi;;
+ --disable-m32-build)
+ if test "$mXY_build" = "-m32"; then
+ mXY_build=
+ fi;;
+ CFLAGS=* | LDFLAGS=*)
+ flgs_var=`expr "$1" : '\([^=]*\)=.*'`
+ flgs_val=`expr "$1" : '[^=]*=\(.*\)'`
+ eval $flgs_var=\$flgs_val
+ ;;
+ --help=r* | -help=r*)
+ help=all;;
+ --help* | -help* | -h)
+ help=$1;;
+ *)
+ case $1 in
+ --without-*)
+ skip_app=`expr "$1" : '--without-\(.*\)'`
+ if test -d "lib/$skip_app"; then
+ echo "$skip_app" >> "$ERL_TOP/lib/SKIP-APPLICATIONS"
+ fi;;
+ *)
+ ;;
+ esac
+ case $1 in
+ *\'*)
+ 1=`echo "$1" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *)
+ ;;
+ esac
+ config_arguments="$config_arguments '$1'";;
+ esac
+ shift
+done
+
+if test $parallel_otp_configure = yes; then
+ case `uname -s` in
+ MSYS* | msys* | CYGWIN* | cygwin )
+ ;;
+ *)
+ trap 'kill -KILL -$$' 1 2 3 6 15
+ ;;
+ esac
+fi
+
+#
+# Figure ERL_TOP out...
+#
+
+root_dir=
+dir_chk_data="$OTP_VERSION"
+
+if root_dir=`dirname "$0" 2>/dev/null` \
+ && test "$root_dir" != "" \
+ && cd "$root_dir" 2>/dev/null; then
+ root_dir=`pwd 2>/dev/null`
+ if test $? -ne 0; then
+ root_dir=
+ else
+ case "$root_dir" in
+ /*)
+ echo $dir_chk_data > "$root_dir"/config.dir.check.$$ 2>/dev/null
+ ;;
+ *)
+ root_dir=
+ esac
+ fi
+else
+ root_dir=
+fi
+
+if test "$root_dir" = ""; then
+ case X"$ERL_TOP" in
+ X)
+ echo "ERROR: Cannot figure out the root directory of" 1>&2
+ echo " the OTP source. Please set the ERL_TOP" 1>&2
+ echo " environment variable." 1>&2
+ exit 1
+ ;;
+ X/*)
+ cd "$ERL_TOP" 2>/dev/null || {
+ echo "ERROR: Cannot change directory to ERL_TOP " 1>&2
+ echo " '$ERL_TOP'" 1>&2
+ exit 1
+ }
+ ;;
+ X*)
+ echo "ERROR: ERL_TOP '$ERL_TOP' is not an absolute path" 1>&2
+ exit 1
+ ;;
+ esac
+else
+ case X"$ERL_TOP" in
+ X)
+ ERL_TOP="$root_dir"
+ rm -f "$root_dir"/config.dir.check.$$
+ ;;
+ X/*)
+ cd "$ERL_TOP" 2>/dev/null || {
+ rm -f "$root_dir"/config.dir.check.$$
+ echo "ERROR: Cannot change directory into ERL_TOP " 1>&2
+ echo " '$ERL_TOP'" 1>&2
+ exit 1
+ }
+ dir_chk=`cat ./config.dir.check.$$ 2>/dev/null` || dir_chk=error
+ rm -f "$root_dir"/config.dir.check.$$
+ test "$dir_chk" = "$dir_chk_data" || {
+ echo "ERROR: ERL_TOP '$ERL_TOP' is not the same" 1>&2
+ echo " as 'configure' location '$root_dir'" 1>&2
+ exit 1
+ }
+ ;;
+ X*)
+ rm -f "$root_dir"/config.dir.check.$$
+ echo "ERROR: ERL_TOP '$ERL_TOP' is not an absolute path" 1>&2
+ exit 1
+ ;;
+ esac
+fi
+
+export ERL_TOP
+
+rm -f "$ERL_TOP/lib/SKIP-APPLICATIONS"
+
+case "$help" in
+ no)
+ ;;
+ all)
+ (cd "$ERL_TOP/make" && ./configure --help)
+ app_dirs=
+ for app_dir in erts lib/*; do
+ if test -f "$app_dir/configure"; then
+ echo ""
+ echo "=== $app_dir ==="
+ (cd "$ERL_TOP/$app_dir" && ./configure --help=short)
+ fi
+ done
+ exit 0;;
+ *)
+ (cd "$ERL_TOP/make" && ./configure "$help")
+ exit 0;;
+esac
+
+if test "$mXY_build" = ""; then
+ if test "$CFLAGS" != ""; then
+ config_arguments="$config_arguments CFLAGS='$CFLAGS'"
+ unset CFLAGS
+ fi
+
+ if test "$LDFLAGS" != ""; then
+ config_arguments="$config_arguments LDFLAGS='$LDFLAGS'"
+ unset LDFLAGS
+ fi
+else
+ if test "$CFLAGS" = ""; then
+ CFLAGS=$default_cflags
+ fi
+ config_arguments="$config_arguments CFLAGS='$mXY_build $CFLAGS'"
+ unset CFLAGS
+ config_arguments="$config_arguments LDFLAGS='$mXY_build $LDFLAGS'"
+ unset LDFLAGS
+ case $mXY_build in
+ -m32)
+ config_arguments="$config_arguments --enable-m32-build"
+ ;;
+ -m64)
+ config_arguments="$config_arguments --enable-m64-build"
+ ;;
+ esac
+fi
+
+config_arguments="$config_arguments --disable-option-checking"
+
+if test $bootstrap_only = no; then
+ check_conf_dirs=`echo lib/*`
+else
+ check_conf_dirs="@BOOTSTRAP_LIB_APP_DIRS@"
+fi
+
+# 'erts' *needs* to be last in app_dirs! Any apps
+# after it wont be able to run in parallel with
+# erts...
+
+app_dirs=
+for app_dir in make $check_conf_dirs erts; do
+ if test -f "$app_dir/configure"; then
+ if test "$static_cache" != ""; then
+ cp -f "$static_cache" "$ERL_TOP/$app_dir/local.static.config.cache"
+ fi
+ rm -f $app_dir/configure.result.failed
+ rm -f $app_dir/configure.result.command
+ rm -f $app_dir/configure.result.stdout
+ rm -f $app_dir/configure.result.stderr
+ app_dirs="$app_dirs $app_dir"
+ fi
+done
+
+if test "$static_cache" = ""; then
+ local_cache_file=/dev/null
+else
+ local_cache_file=./local.static.config.cache
+fi
+
+for app_dir in $app_dirs; do
+ cd "$ERL_TOP/$app_dir"
+ cmd_str="./configure $config_arguments --cache-file=$local_cache_file --srcdir=\"$ERL_TOP/$app_dir\""
+ if test $parallel_otp_configure = no; then
+ echo "=== Running configure in $ERL_TOP/$app_dir ==="
+ eval $cmd_str
+ echo ""
+ elif test $app_dir != erts; then
+ echo $cmd_str >./configure.result.command
+ eval $cmd_str 1>./configure.result.stdout 2>./configure.result.stderr || echo "fatal" > "./configure.result.failed" &
+ else
+ # ERTS configure gets to use stdout/stderr; the others are printed when done...
+ echo "=== Running configure in $ERL_TOP/erts ==="
+ echo $cmd_str
+ eval $cmd_str || {
+ rm -f erts/configure.result.* lib/*/configure.result.*
+ echo "ERROR: $ERL_TOP/$app_dir/configure failed!" 1>&2
+ kill -KILL -$$
+ exit 1
+ }
+ fi
+done
+
+cd "$ERL_TOP"
+
+if test $parallel_otp_configure = yes; then
+ # Wait for all sub-configures to finish...
+ wait
+
+ for app_dir in $app_dirs; do
+ if test -f "$app_dir/configure.result.command"; then
+ echo ""
+ echo "=== Running configure in $ERL_TOP/$app_dir ==="
+ cat "$app_dir/configure.result.command"
+ rm -f "$app_dir/configure.result.command"
+ fi
+ if test -f "$app_dir/configure.result.stdout"; then
+ cat "$app_dir/configure.result.stdout"
+ rm -f "$app_dir/configure.result.stdout"
+ fi
+ if test -f "$app_dir/configure.result.stderr"; then
+ cat "$app_dir/configure.result.stderr" 1>&2
+ rm -f "$app_dir/configure.result.stderr"
+ fi
+ if test -f "$app_dir/configure.result.failed"; then
+ rm -f erts/configure.result.* lib/*/configure.result.*
+ echo "ERROR: $ERL_TOP/$app_dir/configure failed!" 1>&2
+ exit 1
+ fi
+ done
+fi
+
+
+echo ""
+
+pattern="lib/*/SKIP"
+files=`echo $pattern`
+if test "$files" != "$pattern" || test -f "$ERL_TOP/lib/SKIP-APPLICATIONS"; then
+ echo '*********************************************************************'
+ echo '********************** APPLICATIONS DISABLED **********************'
+ echo '*********************************************************************'
+ echo
+ if test "$files" != "$pattern"; then
+ for skipfile in $files; do
+ app=`dirname $skipfile`; app=`basename $app`
+ printf "%-15s: " $app; cat $skipfile
+ done
+ fi
+ if test -f "$ERL_TOP/lib/SKIP-APPLICATIONS"; then
+ for skipapp in `cat "$ERL_TOP/lib/SKIP-APPLICATIONS"`; do
+ printf "%-15s: User gave --without-%s option\n" $skipapp $skipapp
+ done
+ fi
+ echo
+ echo '*********************************************************************'
+fi
+pattern="lib/*/CONF_INFO"
+files=`echo $pattern`
+if test "$files" != "$pattern" || test -f erts/CONF_INFO; then
+ echo '*********************************************************************'
+ echo '********************** APPLICATIONS INFORMATION *******************'
+ echo '*********************************************************************'
+ echo
+ test "$files" != "$pattern" || files=""
+ test ! -f erts/CONF_INFO || files="$files erts/CONF_INFO"
+ for infofile in $files; do
+ app=`dirname $infofile`; app=`basename $app`
+ printf "%-15s: " $app; cat $infofile
+ done
+ echo
+ echo '*********************************************************************'
+fi
+if test -f "erts/doc/CONF_INFO"; then
+ echo '*********************************************************************'
+ echo '********************** DOCUMENTATION INFORMATION ******************'
+ echo '*********************************************************************'
+ echo
+ printf "%-15s: \n" documentation;
+ havexsltproc="yes"
+ for cmd in `cat erts/doc/CONF_INFO`; do
+ echo " $cmd is missing."
+ if test $cmd = "xsltproc"; then
+ havexsltproc="no"
+ fi
+ done
+ if test $havexsltproc = "no"; then
+ echo ' The documentation cannot be built.'
+ else
+ echo ' Using fakefop to generate placeholder PDF files.'
+ fi
+ echo
+ echo '*********************************************************************'
+fi
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 3d227e462c..0ca2755802 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -122,6 +122,9 @@ dnl
AC_DEFUN(LM_WINDOWS_ENVIRONMENT,
[
+
+if test "X$windows_environment_" != "Xchecked"; then
+windows_environment_=checked
MIXED_CYGWIN=no
MIXED_MSYS=no
@@ -197,6 +200,8 @@ else
fi
AC_SUBST(MIXED_MSYS)
+
+fi
])
dnl ----------------------------------------------------------------------
@@ -2856,3 +2861,248 @@ AC_DEFUN([LM_HARDWARE_ARCH], [
AC_SUBST(ARCH)
])
+
+dnl
+dnl--------------------------------------------------------------------
+dnl Dynamic Erlang Drivers
+dnl
+dnl Linking to produce dynamic Erlang drivers to be loaded by Erlang's
+dnl Dynamic Driver Loader and Linker (DDLL). Below the prefix DED is an
+dnl abbreviation for `Dynamic Erlang Driver'.
+dnl
+dnl For DED we need something quite sloppy, which allows undefined references
+dnl (notably driver functions) in the resulting shared library.
+dnl Example of Makefile rule (and settings of macros):
+dnl
+dnl LIBS = @LIBS@
+dnl LD = @DED_LD@
+dnl LDFLAGS = @DED_LDFLAGS@
+dnl soname = @ldsoname@
+dnl
+dnl my_drv.so: my_drv.o my_utils.o
+dnl $(LD) $(LDFLAGS) $(soname) $@ -o $@ $^ -lc $(LIBS)
+dnl
+dnl--------------------------------------------------------------------
+dnl
+
+AC_DEFUN(ERL_DED,
+ [
+
+USER_LD=$LD
+USER_LDFLAGS="$LDFLAGS"
+
+LM_CHECK_THR_LIB
+
+DED_CC=$CC
+DED_GCC=$GCC
+
+DED_CFLAGS=
+DED_OSTYPE=unix
+case $host_os in
+ linux*)
+ DED_CFLAGS="-D_GNU_SOURCE" ;;
+ win32)
+ DED_CFLAGS="-D_WIN32_WINNT=0x0600 -DWINVER=0x0600"
+ DED_OSTYPE=win32 ;;
+ *)
+ ;;
+esac
+
+
+DED_WARN_FLAGS="-Wall -Wstrict-prototypes"
+case "$host_cpu" in
+ tile*)
+ # tile-gcc is a bit stricter with -Wmissing-prototypes than other gccs,
+ # and too strict for our taste.
+ ;;
+ *)
+ DED_WARN_FLAGS="$DED_WARN_FLAGS -Wmissing-prototypes";;
+esac
+
+LM_TRY_ENABLE_CFLAG([-Wdeclaration-after-statement], [DED_WARN_FLAGS])
+
+LM_TRY_ENABLE_CFLAG([-Werror=return-type], [DED_WERRORFLAGS])
+LM_TRY_ENABLE_CFLAG([-Werror=implicit], [DED_WERRORFLAGS])
+LM_TRY_ENABLE_CFLAG([-Werror=undef], [DED_WERRORFLAGS])
+
+DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$DED_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common"
+DED_INCLUDE=$DED_SYS_INCLUDE
+
+if test "$THR_DEFS" = ""; then
+ DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT"
+else
+ DED_THR_DEFS="$THR_DEFS"
+fi
+# DED_EMU_THR_DEFS=$EMU_THR_DEFS
+DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS"
+if test "x$GCC" = xyes; then
+ DED_STATIC_CFLAGS="$DED_CFLAGS"
+ DED_CFLAGS="$DED_CFLAGS -fPIC"
+fi
+
+DED_EXT=so
+case $host_os in
+ win32) DED_EXT=dll;;
+ darwin*)
+ DED_CFLAGS="$DED_CFLAGS -fno-common"
+ DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -fno-common";;
+ *)
+ ;;
+esac
+
+DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER"
+
+if test "$CFLAG_RUNTIME_LIBRARY_PATH" = ""; then
+
+ CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-R"
+ case $host_os in
+ darwin*)
+ CFLAG_RUNTIME_LIBRARY_PATH=
+ ;;
+ win32)
+ CFLAG_RUNTIME_LIBRARY_PATH=
+ ;;
+ osf*)
+ CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-rpath,"
+ ;;
+ *)
+ ;;
+ esac
+
+fi
+
+# If DED_LD is set in environment, we expect all DED_LD* variables
+# to be specified (cross compiling)
+if test "x$DED_LD" = "x"; then
+
+DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-R"
+case $host_os in
+ win32)
+ DED_LD="ld.sh"
+ DED_LDFLAGS="-dll"
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH=
+ ;;
+ solaris2*|sysv4*)
+ DED_LDFLAGS="-G"
+ if test X${enable_m64_build} = Xyes; then
+ DED_LDFLAGS="-64 $DED_LDFLAGS"
+ fi
+ ;;
+ aix4*)
+ DED_LDFLAGS="-G -bnoentry -bexpall"
+ ;;
+ freebsd2*)
+ # Non-ELF GNU linker
+ DED_LDFLAGS="-Bshareable"
+ ;;
+ darwin*)
+ # Mach-O linker: a shared lib and a loadable
+ # object file is not the same thing.
+ DED_LDFLAGS="-bundle -bundle_loader ${ERL_TOP}/bin/$host/beam.smp"
+ if test X${enable_m64_build} = Xyes; then
+ DED_LDFLAGS="-m64 $DED_LDFLAGS"
+ else
+ if test X${enable_m32_build} = Xyes; then
+ DED_LDFLAGS="-m32 $DED_LDFLAGS"
+ else
+ AC_CHECK_SIZEOF(void *)
+ case "$ac_cv_sizeof_void_p" in
+ 8)
+ DED_LDFLAGS="-m64 $DED_LDFLAGS";;
+ *)
+ ;;
+ esac
+ fi
+ fi
+ DED_LD="$CC"
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
+ ;;
+ linux*)
+ DED_LD="$CC"
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
+ DED_LDFLAGS="-shared -Wl,-Bsymbolic"
+ if test X${enable_m64_build} = Xyes; then
+ DED_LDFLAGS="-m64 $DED_LDFLAGS"
+ fi;
+ if test X${enable_m32_build} = Xyes; then
+ DED_LDFLAGS="-m32 $DED_LDFLAGS"
+ fi
+ ;;
+ freebsd*)
+ DED_LD="$CC"
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
+ DED_LDFLAGS="-shared"
+ if test X${enable_m64_build} = Xyes; then
+ DED_LDFLAGS="-m64 $DED_LDFLAGS"
+ fi;
+ if test X${enable_m32_build} = Xyes; then
+ DED_LDFLAGS="-m32 $DED_LDFLAGS"
+ fi
+ ;;
+ openbsd*)
+ DED_LD="$CC"
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
+ DED_LDFLAGS="-shared"
+ ;;
+ osf*)
+ # NOTE! Whitespace after -rpath is important.
+ DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath "
+ DED_LDFLAGS="-shared -expect_unresolved '*'"
+ ;;
+ *)
+ # assume GNU linker and ELF
+ DED_LDFLAGS="-shared"
+ # GNU linker has no option for 64bit build, should not propagate -m64
+ ;;
+esac
+
+if test "$DED_LD" = "" && test "$USER_LD" != ""; then
+ DED_LD="$USER_LD"
+ DED_LDFLAGS="$USER_LDFLAGS $DED_LDFLAGS"
+fi
+
+DED_LIBS=$LIBS
+
+fi # "x$DED_LD" = "x"
+
+AC_CHECK_TOOL(DED_LD, ld, false)
+test "$DED_LD" != "false" || AC_MSG_ERROR([No linker found])
+
+AC_MSG_CHECKING(for static compiler flags)
+DED_STATIC_CFLAGS="$DED_WERRORFLAGS $DED_WFLAGS $DED_THR_DEFS $DED_STATIC_CFLAGS"
+AC_MSG_RESULT([$DED_STATIC_CFLAGS])
+AC_MSG_CHECKING(for basic compiler flags for loadable drivers)
+DED_BASIC_CFLAGS=$DED_CFLAGS
+AC_MSG_RESULT([$DED_CFLAGS])
+AC_MSG_CHECKING(for compiler flags for loadable drivers)
+DED_CFLAGS="$DED_WERRORFLAGS $DED_WARN_FLAGS $DED_THR_DEFS $DED_CFLAGS"
+AC_MSG_RESULT([$DED_CFLAGS])
+AC_MSG_CHECKING(for linker for loadable drivers)
+AC_MSG_RESULT([$DED_LD])
+AC_MSG_CHECKING(for linker flags for loadable drivers)
+AC_MSG_RESULT([$DED_LDFLAGS])
+AC_MSG_CHECKING(for 'runtime library path' linker flag)
+if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then
+ AC_MSG_RESULT([$DED_LD_FLAG_RUNTIME_LIBRARY_PATH])
+else
+ AC_MSG_RESULT([not found])
+fi
+
+AC_SUBST(DED_CC)
+AC_SUBST(DED_GCC)
+AC_SUBST(DED_EXT)
+AC_SUBST(DED_SYS_INCLUDE)
+AC_SUBST(DED_INCLUDE)
+AC_SUBST(DED_BASIC_CFLAGS)
+AC_SUBST(DED_CFLAGS)
+AC_SUBST(DED_STATIC_CFLAGS)
+AC_SUBST(DED_WARN_FLAGS)
+AC_SUBST(DED_WERRORFLAGS)
+AC_SUBST(DED_LD)
+AC_SUBST(DED_LDFLAGS)
+AC_SUBST(DED_LD_FLAG_RUNTIME_LIBRARY_PATH)
+AC_SUBST(DED_LIBS)
+AC_SUBST(DED_THR_DEFS)
+AC_SUBST(DED_OSTYPE)
+
+])
diff --git a/erts/autoconf/vxworks/sed.general b/erts/autoconf/vxworks/sed.general
index a30eb51169..0e99b4dba4 100644
--- a/erts/autoconf/vxworks/sed.general
+++ b/erts/autoconf/vxworks/sed.general
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_cpu32 b/erts/autoconf/vxworks/sed.vxworks_cpu32
index 961adc4104..26e4f4c7ad 100644
--- a/erts/autoconf/vxworks/sed.vxworks_cpu32
+++ b/erts/autoconf/vxworks/sed.vxworks_cpu32
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc32 b/erts/autoconf/vxworks/sed.vxworks_ppc32
index 1e2e760abc..44697aadc2 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc32
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc32
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2016. All Rights Reserved.
+# Copyright Ericsson AB 2006-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603 b/erts/autoconf/vxworks/sed.vxworks_ppc603
index 5beaae4fc9..4fdfd51273 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2016. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
index 2c2f2fa372..d86876e90e 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc603_nolongcall
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_ppc860 b/erts/autoconf/vxworks/sed.vxworks_ppc860
index 71cf887476..a5c4c2d5c3 100644
--- a/erts/autoconf/vxworks/sed.vxworks_ppc860
+++ b/erts/autoconf/vxworks/sed.vxworks_ppc860
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_simlinux b/erts/autoconf/vxworks/sed.vxworks_simlinux
index 06b1847602..1a2bbd6236 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simlinux
+++ b/erts/autoconf/vxworks/sed.vxworks_simlinux
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2016. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_simso b/erts/autoconf/vxworks/sed.vxworks_simso
index 07606cad80..8d15e87a1b 100644
--- a/erts/autoconf/vxworks/sed.vxworks_simso
+++ b/erts/autoconf/vxworks/sed.vxworks_simso
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2016. All Rights Reserved.
+# Copyright Ericsson AB 2005-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/autoconf/vxworks/sed.vxworks_sparc b/erts/autoconf/vxworks/sed.vxworks_sparc
index 59431fddf9..118b01d16d 100644
--- a/erts/autoconf/vxworks/sed.vxworks_sparc
+++ b/erts/autoconf/vxworks/sed.vxworks_sparc
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/erts/configure.in b/erts/configure.in
index 2b3d97cfdd..d211b81878 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -26,11 +26,6 @@ AC_PREREQ(2.59)
LM_PRECIOUS_VARS
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
dnl How to set srcdir absolute is taken from the GNU Emacs distribution
#### Make srcdir absolute, if it isn't already. It's important to
#### avoid running the path through pwd unnecessary, since pwd can
@@ -420,7 +415,10 @@ dnl
dnl Make sure we find config.h
dnl
-extra_flags="-I${ERL_TOP}/erts/$host $OTP_EXTRA_FLAGS"
+ERTS_CONFIG_H_IDIR="-I${ERL_TOP}/erts/$host"
+AC_SUBST(ERTS_CONFIG_H_IDIR)
+
+extra_flags="$ERTS_CONFIG_H_IDIR $OTP_EXTRA_FLAGS"
CFLAGS="$CFLAGS $extra_flags"
DEBUG_CFLAGS="-g $CPPFLAGS $extra_flags $DEBUG_CFLAGS"
DEBUG_FLAGS=-g
@@ -452,23 +450,6 @@ case $CFLAGS in
;;
esac
-
-
-CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-R"
-case $host_os in
- darwin*)
- CFLAG_RUNTIME_LIBRARY_PATH=
- ;;
- win32)
- CFLAG_RUNTIME_LIBRARY_PATH=
- ;;
- osf*)
- CFLAG_RUNTIME_LIBRARY_PATH="-Wl,-rpath,"
- ;;
- *)
- ;;
-esac
-
lfs_conf=ok
lfs_source=none
if test "${LFS_CFLAGS+set}" = "set" || \
@@ -544,7 +525,6 @@ AC_SUBST(DEBUG_FLAGS)
AC_SUBST(DEBUG_CFLAGS)
AC_SUBST(WFLAGS)
AC_SUBST(WERRORFLAGS)
-AC_SUBST(CFLAG_RUNTIME_LIBRARY_PATH)
## Check if we can do profile guided optimization of beam_emu
LM_CHECK_ENABLE_CFLAG([-fprofile-generate -Werror],[PROFILE_GENERATE])
@@ -581,7 +561,8 @@ if test "X$PROFILE_INSTR_GENERATE" = "Xtrue"; then
PROFILE_INSTR_USE=false])
rm -f default.profdata
fi],
- [])
+ [],
+ [AC_MSG_NOTICE([Disabling PGO when cross-compiling])])
rm -f *.profraw
CFLAGS=$saved_CFLAGS;
fi
@@ -602,7 +583,7 @@ AC_MSG_CHECKING([whether to do PGO of erts])
if test $enable_pgo = no; then
AC_MSG_RESULT([no, disabled by user])
elif test $CROSS_COMPILING = yes; then
- if $enable_pgo = yes; then
+ if test $enable_pgo = yes; then
AC_MSG_ERROR(cannot use PGO when cross-compiling)
else
AC_MSG_RESULT([no, cross compiling])
@@ -887,9 +868,6 @@ esac
AC_SUBST(LD)
-LDFLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
-AC_SUBST(LDFLAG_RUNTIME_LIBRARY_PATH)
-
dnl Check for cygwin and object/exe files extension
dnl AC_CYGWIN is deprecated
AC_EXEEXT
@@ -2948,165 +2926,6 @@ dnl ----------------------------------------------------------------------
dnl Stuff that should be moved into their respective application
dnl ----------------------------------------------------------------------
-dnl crypto
-#--------------------------------------------------------------------
-# Dynamic Erlang Drivers
-#
-# Linking to produce dynamic Erlang drivers to be loaded by Erlang's
-# Dynamic Driver Loader and Linker (DDLL). Below the prefix DED is an
-# abbreviation for `Dynamic Erlang Driver'.
-#
-# For DED we need something quite sloppy, which allows undefined references
-# (notably driver functions) in the resulting shared library.
-# Example of Makefile rule (and settings of macros):
-#
-# LIBS = @LIBS@
-# LD = @DED_LD@
-# LDFLAGS = @DED_LDFLAGS@
-# soname = @ldsoname@
-#
-# my_drv.so: my_drv.o my_utils.o
-# $(LD) $(LDFLAGS) $(soname) $@ -o $@ $^ -lc $(LIBS)
-#
-#--------------------------------------------------------------------
-
-DED_SYS_INCLUDE="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$ERLANG_OSTYPE -I${ERL_TOP}/erts/emulator/sys/common"
-
-if test "X$ETHR_DEFS" = "X"; then
- DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT"
-else
- DED_THR_DEFS="$ETHR_DEFS"
-fi
-DED_EMU_THR_DEFS=$EMU_THR_DEFS
-DED_CFLAGS="$CFLAGS $CPPFLAGS"
-if test "x$GCC" = xyes; then
- DED_STATIC_CFLAGS="$DED_CFLAGS"
- DED_CFLAGS="$DED_CFLAGS -fPIC"
-fi
-
-DED_EXT=so
-case $host_os in
- win32) DED_EXT=dll;;
- darwin*)
- DED_CFLAGS="$DED_CFLAGS -fno-common"
- DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -fno-common";;
- *)
- ;;
-esac
-
-DED_STATIC_CFLAGS="$DED_STATIC_CFLAGS -DSTATIC_ERLANG_NIF -DSTATIC_ERLANG_DRIVER"
-
-# If DED_LD is set in environment, we expect all DED_LD* variables
-# to be specified (cross compiling)
-if test "x$DED_LD" = "x"; then
-
-DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-R"
-case $host_os in
- win32)
- DED_LD="ld.sh"
- DED_LDFLAGS="-dll"
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH=
- ;;
- solaris2*|sysv4*)
- DED_LDFLAGS="-G"
- if test X${enable_m64_build} = Xyes; then
- DED_LDFLAGS="-64 $DED_LDFLAGS"
- fi
- ;;
- aix4*)
- DED_LDFLAGS="-G -bnoentry -bexpall"
- ;;
- freebsd2*)
- # Non-ELF GNU linker
- DED_LDFLAGS="-Bshareable"
- ;;
- darwin*)
- # Mach-O linker: a shared lib and a loadable
- # object file is not the same thing.
- DED_LDFLAGS="-bundle -bundle_loader ${ERL_TOP}/bin/$host/beam.smp"
- case $ARCH in
- amd64)
- DED_LDFLAGS="-m64 $DED_LDFLAGS"
- ;;
- *)
- ;;
- esac
- DED_LD="$CC"
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
- ;;
- linux*)
- DED_LD="$CC"
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
- DED_LDFLAGS="-shared -Wl,-Bsymbolic"
- if test X${enable_m64_build} = Xyes; then
- DED_LDFLAGS="-m64 $DED_LDFLAGS"
- fi;
- if test X${enable_m32_build} = Xyes; then
- DED_LDFLAGS="-m32 $DED_LDFLAGS"
- fi
- ;;
- freebsd*)
- DED_LD="$CC"
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
- DED_LDFLAGS="-shared"
- if test X${enable_m64_build} = Xyes; then
- DED_LDFLAGS="-m64 $DED_LDFLAGS"
- fi;
- if test X${enable_m32_build} = Xyes; then
- DED_LDFLAGS="-m32 $DED_LDFLAGS"
- fi
- ;;
- openbsd*)
- DED_LD="$CC"
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH"
- DED_LDFLAGS="-shared"
- ;;
- osf*)
- # NOTE! Whitespace after -rpath is important.
- DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath "
- DED_LDFLAGS="-shared -expect_unresolved '*'"
- ;;
- *)
- # assume GNU linker and ELF
- DED_LDFLAGS="-shared"
- # GNU linker has no option for 64bit build, should not propagate -m64
- ;;
-esac
-
-if test "$DED_LD" = "" && test "$USER_LD" != ""; then
- DED_LD="$USER_LD"
- DED_LDFLAGS="$USER_LDFLAGS $DED_LDFLAGS"
-fi
-
-fi # "x$DED_LD" = "x"
-
-AC_CHECK_TOOL(DED_LD, ld, false)
-test "$DED_LD" != "false" || AC_MSG_ERROR([No linker found])
-
-AC_MSG_CHECKING(for compiler flags for loadable drivers)
-AC_MSG_RESULT([$DED_CFLAGS])
-AC_MSG_CHECKING(for linker for loadable drivers)
-AC_MSG_RESULT([$DED_LD])
-AC_MSG_CHECKING(for linker flags for loadable drivers)
-AC_MSG_RESULT([$DED_LDFLAGS])
-AC_MSG_CHECKING(for 'runtime library path' linker flag)
-if test "x$DED_LD_FLAG_RUNTIME_LIBRARY_PATH" != "x"; then
- AC_MSG_RESULT([$DED_LD_FLAG_RUNTIME_LIBRARY_PATH])
-else
- AC_MSG_RESULT([not found])
-fi
-
-AC_SUBST(DED_EXT)
-AC_SUBST(DED_SYS_INCLUDE)
-AC_SUBST(DED_CFLAGS)
-AC_SUBST(DED_STATIC_CFLAGS)
-AC_SUBST(DED_LD)
-AC_SUBST(DED_LDFLAGS)
-AC_SUBST(DED_LD_FLAG_RUNTIME_LIBRARY_PATH)
-AC_SUBST(DED_THR_DEFS)
-AC_SUBST(DED_EMU_THR_DEFS)
-AC_SUBST(STATIC_CFLAGS)
-
dnl
dnl We should look for a compiler that handles jump tables, for beam_emu
dnl to be optimized
@@ -3259,733 +3078,6 @@ if test "$enable_lttng_test" = "yes" ; then
fi
-dnl
-dnl SSL, SSH and CRYPTO need the OpenSSL libraries
-dnl
-dnl Check flags --with-ssl, --without-ssl --with-ssl=PATH.
-dnl If no option is given or --with-ssl is set without a path then we
-dnl search for OpenSSL libraries and header files in the standard locations.
-dnl If set to --without-ssl we disable the use of SSL, SSH and CRYPTO.
-dnl If set to --with-ssl=PATH we use that path as the prefix, i.e. we
-dnl use "PATH/include" and "PATH/lib".
-
-AC_SUBST(SSL_INCLUDE)
-AC_SUBST(SSL_INCDIR)
-AC_SUBST(SSL_LIBDIR)
-AC_SUBST(SSL_FLAGS)
-AC_SUBST(SSL_CRYPTO_LIBNAME)
-AC_SUBST(SSL_SSL_LIBNAME)
-AC_SUBST(SSL_CC_RUNTIME_LIBRARY_PATH)
-AC_SUBST(SSL_LD_RUNTIME_LIBRARY_PATH)
-AC_SUBST(SSL_DED_LD_RUNTIME_LIBRARY_PATH)
-AC_SUBST(SSL_DYNAMIC_ONLY)
-AC_SUBST(SSL_LINK_WITH_KERBEROS)
-AC_SUBST(STATIC_KERBEROS_LIBS)
-AC_SUBST(SSL_LINK_WITH_ZLIB)
-AC_SUBST(STATIC_ZLIB_LIBS)
-
-std_ssl_locations="/usr/local /usr/sfw /usr /opt/local /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl /"
-
-AC_ARG_WITH(ssl-zlib,
-AS_HELP_STRING([--with-ssl-zlib=PATH],
- [specify location of ZLib to be used by OpenSSL])
-AS_HELP_STRING([--with-ssl-zlib],
- [link SSL with Zlib (default if found)])
-AS_HELP_STRING([--without-ssl-zlib],
- [don't link SSL with ZLib]))
-
-
-if test "x$with_ssl_zlib" = "xno"; then
- SSL_LINK_WITH_ZLIB=no
- STATIC_ZLIB_LIBS=
-elif test "x$with_ssl_zlib" = "xyes" || test "x$with_ssl_zlib" = "x"; then
- if test $erl_xcomp_without_sysroot = yes; then
- AC_MSG_WARN([Cannot search for zlib; missing cross system root (erl_xcomp_sysroot).])
- SSL_LINK_WITH_ZLIB=no
- STATIC_ZLIB_LIBS=
- elif test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
- SSL_LINK_WITH_ZLIB=no
- STATIC_ZLIB_LIBS=
- else
- SSL_LINK_WITH_ZLIB=no
- STATIC_ZLIB_LIBS=
- AC_MSG_CHECKING(for static ZLib to be used by SSL in standard locations)
- for rdir in $std_ssl_locations; do
- dir="$erl_xcomp_sysroot$rdir"
- if test "x$ac_cv_sizeof_void_p" = "x8"; then
- if test -f "$dir/lib64/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS="$dir/lib64/libz.a"
- break
- elif test -f "$dir/lib/64/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS="$dir/lib/64/libz.a"
- break
- fi
- fi
- if test -f "$dir/lib/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS="$dir/lib/libz.a"
- break
- fi
- done
- if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
- AC_MSG_RESULT([no])
- else
- AC_MSG_RESULT([$STATIC_ZLIB_LIBS])
- fi
- fi
-else
- SSL_LINK_WITH_ZLIB=no
- STATIC_ZLIB_LIBS=
- if test -f "$with_ssl_zlib/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS=$with_ssl_zlib/libz.a
- elif test -f "$with_ssl_zlib/lib/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/libz.a
- fi
- if test "x$ac_cv_sizeof_void_p" = "x8"; then
- if test -f "$with_ssl_zlib/lib64/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS=$with_ssl_zlib/lib64/libz.a
- elif test -f "$with_ssl_zlib/lib/64/libz.a"; then
- SSL_LINK_WITH_ZLIB=yes
- STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/64/libz.a
- fi
- fi
- if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
- AC_MSG_ERROR(Invalid path to option --with-ssl-zlib=PATH)
- fi
-fi
-
-
-AC_ARG_WITH(ssl,
-AS_HELP_STRING([--with-ssl=PATH], [specify location of OpenSSL include and lib])
-AS_HELP_STRING([--with-ssl], [use SSL (default)])
-AS_HELP_STRING([--without-ssl], [don't use SSL]))
-
-AC_ARG_WITH(ssl-incl,
-AS_HELP_STRING([--with-ssl-incl=PATH], [location of OpenSSL include dir, if different than specified by --with-ssl=PATH]),
-[
-case X$with_ssl in
- X | Xyes | Xno) AC_MSG_ERROR([--with-ssl-incl=PATH set without --with-ssl=PATH]);;
-esac
-],
-[with_ssl_incl=$with_ssl]) #default
-
-AC_ARG_WITH(ssl-rpath,
-AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS],
- [runtime library path for OpenSSL. Default is "yes", which equates to a
- number of standard locations. If "no", then no runtime
- library paths will be used. Anything else should be a
- comma separated list of paths.]),
-[
-case X$with_ssl in
- Xno) AC_MSG_ERROR([--with-ssl-rpath set without --with-ssl]);;
-esac
-],
-[with_ssl_rpath=yes]) #default
-
-
-AC_ARG_ENABLE(dynamic-ssl-lib,
-AS_HELP_STRING([--disable-dynamic-ssl-lib],
- [disable using dynamic openssl libraries]),
-[ case "$enableval" in
- no) enable_dynamic_ssl=no ;;
- *) enable_dynamic_ssl=yes ;;
- esac ], enable_dynamic_ssl=yes)
-
-#----------------------------------------------------------------------
-# We actually might do the SSL tests twice due to late discovery of
-# kerberos problems with static linking, in case we redo it all trying
-# dynamic SSL libraries instead.
-#----------------------------------------------------------------------
-
-ssl_done=no
-
-while test "x$ssl_done" != "xyes"; do
-
-ssl_done=yes # Default only one run
-
-# Remove all SKIP files from previous runs
-for a in ssl crypto ssh; do
- $RM -f $ERL_TOP/lib/$a/SKIP
-done
-
-SSL_DYNAMIC_ONLY=$enable_dynamic_ssl
-SSL_STATIC_ONLY=no
-
-case "$erl_xcomp_without_sysroot-$with_ssl" in
- yes-* | no-no)
- SSL_APP=
- CRYPTO_APP=
- SSH_APP=
- if test "$with_ssl" = "no"; then
- skip="User gave --without-ssl option"
- else
- skip="Cannot search for ssl; missing cross system root (erl_xcomp_sysroot)."
- fi
- for a in ssl crypto ssh; do
- echo "$skip" > $ERL_TOP/lib/$a/SKIP
- done
- ;;
- no-yes | no- )
- # On windows, we could try to find the installation
- # of Shining Light OpenSSL, which can be found by poking in
- # the uninstall section in the registry, it's worth a try...
- extra_dir=""
- if test "x$MIXED_CYGWIN" = "xyes"; then
- AC_CHECK_PROG(REGTOOL, regtool, regtool, false)
- if test "$ac_cv_prog_REGTOOL" != false; then
- wrp="/machine/software/microsoft/windows/currentversion/"
- if test "x$ARCH" = "xamd64"; then
- urp="uninstall/openssl (64-bit)_is1/inno setup: app path"
- regtool_subsystem=-w
- else
- urp="uninstall/openssl (32-bit)_is1/inno setup: app path"
- regtool_subsystem=-W
- fi
- rp="$wrp$urp"
- if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
- true
- else
- # Fallback to unspecified wordlength
- urp="uninstall/openssl_is1/inno setup: app path"
- rp="$wrp$urp"
- fi
- if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
- ssl_install_dir=`regtool -q $regtool_subsystem get "$rp"`
- # Try hard to get rid of spaces...
- if cygpath -d "$ssl_install_dir" > /dev/null 2>&1; then
- ssl_install_dir=`cygpath -d "$ssl_install_dir"`
- fi
- extra_dir=`cygpath $ssl_install_dir`
- fi
- fi
- elif test "x$MIXED_MSYS" = "xyes"; then
- AC_CHECK_PROG(REGTOOL, reg_query.sh, reg_query.sh, false)
- if test "$ac_cv_prog_REGTOOL" != false; then
- if test "x$ARCH" = "xamd64"; then
- rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL (64-bit)_is1"
- else
- rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL_is1"
- fi
- key="Inno Setup: App Path"
- if "$ac_cv_prog_REGTOOL" "$rp" "$key" > /dev/null; then
- ssl_install_dir=`"$ac_cv_prog_REGTOOL" "$rp" "$key"`
- extra_dir=`win2msys_path.sh "$ssl_install_dir"`
- fi
- fi
- fi
- # We search for OpenSSL in the common OS standard locations.
- SSL_APP=ssl
- CRYPTO_APP=crypto
- SSH_APP=ssh
-
- SSL_CRYPTO_LIBNAME=crypto
- SSL_SSL_LIBNAME=ssl
-
- if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
- if test "x$ARCH" = "xamd64"; then
- std_win_ssl_locations="/cygdrive/c/OpenSSL-Win64 /c/OpenSSL-Win64 /opt/local64/pgm/OpenSSL"
- else
- std_win_ssl_locations="/cygdrive/c/OpenSSL-Win32 /c/OpenSSL-Win32 /cygdrive/c/OpenSSL /c/OpenSSL /opt/local/pgm/OpenSSL"
- fi
- else
- std_win_ssl_locations=""
- fi
-
-
- AC_MSG_CHECKING(for OpenSSL >= 0.9.8c in standard locations)
- for rdir in $extra_dir $std_win_ssl_locations $std_ssl_locations; do
- dir="$erl_xcomp_sysroot$rdir"
- if test -f "$erl_xcomp_isysroot$rdir/include/openssl/opensslv.h"; then
- is_real_ssl=yes
- SSL_INCDIR="$dir"
- if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
- if test -f "$dir/lib/VC/libeay32.lib"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
- SSL_LIBDIR="$dir/lib/VC"
- SSL_CRYPTO_LIBNAME=libeay32
- SSL_SSL_LIBNAME=ssleay32
- elif test -f "$dir/lib/VC/openssl.lib"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
- SSL_LIBDIR="$dir/lib/VC"
- elif test -f $dir/lib/VC/libeay32MD.lib; then
- SSL_CRYPTO_LIBNAME=libeay32MD
- SSL_SSL_LIBNAME=ssleay32MD
- if test "x$enable_dynamic_ssl" = "xno" && \
- test -f $dir/lib/VC/static/libeay32MD.lib; then
- SSL_RUNTIME_LIBDIR="$rdir/lib/VC/static"
- SSL_LIBDIR="$dir/lib/VC/static"
- else
- SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
- SSL_LIBDIR="$dir/lib/VC"
- fi
- elif test -f "$dir/lib/libeay32.lib"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib"
- SSL_LIBDIR="$dir/lib"
- SSL_CRYPTO_LIBNAME=libeay32
- SSL_SSL_LIBNAME=ssleay32
- elif test -f "$dir/lib/openssl.lib"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib"
- SSL_LIBDIR="$dir/lib"
- else
- is_real_ssl=no
- fi
- elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
- SSL_CRYPTO_LIBNAME=sslcrypto
- SSL_LIBDIR="$dir/lib/powerpc/"
- SSL_RUNTIME_LIBDIR="$rdir/lib/powerpc/"
- else
- if test "x$ac_cv_sizeof_void_p" = "x8"; then
- if test -f "$dir/lib64/libcrypto.a"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib64"
- SSL_LIBDIR="$dir/lib64"
- elif test -f "$dir/lib/64/libcrypto.a"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib/64"
- SSL_LIBDIR="$dir/lib/64"
- elif test -f "$dir/lib64/libcrypto.so"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib64"
- SSL_LIBDIR="$dir/lib64"
- elif test -f "$dir/lib/64/libcrypto.so"; then
- SSL_RUNTIME_LIBDIR="$rdir/lib/64"
- SSL_LIBDIR="$dir/lib/64"
- else
- SSL_RUNTIME_LIBDIR="$rdir/lib"
- SSL_LIBDIR="$dir/lib"
- fi
- else
- SSL_RUNTIME_LIBDIR="$rdir/lib"
- SSL_LIBDIR="$dir/lib"
- fi
- fi
- if test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.a"; then
- SSL_DYNAMIC_ONLY=yes
- elif test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.so" -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
- SSL_STATIC_ONLY=yes
- fi
- SSL_BINDIR="$rdir/bin"
- if test "x$is_real_ssl" = "xyes" ; then
- SSL_INCLUDE="-I$dir/include"
- old_CPPFLAGS=$CPPFLAGS
- CPPFLAGS=$SSL_INCLUDE
- AC_EGREP_CPP(^yes$,[
-#include <openssl/opensslv.h>
-#if OPENSSL_VERSION_NUMBER >= 0x0090803fL
-yes
-#endif
- ],[
- ssl_found=yes
- ],[
- SSL_APP=
- ssl_found=no
- ])
- CPPFLAGS=$old_CPPFLAGS
- if test "x$ssl_found" = "xyes"; then
- if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
- ssl_linkable=yes
- elif test "x${SSL_CRYPTO_LIBNAME}" = "xsslcrypto"; then
- # This should only be triggered seen OSE
- ssl_linkable=yes
- else
- saveCFLAGS="$CFLAGS"
- saveLDFLAGS="$LDFLAGS"
- saveLIBS="$LIBS"
- CFLAGS="$CFLAGS $SSL_INCLUDE"
- if test "x$SSL_STATIC_ONLY" = "xyes"; then
- LIBS="${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"
- else
- LDFLAGS="$LDFLAGS -L$SSL_LIBDIR"
- LIBS="$LIBS -l${SSL_CRYPTO_LIBNAME}"
- fi
- AC_TRY_LINK([
- #include <stdio.h>
- #include <openssl/hmac.h>],
- [
- HMAC(0, 0, 0, 0, 0, 0, 0);
- ],
- [ssl_linkable=yes],
- [ssl_linkable=no])
- CFLAGS="$saveCFLAGS"
- LDFLAGS="$saveLDFLAGS"
- LIBS="$saveLIBS"
- fi
- fi
- if test "x$ssl_found" = "xyes" && test "x$ssl_linkable" = "xyes"; then
- AC_MSG_RESULT([$dir])
- break;
- fi
- fi
- fi
- done
-
- if test "x$ssl_found" != "xyes" ; then
- dnl
- dnl If no SSL found above, check whether we are running on OpenBSD.
- dnl
- case $host_os in
- openbsd*)
- if test -f "$erl_xcomp_isysroot/usr/include/openssl/opensslv.h"; then
- # Trust OpenBSD to have everything the in the correct locations.
- ssl_found=yes
- ssl_linkable=yes
- SSL_INCDIR="$erl_xcomp_sysroot/usr"
- AC_MSG_RESULT([$SSL_INCDIR])
- SSL_RUNTIME_LIB="/usr/lib"
- SSL_LIB="$erl_xcomp_sysroot/usr/lib"
- SSL_BINDIR="/usr/sbin"
- dnl OpenBSD requires us to link with -L and -l
- SSL_DYNAMIC_ONLY="yes"
- fi
- ;;
- esac
- fi
-dnl Now, certain linuxes have a 64bit libcrypto
-dnl that cannot build shared libraries (i.e. not PIC)
-dnl One could argue that this is wrong, but
-dnl so it is - be adoptable
- if test "$ssl_found" = "yes" && test "$ssl_linkable" = "yes" && test "$SSL_DYNAMIC_ONLY" != "yes"; then
- case $host_os in
- linux*)
- saveCFLAGS="$CFLAGS"
- saveLDFLAGS="$LDFLAGS"
- saveLIBS="$LIBS"
- CFLAGS="$DED_CFLAGS $SSL_INCLUDE"
- LDFLAGS="$DED_LDFLAGS"
- LIBS="$SSL_LIBDIR/libcrypto.a $STATIC_ZLIB_LIBS"
- AC_TRY_LINK([
- #include <stdio.h>
- #include <openssl/hmac.h>],
- [
- HMAC(0, 0, 0, 0, 0, 0, 0);
- ],
- [ssl_dyn_linkable=yes],
- [ssl_dyn_linkable=no])
- CFLAGS="$saveCFLAGS"
- LDFLAGS="$saveLDFLAGS"
- LIBS="$saveLIBS"
- if test "x$ssl_dyn_linkable" != "xyes"; then
- SSL_DYNAMIC_ONLY=yes
- AC_MSG_WARN([SSL will be linked against dynamic lib as static lib is not purely relocatable])
- fi
- ;;
- esac
- fi
-
-
-
-
- if test "x$ssl_found" != "xyes" || test "x$ssl_linkable" != "xyes"; then
- if test "x$ssl_found" = "xyes"; then
- AC_MSG_RESULT([found; but not usable])
- else
- AC_MSG_RESULT([no])
- fi
- SSL_APP=
- CRYPTO_APP=
- SSH_APP=
- AC_MSG_WARN([No (usable) OpenSSL found, skipping ssl, ssh and crypto applications])
-
- for a in ssl crypto ssh; do
- echo "No usable OpenSSL found" > $ERL_TOP/lib/$a/SKIP
- done
- fi
- ;;
- *)
- # Option given with PATH to package
- if test ! -d "$with_ssl" ; then
- AC_MSG_ERROR(Invalid path to option --with-ssl=PATH)
- fi
- if test ! -d "$with_ssl_incl" ; then
- AC_MSG_ERROR(Invalid path to option --with-ssl-incl=PATH)
- fi
- SSL_INCDIR="$with_ssl_incl"
- SSL_CRYPTO_LIBNAME=crypto
- SSL_SSL_LIBNAME=ssl
- if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes" && test -d "$with_ssl/lib/VC"; then
- if test -f "$with_ssl/lib/VC/libeay32.lib"; then
- SSL_LIBDIR="$with_ssl/lib/VC"
- SSL_CRYPTO_LIBNAME=libeay32
- SSL_SSL_LIBNAME=ssleay32
- elif test -f "$with_ssl/lib/VC/openssl.lib"; then
- SSL_LIBDIR="$with_ssl/lib/VC"
- elif test -f $with_ssl/lib/VC/libeay32MD.lib; then
- SSL_CRYPTO_LIBNAME=libeay32MD
- SSL_SSL_LIBNAME=ssleay32MD
- if test "x$enable_dynamic_ssl" = "xno" && \
- test -f $with_ssl/lib/VC/static/libeay32MD.lib; then
- SSL_LIBDIR="$with_ssl/lib/VC/static"
- else
- SSL_LIBDIR="$with_ssl/lib/VC"
- fi
- elif test -f "$with_ssl/lib/libeay32.lib"; then
- SSL_LIBDIR="$with_ssl/lib"
- SSL_CRYPTO_LIBNAME=libeay32
- SSL_SSL_LIBNAME=ssleay32
- else
- # This probably wont work, but that's what the user said, so...
- SSL_LIBDIR="$with_ssl/lib"
- fi
- elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
- SSL_CRYPTO_LIBNAME=sslcrypto
- SSL_LIBDIR="$with_ssl/lib/powerpc/"
- elif test "x$ac_cv_sizeof_void_p" = "x8"; then
- if test -f "$with_ssl/lib64/libcrypto.a"; then
- SSL_LIBDIR="$with_ssl/lib64"
- elif test -f "$with_ssl/lib/64/libcrypto.a"; then
- SSL_LIBDIR="$with_ssl/lib/64"
- elif test -f "$with_ssl/lib64/libcrypto.so"; then
- SSL_LIBDIR="$with_ssl/lib64"
- elif test -f "$with_ssl/lib/64/libcrypto.so"; then
- SSL_LIBDIR="$with_ssl/lib/64"
- else
- SSL_LIBDIR="$with_ssl/lib"
- fi
- else
- SSL_LIBDIR="$with_ssl/lib"
- fi
- if test '!' -f "${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"; then
- SSL_DYNAMIC_ONLY=yes
- elif test '!' -f ${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.so -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
- SSL_STATIC_ONLY=yes
- fi
- SSL_INCLUDE="-I$with_ssl_incl/include"
- SSL_APP=ssl
- CRYPTO_APP=crypto
- SSH_APP=ssh
- if test "$cross_compiling" = "yes"; then
- SSL_RUNTIME_LIBDIR=`echo "$SSL_LIBDIR" | sed -n "s|^$erl_xcomp_sysroot\(/*\)\(.*\)\$|/\2|p"`
- else
- SSL_RUNTIME_LIBDIR="$SSL_LIBDIR"
- fi
-esac
-
-if test "x$SSL_APP" != "x" ; then
- dnl We found openssl, now check if we use kerberos 5 support
- dnl FIXME: Do we still support platforms that have Kerberos?
- AC_MSG_CHECKING(for OpenSSL kerberos 5 support)
- old_CPPFLAGS=$CPPFLAGS
- CPPFLAGS=$SSL_INCLUDE
- AC_EGREP_CPP(^yes$,[
-#include <openssl/opensslv.h>
-#include <openssl/opensslconf.h>
-#if OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(OPENSSL_NO_KRB5)
-yes
-#endif
- ],[
- AC_MSG_RESULT([yes])
- ssl_krb5_enabled=yes
- if test "x$SSL_DYNAMIC_ONLY" != "xyes"; then
- if test -f "$SSL_LIBDIR/libkrb5.a"; then
- SSL_LINK_WITH_KERBEROS=yes
- STATIC_KERBEROS_LIBS="$SSL_LIBDIR/libkrb5.a"
- if test -f "$SSL_LIBDIR/libkrb5support.a"; then
- STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libkrb5support.a"
- fi
- if test -f "$SSL_LIBDIR/libk5crypto.a"; then
- STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libk5crypto.a"
- fi
- if test -f "$SSL_LIBDIR/libresolv.a"; then
- STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libresolv.a"
- fi
- if test -f "$SSL_LIBDIR/libcom_err.a"; then
- STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libcom_err.a"
- fi
- else
- AC_MSG_WARN([Kerberos needed but no kerberos static libraries found])
- AC_MSG_WARN([Rescanning for dynamic SSL libraries])
- enable_dynamic_ssl=yes
- ssl_done=no
- SSL_LINK_WITH_KERBEROS=no
- STATIC_KERBEROS_LIBS=""
- ssl_krb5_enabled=no
- SSL_WITH_KERBEROS=no
- fi
- else
- SSL_LINK_WITH_KERBEROS=no
- STATIC_KERBEROS_LIBS=""
- fi
- ],[
- AC_MSG_RESULT([no])
- ssl_krb5_enabled=no
- SSL_WITH_KERBEROS=no
- ])
- CPPFLAGS=$old_CPPFLAGS
- SSL_KRB5_INCLUDE=
- if test "x$ssl_krb5_enabled" = "xyes" ; then
- AC_MSG_CHECKING(for krb5.h in standard locations)
- for dir in $extra_dir "$SSL_INCDIR/include" "$SSL_INCDIR/include/openssl" \
- "$SSL_INCDIR/include/kerberos" \
- "$erl_xcomp_isysroot/cygdrive/c/kerberos/include" \
- "$erl_xcomp_isysroot/usr/local/kerberos/include" \
- "$erl_xcomp_isysroot/usr/kerberos/include" \
- "$erl_xcomp_isysroot/usr/include"
- do
- if test -f "$dir/krb5.h" ; then
- SSL_KRB5_INCLUDE="$dir"
- break
- fi
- done
- if test "x$SSL_KRB5_INCLUDE" = "x" ; then
- AC_MSG_RESULT([not found])
- SSL_APP=
- CRYPTO_APP=
- SSH_APP=
- AC_MSG_WARN([OpenSSL is configured for kerberos but no krb5.h found])
- for a in ssl crypto ssh ; do
- echo "OpenSSL is configured for kerberos but no krb5.h found" > $ERL_TOP/lib/$a/SKIP
- done
- else
- AC_MSG_RESULT([found in $SSL_KRB5_INCLUDE])
- SSL_INCLUDE="$SSL_INCLUDE -I$SSL_KRB5_INCLUDE"
- fi
- fi
-fi
-
-done # while test ssl_done != yes
-
-SSL_CC_RUNTIME_LIBRARY_PATH=
-SSL_LD_RUNTIME_LIBRARY_PATH=
-SSL_DED_LD_RUNTIME_LIBRARY_PATH=
-cc_rflg="$CFLAG_RUNTIME_LIBRARY_PATH"
-ld_rflg="$LDFLAG_RUNTIME_LIBRARY_PATH"
-ded_ld_rflg="$DED_LD_FLAG_RUNTIME_LIBRARY_PATH"
-
-
-case "$with_ssl_rpath" in
-
-yes) # Use standard lib locations for ssl runtime library path
-
- if test "$SSL_APP" != "" && test "$SSL_DYNAMIC_ONLY" = "yes" && \
- { test "$cc_rflg" != "" || test "$ld_rflg" != "" || test "$ded_ld_rflg" != ""; } ; then
-
- AC_MSG_CHECKING(for ssl runtime library path to use)
-
- libdirs="/lib"
-
- if test "$ac_cv_sizeof_void_p" = "8"; then
- dir_lib64=no
- dir_lib_64=no
-
- case "$SSL_RUNTIME_LIBDIR" in
- */lib/64 | */lib/64/ ) dir_lib_64=yes;;
- */lib64 | */lib64/ ) dir_lib64=yes;;
- *) ;;
- esac
-
- for dir in $std_ssl_locations; do
- test $dir_lib_64 = no &&
- test -d "$erl_xcomp_sysroot$dir/lib/64" &&
- dir_lib_64=yes
- test $dir_lib64 = no &&
- test -d "$erl_xcomp_sysroot$dir/lib64" &&
- dir_lib64=yes
- done
-
- test $dir_lib_64 = yes && libdirs="/lib/64 $libdirs"
- test $dir_lib64 = yes && libdirs="/lib64 $libdirs"
- fi
-
- for type in std x_std curr; do
-
- cc_rpath="$cc_rflg$SSL_RUNTIME_LIBDIR"
- ld_rpath="$ld_rflg$SSL_RUNTIME_LIBDIR"
- ded_ld_rpath="$ded_ld_rflg$SSL_RUNTIME_LIBDIR"
- rpath="$SSL_RUNTIME_LIBDIR"
-
- if test $type != curr; then
- for ldir in $libdirs; do
- for dir in $std_ssl_locations; do
- test "$SSL_LIBDIR" != "$dir$ldir" || continue
- test $type != x_std || test -d "$dir$ldir" || continue
- test "$cc_rflg" = "" ||
- cc_rpath="$cc_rpath $cc_rflg$dir$ldir"
- test "$ld_rflg" = "" ||
- ld_rpath="$ld_rpath $ld_rflg$dir$ldir"
- test "$ded_ld_rflg" = "" ||
- ded_ld_rpath="$ded_ld_rpath $ded_ld_rflg$dir$ldir"
- rpath="$rpath:$dir$ldir"
- done
- done
- fi
-
- saveCFLAGS="$CFLAGS"
- saveLDFLAGS="$LDFLAGS"
- saveLIBS="$LIBS"
- CFLAGS="$CFLAGS $SSL_INCLUDE"
- LDFLAGS="$LDFLAGS $ld_rpath -L$SSL_LIBDIR"
- LIBS="-lcrypto"
- AC_TRY_LINK([
- #include <stdio.h>
- #include <openssl/hmac.h>
- ],
- [
- HMAC(0, 0, 0, 0, 0, 0, 0);
- ],
- [rpath_success=yes],
- [rpath_success=no])
- CFLAGS="$saveCFLAGS"
- LDFLAGS="$saveLDFLAGS"
- LIBS="$saveLIBS"
-
- test "$rpath_success" = "yes" && break
- done
-
- test "$rpath_success" = "yes" || { cc_rpath=; ld_rpath=; ded_ld_rpath=; rpath=; }
-
- SSL_CC_RUNTIME_LIBRARY_PATH="$cc_rpath"
- SSL_LD_RUNTIME_LIBRARY_PATH="$ld_rpath"
- SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
-
- AC_MSG_RESULT([$rpath])
- test "$rpath" != "" || AC_MSG_WARN([Cannot set run path during linking])
- fi
- ;;
-
-no) # Use no ssl runtime library path
- SSL_DED_LD_RUNTIME_LIBRARY_PATH=
- ;;
-
-*) # Use ssl runtime library paths set by --with-ssl-rpath (without any check)
- ded_ld_rpath=
- delimit=
- for dir in `echo $with_ssl_rpath | sed "s/,/ /g"`; do
- ded_ld_rpath="$ded_ld_rpath$delimit$ded_ld_rflg$dir"
- delimit=" "
- done
- SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
- ;;
-
-esac
-
-
-AC_ARG_ENABLE(fips,
-AS_HELP_STRING([--enable-fips], [enable OpenSSL FIPS mode support])
-AS_HELP_STRING([--disable-fips], [disable OpenSSL FIPS mode support (default)]),
-[ case "$enableval" in
- yes) enable_fips_support=yes ;;
- *) enable_fips_support=no ;;
- esac ], enable_fips_support=no)
-
-if test "x$enable_fips_support" = "xyes" && test "$CRYPTO_APP" != ""; then
- saveCFLAGS="$CFLAGS"
- saveLDFLAGS="$LDFLAGS"
- saveLIBS="$LIBS"
- CFLAGS="$CFLAGS $SSL_INCLUDE"
- LDFLAGS="$LDFLAGS $SSL_LD_RUNTIME_LIBRARY_PATH -L$SSL_LIBDIR"
- LIBS="-lcrypto"
- AC_CHECK_FUNC([FIPS_mode_set],
- [SSL_FLAGS="-DFIPS_SUPPORT"],
- [SSL_FLAGS=])
- CFLAGS="$saveCFLAGS"
- LDFLAGS="$saveLDFLAGS"
- LIBS="$saveLIBS"
-else
- SSL_FLAGS=
-fi
-
#--------------------------------------------------------------------
# Os mon stuff.
#--------------------------------------------------------------------
@@ -4126,6 +3218,8 @@ AC_DEFINE_UNQUOTED(ERTS_EMU_CMDLINE_FLAGS,
"$STATIC_CFLAGS $CFLAGS $DEBUG_CFLAGS $EMU_THR_DEFS $DEFS $WERRORFLAGS $WFLAGS",
[The only reason ERTS_EMU_CMDLINE_FLAGS exists is to force modification of config.h when the emulator command line flags are modified by configure])
+AC_SUBST(STATIC_CFLAGS)
+
dnl ----------------------------------------------------------------------
dnl Directories needed for the build
dnl ----------------------------------------------------------------------
@@ -4228,7 +3322,6 @@ AC_CONFIG_FILES([
include/internal/$host/erts_internal.mk:include/internal/erts_internal.mk.in
lib_src/$host/Makefile:lib_src/Makefile.in
../make/$host/otp.mk:../make/otp.mk.in
- ../make/$host/otp_ded.mk:../make/otp_ded.mk.in
])
AC_CONFIG_FILES([../make/make_emakefile:../make/make_emakefile.in],
@@ -4240,7 +3333,6 @@ dnl
dnl ../lib/ssl/c_src/$host/Makefile:../lib/ssl/c_src/Makefile.in
AC_CONFIG_FILES([
../lib/os_mon/c_src/$host/Makefile:../lib/os_mon/c_src/Makefile.in
- ../lib/crypto/c_src/$host/Makefile:../lib/crypto/c_src/Makefile.in
../lib/runtime_tools/c_src/$host/Makefile:../lib/runtime_tools/c_src/Makefile.in
../lib/tools/c_src/$host/Makefile:../lib/tools/c_src/Makefile.in
])
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index f29bb7b8f9..d77d989057 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -811,7 +811,9 @@
</item>
<item>
<p>If T is the empty list type <c>[]</c>, then Rep(T) =
- <c>{type,Line,nil,[]}</c>.</p>
+ <c>{type,Line,nil,[]}</c>, that is, the empty list type
+ <c>[]</c> cannot be distinguished from the predefined type
+ <c>nil()</c>.</p>
</item>
<item>
<p>If T is a fun type <c>fun()</c>, then Rep(T) =
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index a5826307f7..3820132d71 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1252,7 +1252,7 @@ typedef struct {
<p>Similar to <c>fprintf</c> but this format string also accepts
<c>"%T"</c>, which formats Erlang terms of type
<seealso marker="#ERL_NIF_TERM"><c>ERL_NIF_TERM</c></seealso>.</p>
- <p>This function is primarily intenden for debugging purpose. It is not
+ <p>This function is primarily intended for debugging purpose. It is not
recommended to print very large terms with <c>%T</c>. The function may
change <c>errno</c>, even if successful.</p>
</desc>
@@ -3216,7 +3216,7 @@ if (retval &amp; ERL_NIF_SELECT_STOP_CALLED) {
<p>Similar to <c>snprintf</c> but this format string also accepts
<c>"%T"</c>, which formats Erlang terms of type
<seealso marker="#ERL_NIF_TERM"><c>ERL_NIF_TERM</c></seealso>.</p>
- <p>This function is primarily intenden for debugging purpose. It is not
+ <p>This function is primarily intended for debugging purpose. It is not
recommended to print very large terms with <c>%T</c>. The function may
change <c>errno</c>, even if successful.</p>
</desc>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 8e014c3010..bd33e35603 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -1751,6 +1751,10 @@ true</pre>
<item>
<p><c>Pid</c> is the process identifier of the process
that originally created the fun.</p>
+ <p>It might point to the <c>init</c> process if the
+ <c>Fun</c> was statically allocated when module was
+ loaded (this optimisation is performed for local
+ functions that do not capture the enviornment).</p>
</item>
<tag><c>{index, Index}</c></tag>
<item>
diff --git a/erts/doc/src/escript.xml b/erts/doc/src/escript.xml
index 9b0d42185e..be1664b39f 100644
--- a/erts/doc/src/escript.xml
+++ b/erts/doc/src/escript.xml
@@ -4,7 +4,7 @@
<comref>
<header>
<copyright>
- <year>2007</year><year>2017</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -155,9 +155,12 @@ io:setopts([{encoding, unicode}])</code>
for example:</p>
<pre>
halt(1).</pre>
- <p>To retrieve the pathname of the script, call
- <seealso marker="#script_name_0">
- <c>escript:script_name()</c></seealso> from your script
+ <p>
+ To retrieve the pathname of the script, call
+ <seealso marker="#script_name-0">
+ <c>escript:script_name()</c>
+ </seealso>
+ from your script
(the pathname is usually, but not always, absolute).</p>
<p>If the file contains source code (as in the example above),
it is processed by the
@@ -229,6 +232,7 @@ $ <input>escript factorial.beam 5</input>
factorial 5 = 120
$ <input>escript factorial.zip 5</input>
factorial 5 = 120</pre>
+ <marker id="create-2"/>
</desc>
</func>
@@ -259,7 +263,7 @@ factorial 5 = 120</pre>
zip:create_option()</seealso>]</v>
</type>
<desc>
- <p><marker id="create_2"></marker>
+ <p>
Creates an escript from a list of sections. The
sections can be specified in any order. An escript begins with an
optional <c>Header</c> followed by a mandatory <c>Body</c>. If
@@ -344,6 +348,7 @@ ok
{{2010,3,2},{0,59,22}},
54,1,0,0,0,0,0},
&lt;&lt;"%% demo.erl\n-module(demo).\n-export([main/1]).\n\n%% Demo\nmain(_Arg"...&gt;&gt;}]}</pre>
+ <marker id="extract-2"/>
</desc>
</func>
@@ -368,9 +373,11 @@ ok
<v>SourceCode = BeamCode = ZipArchive = binary()</v>
</type>
<desc>
- <p><marker id="extract_2"></marker>
- Parses an escript and extracts its sections. This is the reverse
- of <seealso marker="#create_2"><c>create/2</c></seealso>.</p>
+ <p>
+ Parses an escript and extracts its sections.
+ This is the reverse of
+ <seealso marker="#create-2"><c>create/2</c></seealso>.
+ </p>
<p>All sections are returned even if they do not exist in the
escript. If a particular section happens to have the same
value as the default value, the extracted value is set to the
@@ -393,6 +400,7 @@ ok
{ok,[{{archive,&lt;&lt;80,75,3,4,20,0,0,0,8,0,118,7,98,60,105,
152,61,93,107,0,0,0,118,0,...&gt;&gt;}
{emu_args,undefined}]}</pre>
+ <marker id="script_name-0"/>
</desc>
</func>
@@ -403,7 +411,7 @@ ok
<v>File = filename()</v>
</type>
<desc>
- <p><marker id="script_name_0"></marker>
+ <p>
Returns the name of the escript that is executed.
If the function is invoked outside the context
of an escript, the behavior is undefined.</p>
diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml
index 5cd6dc1750..48e502739a 100644
--- a/erts/doc/src/match_spec.xml
+++ b/erts/doc/src/match_spec.xml
@@ -113,6 +113,7 @@
<c><![CDATA[length]]></c> | <c><![CDATA[map_get]]></c> |
<c><![CDATA[map_size]]></c> | <c><![CDATA[node]]></c> |
<c><![CDATA[round]]></c> | <c><![CDATA[size]]></c> |
+ <c><![CDATA[bit_size]]></c> |
<c><![CDATA[tl]]></c> | <c><![CDATA[trunc]]></c> |
<c><![CDATA['+']]></c> | <c><![CDATA['-']]></c> |
<c><![CDATA['*']]></c> | <c><![CDATA['div']]></c> |
@@ -194,6 +195,7 @@
<c><![CDATA[length]]></c> | <c><![CDATA[map_get]]></c> |
<c><![CDATA[map_size]]></c> | <c><![CDATA[node]]></c> |
<c><![CDATA[round]]></c> | <c><![CDATA[size]]></c> |
+ <c><![CDATA[bit_size]]></c> |
<c><![CDATA[tl]]></c> | <c><![CDATA[trunc]]></c> |
<c><![CDATA['+']]></c> | <c><![CDATA['-']]></c> |
<c><![CDATA['*']]></c> | <c><![CDATA['div']]></c> |
@@ -269,8 +271,9 @@
other <c>false</c> to return <c><![CDATA[true]]></c>; otherwise
<c><![CDATA['xor']]></c> returns false.</p>
</item>
- <tag><c>abs</c>, <c>element</c>, <c>hd</c>, <c>length</c>, <c>node</c>,
- <c>round</c>, <c>size</c>, <c>tl</c>, <c>trunc</c>, <c>'+'</c>,
+ <tag><c>abs</c>, <c>element</c>, <c>hd</c>, <c>length</c>,
+ <c>map_get</c>, <c>map_size</c>, <c>node</c>, <c>round</c>,
+ <c>size</c>, <c>bit_size</c>, <c>tl</c>, <c>trunc</c>, <c>'+'</c>,
<c>'-'</c>, <c>'*'</c>, <c>'div'</c>, <c>'rem'</c>, <c>'band'</c>,
<c>'bor'</c>, <c>'bxor'</c>, <c>'bnot'</c>, <c>'bsl'</c>,
<c>'bsr'</c>, <c>'>'</c>, <c>'>='</c>, <c>'&lt;'</c>, <c>'=&lt;'</c>,
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 5866ee704a..a71d1eddf5 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -31,6 +31,334 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A bug where the socket option 'pktoptions' caused a read
+ of uninitialized memory has been fixed. Would cause
+ malfunction on FreeBSD.</p>
+ <p>
+ Own Id: OTP-14297 Aux Id: OTP-15141 </p>
+ </item>
+ <item>
+ <p>Fixed a memory leak on errors when reading files.</p>
+ <p>
+ Own Id: OTP-15318</p>
+ </item>
+ <item>
+ <p>File access through UNC paths works again on Windows.
+ This regression was introduced in OTP 21.</p>
+ <p>
+ Own Id: OTP-15333 Aux Id: ERL-737 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the seq_trace token to not be cleared when a process
+ receives messages sent by erts. Some examples of when
+ this could happen is all port BIFs, i.e.
+ <c>open_port</c>, <c>port_command</c> etc etc.</p>
+ <p>
+ Fix so that messages sent by nifs can be traced using
+ normal and <c>seq_trace</c> tracing.</p>
+ <p>
+ Own Id: OTP-15038 Aux Id: ERL-602 </p>
+ </item>
+ <item>
+ <p>
+ Fixed specs and documentation for <c>process_info</c>
+ item <c>monitored_by</c> to include port identifiers and
+ nif resources as possible types.</p>
+ <p>
+ Own Id: OTP-15180 Aux Id: ERL-648 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in generation of erl_crash.dump, which could
+ cause VM to crash.</p>
+ <p>
+ Bug exist since erts-9.2 (OTP-20.2).</p>
+ <p>
+ Own Id: OTP-15181</p>
+ </item>
+ <item>
+ <p>
+ Fix bug where ctrl-break or ctrl-c would not trigger the
+ break mode properly on Windows. This bug was introduced
+ in erts-10.0 (OTP-21).</p>
+ <p>
+ Own Id: OTP-15205</p>
+ </item>
+ <item>
+ <p>
+ Fix a performance bug for reception of UDP packages,
+ where a memory buffer would be reallocated when it should
+ not have been.</p>
+ <p>
+ Introduce a limit on the maximum automatic increase of
+ the UDP user-space buffer to the theoretical max of the
+ network PATH, i.e. 65535.</p>
+ <p>
+ Own Id: OTP-15206</p>
+ </item>
+ <item>
+ <p>
+ Fix alignment of erts allocator state internally in erts.
+ With the improper alignment the emulator would refuse to
+ start when compiled with clang on 32-bit systems.</p>
+ <p>
+ Own Id: OTP-15208 Aux Id: PR-1897 ERL-677 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug where too many concurrent calls to
+ <c>erlang:open_port({spawn,"cmd"},...)</c> would result
+ in the emulator terminating with the reason "Failed to
+ write to erl_child_setup: ". After this fix the
+ <c>open_port</c> call will throw an <c>emfile</c>
+ exception instead.</p>
+ <p>
+ Own Id: OTP-15210</p>
+ </item>
+ <item>
+ <p>
+ Upgraded the ERTS internal PCRE library from version 8.41
+ to version 8.42. See <url
+ href="http://pcre.org/original/changelog.txt">http://pcre.org/original/changelog.txt</url>
+ for information about changes made to PCRE. This library
+ implements major parts of the <seealso
+ marker="stdlib:re"><c>re</c></seealso> regular
+ expressions module.</p>
+ <p>
+ Own Id: OTP-15217</p>
+ </item>
+ <item>
+ <p>
+ Fix <c>open_port({fd,X,Y}, ...)</c> to release the file
+ descriptors from the pollset when closing the port.
+ Without this fix the same file descriptor number could
+ not be reused when doing multiple open_port and
+ port_close sequences.</p>
+ <p>
+ Own Id: OTP-15236 Aux Id: ERL-692 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>float_to_list/2</c> and
+ <c>float_to_binary/2</c> with options
+ <c>[{decimals,0},compact]</c> causing totally wrong
+ results. Bug exists since OTP-21.0.</p>
+ <p>
+ Own Id: OTP-15276 Aux Id: PR-1920 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>erlang:memory</c> causing <c>ets</c> to
+ report too much. This small false memory leak (16 bytes
+ each time) can only happen when a specific race condition
+ occurs between scheduler threads on a table with option
+ <c>write_concurrency</c>.</p>
+ <p>
+ Own Id: OTP-15278</p>
+ </item>
+ <item>
+ <p>
+ Minor <c>configure</c> test fixes</p>
+ <p>
+ Own Id: OTP-15282</p>
+ </item>
+ <item>
+ <p>
+ Improved robustness of distribution connection setup. In
+ OTP-21.0 a truly asynchronous connection setup was
+ introduced. This is further improvement on that work to
+ make the emulator more robust and also be able to recover
+ in cases when involved Erlang processes misbehave.</p>
+ <p>
+ Own Id: OTP-15297 Aux Id: OTP-15279, OTP-15280 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The socket options <c>recvtos</c>, <c>recvttl</c>,
+ <c>recvtclass</c> and <c>pktoptions</c> have been
+ implemented in the socket modules. See the documentation
+ for the <c>gen_tcp</c>, <c>gen_udp</c> and <c>inet</c>
+ modules. Note that support for these in the runtime
+ system is platform dependent. Especially for
+ <c>pktoptions</c> which is very Linux specific and
+ obsoleted by the RFCs that defined it.</p>
+ <p>
+ Own Id: OTP-15145 Aux Id: ERIERL-187 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ As of ERTS version 10.0 (OTP 21.0) the
+ <c>erl_child_setup</c> program, which creates port
+ programs, ignores <c>TERM</c> signals. This setting was
+ unintentionally inherited by port programs. Handling of
+ <c>TERM</c> signals in port programs has now been
+ restored to the default behavior. That is, terminate the
+ process.</p>
+ <p>
+ Own Id: OTP-15289 Aux Id: ERIERL-235, OTP-14943, ERL-576 </p>
+ </item>
+ <item>
+ <p>
+ The fix made for OTP-15279 in erts-10.07 (OTP-21.0.8) was
+ not complete. It could cause a new connection attempt to
+ be incorrectly aborted in certain cases. This fix will
+ amend that flaw.</p>
+ <p>
+ Own Id: OTP-15296 Aux Id: OTP-15279, ERIERL-226 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could get stuck in an infinite rescheduling
+ loop between normal and dirty schedulers. This bug was
+ introduced in ERTS version 10.0.</p>
+ <p>
+ Thanks to Maxim Fedorov for finding and fixing this
+ issue.</p>
+ <p>
+ Own Id: OTP-15275 Aux Id: PR-1943 </p>
+ </item>
+ <item>
+ <p>
+ Garbage collection of a distribution entry could cause an
+ emulator crash if <c>net_kernel</c> had not brought
+ previous connection attempts on it down properly.</p>
+ <p>
+ Own Id: OTP-15279 Aux Id: ERIERL-226 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race between termination of a process and resume of the
+ same process via <c>erlang:resume_process/1</c> could
+ cause the VM to crash. This bug was introduced in erts
+ version 10.0 (OTP 21.0).</p>
+ <p>
+ Own Id: OTP-15237</p>
+ </item>
+ <item>
+ <p>
+ When tracing on <c>running</c>, <c>in</c> trace events
+ could be lost when a process was rescheduled between a
+ dirty and a normal scheduler.</p>
+ <p>
+ Own Id: OTP-15269 Aux Id: ERL-713 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug which caused an emulator crash when
+ <c>enif_send()</c> was called by a NIF that executed on a
+ dirty scheduler. The bug was either triggered when the
+ NIF called <c>enif_send()</c> without a message
+ environment, or when the process executing the NIF was
+ <c>send</c> traced.</p>
+ <p>
+ Own Id: OTP-15223</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.0.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that prevented the <c>noshell</c> option
+ from working correctly on Mac OS X and BSD.</p>
+ <p>
+ Own Id: OTP-15169</p>
+ </item>
+ <item>
+ <p>Fixed a crash when matching directly against a literal
+ map using a single key that had been saved on the
+ stack.</p>
+ <p>
+ Own Id: OTP-15184</p>
+ </item>
+ <item>
+ <p>Fix node crash when passing a bad time option to
+ <c>file:read_file_info/2</c>.</p>
+ <p>
+ Own Id: OTP-15196</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.0.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1027,6 +1355,108 @@
</section>
+<section><title>Erts 9.3.3.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ ERTS internal trees of monitor structures could get into
+ an inconsistent state. This could cause <c>'DOWN'</c>
+ messages not to be delivered when they should, as well as
+ delivery of <c>'DOWN'</c> messages that should not be
+ delivered.</p>
+ <p>
+ This bug was introduced in ERTS version 9.0 (OTP 20.0)
+ and was fixed in ERTS version 10.0 (OTP 21.0) due to a
+ rewrite of the monitor code. That is, this bug only exist
+ in the OTP 20 release.</p>
+ <p>
+ Own Id: OTP-15399 Aux Id: ERL-751, ERIERL-262, OTP-14205 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>ets:select_replace</c> when called with a
+ fully bound key could cause a following call to
+ <c>ets:next</c> or <c>ets:prev</c> to crash the emulator
+ or return invalid result.</p>
+ <p>
+ Own Id: OTP-15346</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed a bug which caused an emulator crash when
+ <c>enif_send()</c> was called by a NIF that executed on a
+ dirty scheduler. The bug was either triggered when the
+ NIF called <c>enif_send()</c> without a message
+ environment, or when the process executing the NIF was
+ <c>send</c> traced.</p>
+ <p>
+ Own Id: OTP-15223</p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a race condition in the inet driver that could
+ cause receive to hang when the emulator was compiled with
+ gcc 8.</p>
+ <p>
+ Own Id: OTP-15158 Aux Id: ERL-654 </p>
+ </item>
+ <item>
+ <p>
+ Fix bug in generation of erl_crash.dump, which could
+ cause VM to crash.</p>
+ <p>
+ Bug exist since erts-9.2 (OTP-20.2).</p>
+ <p>
+ Own Id: OTP-15181</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 9.3.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -2469,6 +2899,79 @@
</section>
+<section><title>Erts 8.3.5.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed small memory leak that could occur when sending to
+ a terminating port.</p>
+ <p>
+ Own Id: OTP-14609 Aux Id: ERIERL-238 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 8.3.5.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a race condition in the inet driver that could
+ cause receive to hang when the emulator was compiled with
+ gcc 8.</p>
+ <p>
+ Own Id: OTP-15158 Aux Id: ERL-654 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug causing some Erlang references to be
+ inconsistently ordered. This could for example cause
+ failure to look up certain elements with references as
+ keys in search data structures. This bug was introduced
+ in R13B02.</p>
+ <p>
+ Thanks to Simon Cornish for finding the bug and supplying
+ a fix.</p>
+ <p>
+ *** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>
+ Own Id: OTP-15225</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 8.3.5.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug in file closure on Unix; close(2) was
+ retried on EINTR which could cause a different (recently
+ opened) file to be closed as well.</p>
+ <p>
+ Own Id: OTP-14775</p>
+ </item>
+ <item>
+ <p>
+ A race-condition when tearing down a connection with
+ active node monitors could cause the runtime system to
+ crash.</p>
+ <p>
+ This bug was introduced in ERTS version 8.0 (OTP 19.0).</p>
+ <p>
+ Own Id: OTP-14781 Aux Id: OTP-13047 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 8.3.5.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -4296,6 +4799,22 @@
</section>
+<section><title>Erts 7.3.1.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed small memory leak that could occur when sending to
+ a terminating port.</p>
+ <p>
+ Own Id: OTP-14609 Aux Id: ERIERL-238 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 7.3.1.4</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -5788,6 +6307,103 @@
</section>
+<section><title>Erts 6.4.1.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process communicating with a port via one of the
+ <c>erlang:port_*</c> BIFs could potentially end up in an
+ inconsistent state if the port terminated during the
+ communication. When this occurred the process could later
+ block in a <c>receive</c> even though it had messages
+ matching in its message queue.</p>
+ <p>
+ This bug was introduced in erts version 5.10 (OTP R16A).</p>
+ <p>
+ Own Id: OTP-13424 Aux Id: OTP-10336 </p>
+ </item>
+ <item>
+ <p>
+ Calls to <c>erl_drv_send_term()</c> or
+ <c>erl_drv_output_term()</c> from a non-scheduler thread
+ while the corresponding port was invalid caused the
+ emulator to enter an inconsistent state which eventually
+ caused an emulator crash.</p>
+ <p>
+ Own Id: OTP-13866</p>
+ </item>
+ <item>
+ <p>Driver and NIF operations accessing processes or ports
+ could cause an emulator crash when used from
+ non-scheduler threads. Those operations are:</p> <list>
+ <item><c>erl_drv_send_term()</c></item>
+ <item><c>driver_send_term()</c></item>
+ <item><c>erl_drv_output_term()</c></item>
+ <item><c>driver_output_term()</c></item>
+ <item><c>enif_send()</c></item>
+ <item><c>enif_port_command()</c></item> </list>
+ <p>
+ Own Id: OTP-13869</p>
+ </item>
+ <item>
+ <p>
+ Fix bug in <c>binary_to_term</c> for binaries created by
+ <c>term_to_binary </c> with option <c>compressed</c>. The
+ bug can cause <c>badarg</c> exception for a valid binary
+ when Erlang VM is linked against a <c>zlib</c> library of
+ version 1.2.9 or newer. Bug exists since OTP 17.0.</p>
+ <p>
+ Own Id: OTP-14159 Aux Id: ERL-340 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in operator <c>bxor</c> causing erroneuos
+ result when one operand is a big <em>negative</em>
+ integer with the lowest <c>N*W</c> bits as zero and the
+ other operand not larger than <c>N*W</c> bits. <c>N</c>
+ is an integer of 1 or larger and <c>W</c> is 32 or 64
+ depending on word size.</p>
+ <p>
+ Own Id: OTP-14514</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>binary_to_term</c> and
+ <c>binary_to_atom</c> that could cause VM crash.
+ Typically happens when the last character of an UTF8
+ string is in the range 128 to 255, but truncated to only
+ one byte. Bug exists in <c>binary_to_term</c> since ERTS
+ version 5.10.2 (OTP_R16B01) and <c>binary_to_atom</c>
+ since ERTS version 9.0 (OTP-20.0).</p>
+ <p>
+ Own Id: OTP-14590 Aux Id: ERL-474 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 6.4.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When calling <c>garbage_collect/[1,2]</c> or
+ <c>check_process_code/[2,3]</c> from a process with a
+ higher priority than the priority of the process operated
+ on, the run queues could end up in an inconsistent state.
+ This bug has now been fixed.</p>
+ <p>
+ Own Id: OTP-13298 Aux Id: OTP-11388 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 6.4.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -9879,7 +10495,7 @@
you use erlang:halt/2 with an integer first argument and
an option list containing {flush,false} as the second
argument. Note that now is flushing not dependant of the
- exit code, and you can not only flush async threads
+ exit code, and you cannot only flush async threads
operations which we deemed as a strange behaviour anyway.
</p>
<p>Also, erlang:halt/1,2 has gotten a new feature: If the
@@ -18614,4 +19230,3 @@
</section>
</section>
</chapter>
-
diff --git a/erts/doc/src/time_correction.xml b/erts/doc/src/time_correction.xml
index 77e7a40529..a9f06d8a7d 100644
--- a/erts/doc/src/time_correction.xml
+++ b/erts/doc/src/time_correction.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1999</year><year>2016</year>
+ <year>1999</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -940,7 +940,7 @@ EventTag = {Time, UMI}</code>
</item>
<item>
<seealso marker="erlang#system_info_os_system_time_source">
- <c>erlang:system_info(os_system_time_source)</c></seealso>)
+ <c>erlang:system_info(os_system_time_source)</c></seealso>
</item>
</list>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 054692819e..f84c124a14 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -633,8 +633,8 @@ GENERATE += $(TTF_DIR)/driver_tab.c
# This list must be consistent with PRE_LOADED_MODULES in
# erts/preloaded/src/Makefile.
-PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
- $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \
+PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \
+ $(ERL_TOP)/erts/preloaded/ebin/erl_init.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_buffer.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \
@@ -874,7 +874,7 @@ RUN_OBJS += \
$(OBJDIR)/erl_thr_queue.o $(OBJDIR)/erl_sched_spec_pre_alloc.o \
$(OBJDIR)/erl_ptab.o $(OBJDIR)/erl_map.o \
$(OBJDIR)/erl_msacc.o $(OBJDIR)/erl_lock_flags.o \
- $(OBJDIR)/erl_io_queue.o
+ $(OBJDIR)/erl_io_queue.o $(OBJDIR)/erl_db_catree.o
LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o
NIF_OBJS = \
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 45b7540aeb..fb223d2a5d 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -208,7 +208,6 @@ atom dirty_nif_finalizer
atom disable_trace
atom disabled
atom discard
-atom display_items
atom dist
atom dist_cmd
atom dist_ctrl_put_data
@@ -237,6 +236,7 @@ atom eof
atom eol
atom Eq='=:='
atom Eqeq='=='
+atom erl_init
atom erl_tracer
atom erlang
atom erl_signal_server
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index a0dbd9ec7b..d221e6aea6 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -1753,6 +1753,7 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2)
if (literals) {
ErtsLiteralAreaRef *ref;
+ ErtsMessage *mp;
ref = erts_alloc(ERTS_ALC_T_LITERAL_REF,
sizeof(ErtsLiteralAreaRef));
ref->literal_area = literals;
@@ -1767,10 +1768,12 @@ BIF_RETTYPE erts_internal_purge_module_2(BIF_ALIST_2)
release_literal_areas.last = ref;
}
erts_mtx_unlock(&release_literal_areas.mtx);
+ mp = erts_alloc_message(0, NULL);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(BIF_P,
erts_literal_area_collector,
0,
- erts_alloc_message(0, NULL),
+ mp,
am_copy_literals);
}
diff --git a/erts/emulator/beam/beam_debug.c b/erts/emulator/beam/beam_debug.c
index 10d20c8f3f..b33aab7eee 100644
--- a/erts/emulator/beam/beam_debug.c
+++ b/erts/emulator/beam/beam_debug.c
@@ -786,8 +786,8 @@ print_op(fmtfn_t to, void *to_arg, int op, int size, BeamInstr* addr)
}
}
break;
- case op_i_put_tuple_xI:
- case op_i_put_tuple_yI:
+ case op_put_tuple2_xI:
+ case op_put_tuple2_yI:
case op_new_map_dtI:
case op_update_map_assoc_sdtI:
case op_update_map_exact_jsdtI:
@@ -1191,6 +1191,7 @@ dirty_send_message(Process *c_p, Eterm to, Eterm tag)
mp = erts_alloc_message_heap(rp, &rp_locks, 3, &hp, &ohp);
msg = TUPLE2(hp, tag, c_p->common.id);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, rp_locks, mp, msg);
if (rp == real_c_p)
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index ab5920a67e..aa61a2d7f9 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -3061,12 +3061,14 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
Uint need;
flatmap_t *old_mp, *mp;
Eterm res;
+ Eterm* old_hp;
Eterm* hp;
Eterm* E;
Eterm* old_keys;
Eterm* old_vals;
Eterm new_key;
Eterm map;
+ int changed = 0;
n /= 2; /* Number of values to be updated */
ASSERT(n > 0);
@@ -3133,6 +3135,7 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
* Update map, keeping the old key tuple.
*/
+ old_hp = p->htop;
hp = p->htop;
E = p->stop;
@@ -3155,20 +3158,26 @@ erts_gc_update_map_exact(Process* p, Eterm* reg, Uint live, Uint n, Eterm* new_p
/* Not same keys */
*hp++ = *old_vals;
} else {
- GET_TERM(new_p[1], *hp);
- hp++;
- n--;
+ GET_TERM(new_p[1], *hp);
+ if(*hp != *old_vals) changed = 1;
+ hp++;
+ n--;
if (n == 0) {
- /*
- * All updates done. Copy remaining values
- * and return the result.
- */
- for (i++, old_vals++; i < num_old; i++) {
- *hp++ = *old_vals++;
- }
- ASSERT(hp == p->htop + need);
- p->htop = hp;
- return res;
+ /*
+ * All updates done. Copy remaining values
+ * if any changed or return the original one.
+ */
+ if(changed) {
+ for (i++, old_vals++; i < num_old; i++) {
+ *hp++ = *old_vals++;
+ }
+ ASSERT(hp == p->htop + need);
+ p->htop = hp;
+ return res;
+ } else {
+ p->htop = old_hp;
+ return map;
+ }
} else {
new_p += 2;
GET_TERM(*new_p, new_key);
diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c
index e61199a8fd..c28a5c57e6 100644
--- a/erts/emulator/beam/beam_load.c
+++ b/erts/emulator/beam/beam_load.c
@@ -2868,6 +2868,7 @@ load_code(LoaderState* stp)
break;
case op_bs_put_string_WW:
case op_i_bs_match_string_xfWW:
+ case op_i_bs_match_string_yfWW:
new_string_patch(stp, ci-1);
break;
@@ -4245,21 +4246,55 @@ gen_make_fun2(LoaderState* stp, GenOpArg idx)
{
ErlFunEntry* fe;
GenOp* op;
+ Uint arity, num_free;
if (idx.val >= stp->num_lambdas) {
- stp->lambda_error = "missing or short chunk 'FunT'";
- fe = 0;
+ stp->lambda_error = "missing or short chunk 'FunT'";
+ fe = 0;
+ num_free = 0;
+ arity = 0;
} else {
- fe = stp->lambdas[idx.val].fe;
+ fe = stp->lambdas[idx.val].fe;
+ num_free = stp->lambdas[idx.val].num_free;
+ arity = fe->arity;
}
NEW_GENOP(stp, op);
- op->op = genop_i_make_fun_2;
- op->arity = 2;
- op->a[0].type = TAG_u;
- op->a[0].val = (BeamInstr) fe;
- op->a[1].type = TAG_u;
- op->a[1].val = stp->lambdas[idx.val].num_free;
+
+ /*
+ * It's possible this is called before init process is started,
+ * skip the optimisation in such case.
+ */
+ if (num_free == 0 && erts_init_process_id != ERTS_INVALID_PID) {
+ Uint lit;
+ Eterm* hp;
+ ErlFunThing* funp;
+
+ lit = new_literal(stp, &hp, ERL_FUN_SIZE);
+ funp = (ErlFunThing *) hp;
+ erts_refc_inc(&fe->refc, 2);
+ funp->thing_word = HEADER_FUN;
+ funp->next = NULL;
+ funp->fe = fe;
+ funp->num_free = 0;
+ funp->creator = erts_init_process_id;
+ funp->arity = arity;
+
+ op->op = genop_move_2;
+ op->arity = 2;
+ op->a[0].type = TAG_q;
+ op->a[0].val = lit;
+ op->a[1].type = TAG_x;
+ op->a[1].val = 0;
+ } else {
+ op->op = genop_i_make_fun_2;
+ op->arity = 2;
+ op->a[0].type = TAG_u;
+ op->a[0].val = (BeamInstr) fe;
+ op->a[1].type = TAG_u;
+ op->a[1].val = num_free;
+ }
+
op->next = NULL;
return op;
}
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 97e1ee1286..4741d7451d 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -218,11 +218,8 @@ BIF_RETTYPE link_1(BIF_ALIST_1)
* We have (pending) connection.
* Setup link and enqueue link signal.
*/
-#ifdef DEBUG
- int inserted =
-#endif
- erts_link_dist_insert(&ldp->b, dep->mld);
- ASSERT(inserted);
+ int inserted = erts_link_dist_insert(&ldp->b, dep->mld);
+ ASSERT(inserted); (void)inserted;
erts_de_runlock(dep);
code = erts_dsig_send_link(&dsd, BIF_P->common.id, BIF_ARG_1);
@@ -567,12 +564,8 @@ BIF_RETTYPE monitor_2(BIF_ALIST_2)
case ERTS_DSIG_PREP_PENDING:
case ERTS_DSIG_PREP_CONNECTED: {
-#ifdef DEBUG
- int inserted =
-#endif
-
- erts_monitor_dist_insert(&mdp->target, dep->mld);
- ASSERT(inserted);
+ int inserted = erts_monitor_dist_insert(&mdp->target, dep->mld);
+ ASSERT(inserted); (void)inserted;
erts_de_runlock(dep);
code = erts_dsig_send_monitor(&dsd, BIF_P->common.id, target, ref);
@@ -1803,6 +1796,7 @@ ebif_bang_2(BIF_ALIST_2)
#define SEND_INTERNAL_ERROR (-6)
#define SEND_AWAIT_RESULT (-7)
#define SEND_YIELD_CONTINUE (-8)
+#define SEND_SYSTEM_LIMIT (-9)
static Sint remote_send(Process *p, DistEntry *dep,
@@ -1842,6 +1836,8 @@ static Sint remote_send(Process *p, DistEntry *dep,
res = SEND_YIELD_RETURN;
else if (code == ERTS_DSIG_SEND_CONTINUE)
res = SEND_YIELD_CONTINUE;
+ else if (code == ERTS_DSIG_SEND_TOO_LRG)
+ res = SEND_SYSTEM_LIMIT;
else
res = 0;
break;
@@ -2063,7 +2059,7 @@ do_send(Process *p, Eterm to, Eterm msg, Eterm *refp, ErtsSendContext *ctx)
if (p == rp)
rp_locks |= ERTS_PROC_LOCK_MAIN;
/* send to local process */
- erts_send_message(p, rp, &rp_locks, msg, 0);
+ erts_send_message(p, rp, &rp_locks, msg);
erts_proc_unlock(rp,
p == rp
? (rp_locks & ~ERTS_PROC_LOCK_MAIN)
@@ -2162,6 +2158,9 @@ BIF_RETTYPE send_3(BIF_ALIST_3)
case SEND_BADARG:
ERTS_BIF_PREP_ERROR(retval, p, BADARG);
break;
+ case SEND_SYSTEM_LIMIT:
+ ERTS_BIF_PREP_ERROR(retval, p, SYSTEM_LIMIT);
+ break;
case SEND_USER_ERROR:
ERTS_BIF_PREP_ERROR(retval, p, EXC_ERROR);
break;
@@ -2218,6 +2217,10 @@ static BIF_RETTYPE dsend_continue_trap_1(BIF_ALIST_1)
BUMP_ALL_REDS(BIF_P);
BIF_TRAP1(&dsend_continue_trap_export, BIF_P, BIF_ARG_1);
}
+ case ERTS_DSIG_SEND_TOO_LRG: { /*SEND_SYSTEM_LIMIT*/
+ erts_set_gc_state(BIF_P, 1);
+ BIF_ERROR(BIF_P, SYSTEM_LIMIT);
+ }
default:
erts_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result);
break;
@@ -2275,6 +2278,9 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg)
case SEND_BADARG:
ERTS_BIF_PREP_ERROR(retval, p, BADARG);
break;
+ case SEND_SYSTEM_LIMIT:
+ ERTS_BIF_PREP_ERROR(retval, p, SYSTEM_LIMIT);
+ break;
case SEND_USER_ERROR:
ERTS_BIF_PREP_ERROR(retval, p, EXC_ERROR);
break;
@@ -2732,9 +2738,7 @@ BIF_RETTYPE atom_to_list_1(BIF_ALIST_1)
Uint num_chars, num_built, num_eaten;
byte* err_pos;
Eterm res;
-#ifdef DEBUG
int ares;
-#endif
if (is_not_atom(BIF_ARG_1))
BIF_ERROR(BIF_P, BADARG);
@@ -2744,11 +2748,9 @@ BIF_RETTYPE atom_to_list_1(BIF_ALIST_1)
if (ap->len == 0)
BIF_RET(NIL); /* the empty atom */
-#ifdef DEBUG
ares =
-#endif
erts_analyze_utf8(ap->name, ap->len, &err_pos, &num_chars, NULL);
- ASSERT(ares == ERTS_UTF8_OK);
+ ASSERT(ares == ERTS_UTF8_OK); (void)ares;
res = erts_utf8_to_list(BIF_P, num_chars, ap->name, ap->len, ap->len,
&num_built, &num_eaten, NIL);
@@ -3622,6 +3624,10 @@ erts_internal_garbage_collect_1(BIF_ALIST_1)
default: BIF_ERROR(BIF_P, BADARG);
}
erts_garbage_collect(BIF_P, 0, NULL, 0);
+ if (ERTS_PROC_IS_EXITING(BIF_P)) {
+ /* The max heap size limit was reached. */
+ return THE_NON_VALUE;
+ }
return am_true;
}
@@ -4438,13 +4444,6 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2)
erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
BIF_RET(old_value);
- } else if (BIF_ARG_1 == am_display_items) {
- int oval = display_items;
- if (!is_small(BIF_ARG_2) || (n = signed_val(BIF_ARG_2)) < 0) {
- goto error;
- }
- display_items = n < 32 ? 32 : n;
- BIF_RET(make_small(oval));
} else if (BIF_ARG_1 == am_debug_flags) {
BIF_RET(am_true);
} else if (BIF_ARG_1 == am_backtrace_depth) {
@@ -5147,17 +5146,11 @@ BIF_RETTYPE send_to_logger_2(BIF_ALIST_2)
else if (len == 0)
buf = "";
else {
-#ifdef DEBUG
ErlDrvSizeT len2;
-#endif
buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, len+1);
-#ifdef DEBUG
len2 =
-#else
- (void)
-#endif
erts_iolist_to_buf(BIF_ARG_2, buf, len);
- ASSERT(len2 == len);
+ ASSERT(len2 == len); (void)len2;
buf[len] = '\0';
switch (BIF_ARG_1) {
case am_info:
diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab
index 7548924178..a770524221 100644
--- a/erts/emulator/beam/bif.tab
+++ b/erts/emulator/beam/bif.tab
@@ -629,7 +629,6 @@ bif maps:from_list/1
bif maps:is_key/2
bif maps:keys/1
bif maps:merge/2
-bif maps:new/0
bif maps:put/3
bif maps:remove/2
bif maps:update/3
diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h
index 7556205063..a1ad75708c 100644
--- a/erts/emulator/beam/big.h
+++ b/erts/emulator/beam/big.h
@@ -42,7 +42,7 @@ typedef Uint16 ErtsHalfDigit;
#undef BIG_HAVE_DOUBLE_DIGIT
typedef Uint32 ErtsHalfDigit;
#else
-#error "can not determine machine size"
+#error "cannot determine machine size"
#endif
typedef Uint dsize_t; /* Vector size type */
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 9ff52c92b8..81531f6cc8 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -108,6 +108,7 @@ process_killer(void)
erts_exit(0, "");
switch(j) {
case 'k':
+ ASSERT(erts_init_process_id != ERTS_INVALID_PID);
/* Send a 'kill' exit signal from init process */
erts_proc_sig_send_exit(NULL, erts_init_process_id,
rp->common.id, am_kill, NIL,
diff --git a/erts/emulator/beam/bs_instrs.tab b/erts/emulator/beam/bs_instrs.tab
index 61eb02a7a2..2dde70c2e1 100644
--- a/erts/emulator/beam/bs_instrs.tab
+++ b/erts/emulator/beam/bs_instrs.tab
@@ -102,6 +102,7 @@ i_bs_get_binary_all2(Fail, Ms, Live, Unit, Dst) {
LIGHT_SWAPIN;
HEAP_SPACE_VERIFIED(0);
ASSERT(is_value(_result));
+ $REFRESH_GEN_DEST();
$Dst = _result;
} else {
HEAP_SPACE_VERIFIED(0);
@@ -123,6 +124,7 @@ i_bs_get_binary2(Fail, Ms, Live, Sz, Flags, Dst) {
if (is_non_value(_result)) {
$FAIL($Fail);
} else {
+ $REFRESH_GEN_DEST();
$Dst = _result;
}
}
@@ -139,6 +141,7 @@ i_bs_get_binary_imm2(Fail, Ms, Live, Sz, Flags, Dst) {
if (is_non_value(_result)) {
$FAIL($Fail);
} else {
+ $REFRESH_GEN_DEST();
$Dst = _result;
}
}
@@ -161,6 +164,7 @@ i_bs_get_float2(Fail, Ms, Live, Sz, Flags, Dst) {
if (is_non_value(_result)) {
$FAIL($Fail);
} else {
+ $REFRESH_GEN_DEST();
$Dst = _result;
}
}
@@ -724,26 +728,34 @@ bs_start_match.execute(Fail, Live, Slots, Dst) {
$FAIL($Fail);
}
header = *boxed_val(context);
- slots = $Slots;
+
+ /* Reserve a slot for the start position. */
+ slots = $Slots + 1;
live = $Live;
+
if (header_is_bin_matchstate(header)) {
ErlBinMatchState* ms = (ErlBinMatchState *) boxed_val(context);
Uint actual_slots = HEADER_NUM_SLOTS(header);
+
+ /* We're not compatible with contexts created by bs_start_match3. */
+ ASSERT(actual_slots >= 1);
+
ms->save_offset[0] = ms->mb.offset;
- if (actual_slots < slots) {
- ErlBinMatchState* dst;
+ if (ERTS_UNLIKELY(actual_slots < slots)) {
+ ErlBinMatchState* expanded;
Uint live = $Live;
Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots);
-
$GC_TEST_PRESERVE(wordsneeded, live, context);
ms = (ErlBinMatchState *) boxed_val(context);
- dst = (ErlBinMatchState *) HTOP;
- *dst = *ms;
+ expanded = (ErlBinMatchState *) HTOP;
+ *expanded = *ms;
*HTOP = HEADER_BIN_MATCHSTATE(slots);
HTOP += wordsneeded;
HEAP_SPACE_VERIFIED(0);
- $Dst = make_matchstate(dst);
+ context = make_matchstate(expanded);
+ $REFRESH_GEN_DEST();
}
+ $Dst = context;
} else if (is_binary_header(header)) {
Eterm result;
Uint wordsneeded = ERL_BIN_MATCHSTATE_SIZE(slots);
@@ -758,6 +770,7 @@ bs_start_match.execute(Fail, Live, Slots, Dst) {
if (is_non_value(result)) {
$FAIL($Fail);
}
+ $REFRESH_GEN_DEST();
$Dst = result;
} else {
$FAIL($Fail);
@@ -906,6 +919,7 @@ i_bs_get_integer(Fail, Live, FlagsAndUnit, Ms, Sz, Dst) {
}
wordsneeded = 1+WSIZE(NBYTES((Uint) size));
$GC_TEST_PRESERVE(wordsneeded, $Live, ms);
+ $REFRESH_GEN_DEST();
}
mb = ms_matchbuffer(ms);
LIGHT_SWAPOUT;
@@ -939,6 +953,7 @@ i_bs_get_utf8(Ctx, Fail, Dst) {
if (is_non_value(result)) {
$FAIL($Fail);
}
+ $REFRESH_GEN_DEST();
$Dst = result;
}
@@ -949,6 +964,7 @@ i_bs_get_utf16(Ctx, Fail, Flags, Dst) {
if (is_non_value(result)) {
$FAIL($Fail);
}
+ $REFRESH_GEN_DEST();
$Dst = result;
}
@@ -1029,10 +1045,289 @@ i_bs_match_string(Ctx, Fail, Bits, Ptr) {
i_bs_save2(Src, Slot) {
ErlBinMatchState* _ms = (ErlBinMatchState*) boxed_val((Eterm) $Src);
+ ASSERT(HEADER_NUM_SLOTS(_ms->thing_word) > $Slot);
_ms->save_offset[$Slot] = _ms->mb.offset;
}
i_bs_restore2(Src, Slot) {
ErlBinMatchState* _ms = (ErlBinMatchState*) boxed_val((Eterm) $Src);
+ ASSERT(HEADER_NUM_SLOTS(_ms->thing_word) > $Slot);
_ms->mb.offset = _ms->save_offset[$Slot];
}
+
+bs_get_tail(Src, Dst, Live) {
+ ErlBinMatchBuffer* mb;
+ Uint size, offs;
+ ErlSubBin* sb;
+ Eterm context;
+
+ context = $Src;
+
+ ASSERT(header_is_bin_matchstate(*boxed_val(context)));
+
+ $GC_TEST_PRESERVE(ERL_SUB_BIN_SIZE, $Live, context);
+
+ mb = ms_matchbuffer(context);
+
+ offs = mb->offset;
+ size = mb->size - offs;
+
+ sb = (ErlSubBin *) HTOP;
+ HTOP += ERL_SUB_BIN_SIZE;
+
+ sb->thing_word = HEADER_SUB_BIN;
+ sb->size = BYTE_OFFSET(size);
+ sb->bitsize = BIT_OFFSET(size);
+ sb->offs = BYTE_OFFSET(offs);
+ sb->bitoffs = BIT_OFFSET(offs);
+ sb->is_writable = 0;
+ sb->orig = mb->orig;
+
+ $REFRESH_GEN_DEST();
+ $Dst = make_binary(sb);
+}
+
+
+%if ARCH_64
+
+i_bs_start_match3_gp(Src, Live, Fail, Dst, Pos) {
+ Eterm context, header;
+ Uint position, live;
+
+ context = $Src;
+ live = $Live;
+
+ if (!is_boxed(context)) {
+ $FAIL($Fail);
+ }
+
+ header = *boxed_val(context);
+
+ if (header_is_bin_matchstate(header)) {
+ ErlBinMatchBuffer *mb;
+
+ ASSERT(HEADER_NUM_SLOTS(header) == 0);
+
+ mb = ms_matchbuffer(context);
+ position = mb->offset;
+
+ $Dst = context;
+ } else if (is_binary_header(header)) {
+ ErlBinMatchState *ms;
+
+ $GC_TEST_PRESERVE(ERL_BIN_MATCHSTATE_SIZE(0), live, context);
+ HEAP_TOP(c_p) = HTOP;
+#ifdef DEBUG
+ c_p->stop = E; /* Needed for checking in HeapOnlyAlloc(). */
+#endif
+ ms = erts_bs_start_match_3(c_p, context);
+ HTOP = HEAP_TOP(c_p);
+ HEAP_SPACE_VERIFIED(0);
+
+ if (ms == NULL) {
+ $FAIL($Fail);
+ }
+
+ $REFRESH_GEN_DEST();
+ $Dst = make_matchstate(ms);
+ position = ms->mb.offset;
+ } else {
+ $FAIL($Fail);
+ }
+
+ ASSERT(IS_USMALL(0, position));
+ $Pos = make_small(position);
+}
+
+i_bs_start_match3(Src, Live, Fail, Dst) {
+ Eterm context, header;
+ Uint live;
+
+ context = $Src;
+ live = $Live;
+
+ if (!is_boxed(context)) {
+ $FAIL($Fail);
+ }
+
+ header = *boxed_val(context);
+
+ if (header_is_bin_matchstate(header)) {
+ ASSERT(HEADER_NUM_SLOTS(header) == 0);
+ $Dst = context;
+ } else if (is_binary_header(header)) {
+ ErlBinMatchState *ms;
+
+ $GC_TEST_PRESERVE(ERL_BIN_MATCHSTATE_SIZE(0), live, context);
+ HEAP_TOP(c_p) = HTOP;
+#ifdef DEBUG
+ c_p->stop = E; /* Needed for checking in HeapOnlyAlloc(). */
+#endif
+ ms = erts_bs_start_match_3(c_p, context);
+ HTOP = HEAP_TOP(c_p);
+ HEAP_SPACE_VERIFIED(0);
+
+ if (ms == NULL) {
+ $FAIL($Fail);
+ }
+
+ $REFRESH_GEN_DEST();
+ $Dst = make_matchstate(ms);
+ } else {
+ $FAIL($Fail);
+ }
+}
+
+bs_set_position(Ctx, Pos) {
+ ErlBinMatchBuffer* mb;
+ Eterm context;
+
+ context = $Ctx;
+ ASSERT(header_is_bin_matchstate(*boxed_val(context)));
+
+ mb = ms_matchbuffer(context);
+ mb->offset = unsigned_val($Pos);
+}
+
+i_bs_get_position(Ctx, Dst) {
+ ErlBinMatchBuffer* mb;
+ Eterm context;
+
+ context = $Ctx;
+ ASSERT(header_is_bin_matchstate(*boxed_val(context)));
+
+ mb = ms_matchbuffer(context);
+ $Dst = make_small(mb->offset);
+}
+
+%else
+
+#
+# Unlike their 64-bit counterparts, the 32-bit position instructions operate on
+# an offset from the "base position" of the context because storing raw
+# positions would lead to the creation of far too many bigints.
+#
+# When a match context is reused we check whether its position fits into an
+# immediate, and create a new match context if it does not. This means we only
+# have to allocate stuff roughly once every 16MB rather than every time we
+# match at a position beyond 16MB.
+#
+
+bs_set_position(Ctx, Pos) {
+ Eterm context, position;
+ ErlBinMatchState *ms;
+
+ context = $Ctx;
+ position = $Pos;
+
+ ASSERT(header_is_bin_matchstate(*boxed_val(context)));
+ ms = (ErlBinMatchState*)boxed_val(context);
+
+ if (ERTS_LIKELY(is_small(position))) {
+ ms->mb.offset = ms->save_offset[0] + unsigned_val(position);
+ } else {
+ ASSERT(is_big(position));
+ ms->mb.offset = ms->save_offset[0] + *BIG_V(big_val(position));
+ }
+}
+
+bs_get_position(Ctx, Dst, Live) {
+ ErlBinMatchState *ms;
+ Eterm context;
+ Uint position;
+
+ context = $Ctx;
+
+ ASSERT(header_is_bin_matchstate(*boxed_val(context)));
+ ms = (ErlBinMatchState*)boxed_val(context);
+
+ position = ms->mb.offset - ms->save_offset[0];
+
+ if (ERTS_LIKELY(IS_USMALL(0, position))) {
+ $Dst = make_small(position);
+ } else {
+ Eterm *hp;
+
+ $GC_TEST_PRESERVE(BIG_UINT_HEAP_SIZE, $Live, context);
+
+ hp = HTOP;
+ HTOP += BIG_UINT_HEAP_SIZE;
+
+ *hp = make_pos_bignum_header(1);
+ BIG_DIGIT(hp, 0) = position;
+
+ $REFRESH_GEN_DEST();
+ $Dst = make_big(hp);
+ }
+}
+
+i_bs_start_match3(Src, Live, Fail, Dst) {
+ Eterm context, header;
+ Uint live;
+
+ context = $Src;
+ live = $Live;
+
+ if (!is_boxed(context)) {
+ $FAIL($Fail);
+ }
+
+ header = *boxed_val(context);
+
+ if (header_is_bin_matchstate(header)) {
+ ErlBinMatchState *current_ms;
+ Uint position;
+
+ ASSERT(HEADER_NUM_SLOTS(header) == 1);
+
+ current_ms = (ErlBinMatchState*)boxed_val(context);
+ position = current_ms->mb.offset - current_ms->save_offset[0];
+
+ if (ERTS_LIKELY(IS_USMALL(0, position))) {
+ $Dst = context;
+ } else {
+ ErlBinMatchState *new_ms;
+
+ $GC_TEST_PRESERVE(ERL_BIN_MATCHSTATE_SIZE(1), live, context);
+ current_ms = (ErlBinMatchState*)boxed_val(context);
+
+ new_ms = (ErlBinMatchState*)HTOP;
+ HTOP += ERL_BIN_MATCHSTATE_SIZE(1);
+
+ new_ms->thing_word = HEADER_BIN_MATCHSTATE(1);
+ new_ms->save_offset[0] = current_ms->mb.offset;
+ new_ms->mb = current_ms->mb;
+
+ $REFRESH_GEN_DEST();
+ $Dst = make_matchstate(new_ms);
+ }
+ } else if (is_binary_header(header)) {
+ Eterm result;
+
+ $GC_TEST_PRESERVE(ERL_BIN_MATCHSTATE_SIZE(1), live, context);
+ HEAP_TOP(c_p) = HTOP;
+
+#ifdef DEBUG
+ c_p->stop = E; /* Needed for checking in HeapOnlyAlloc(). */
+#endif
+
+ /* We intentionally use erts_bs_start_match_2 so that we can use
+ * save_offset as a base for all saved positions on this context,
+ * allowing us to avoid bigints for much longer. */
+ result = erts_bs_start_match_2(c_p, context, 1);
+
+ HTOP = HEAP_TOP(c_p);
+ HEAP_SPACE_VERIFIED(0);
+
+ if (is_non_value(result)) {
+ $FAIL($Fail);
+ }
+
+ $REFRESH_GEN_DEST();
+ $Dst = result;
+ } else {
+ $FAIL($Fail);
+ }
+}
+
+%endif
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index 70474898b2..15642e1669 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -116,11 +116,12 @@ static Export *dist_ctrl_put_data_trap;
/* forward declarations */
-static void clear_dist_entry(DistEntry*);
static int dsig_send_ctl(ErtsDSigData* dsdp, Eterm ctl, int force_busy);
static void send_nodes_mon_msgs(Process *, Eterm, Eterm, Eterm, Eterm);
static void init_nodes_monitors(void);
static Sint abort_connection(DistEntry* dep, Uint32 conn_id);
+static ErtsDistOutputBuf* clear_de_out_queues(DistEntry*);
+static void free_de_out_queues(DistEntry*, ErtsDistOutputBuf*);
static erts_atomic_t no_caches;
static erts_atomic_t no_nodes;
@@ -556,7 +557,10 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
}
}
else { /* Call from distribution controller (port/process) */
- ErtsMonLnkDist *mld;
+ ErtsMonLnkDist *mld;
+ ErtsAtomCache *cache;
+ ErtsProcList *suspendees;
+ ErtsDistOutputBuf *obuf;
Uint32 flags;
erts_atomic_set_mb(&dep->dist_cmd_scheduled, 1);
@@ -570,9 +574,7 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
}
if (dep->state == ERTS_DE_STATE_EXITING) {
-#ifdef DEBUG
ASSERT(erts_atomic32_read_nob(&dep->qflgs) & ERTS_DE_QFLG_EXIT);
-#endif
}
else {
dep->state = ERTS_DE_STATE_EXITING;
@@ -588,6 +590,22 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
nodename = dep->sysname;
flags = dep->flags;
+ erts_atomic_set_nob(&dep->input_handler, (erts_aint_t) NIL);
+ cache = dep->cache;
+ dep->cache = NULL;
+
+ erts_mtx_lock(&dep->qlock);
+
+ erts_atomic64_set_nob(&dep->in, 0);
+ erts_atomic64_set_nob(&dep->out, 0);
+
+ obuf = clear_de_out_queues(dep);
+ suspendees = get_suspended_on_de(dep, ERTS_DE_QFLGS_ALL);
+
+ erts_mtx_unlock(&dep->qlock);
+ erts_atomic_set_nob(&dep->dist_cmd_scheduled, 0);
+ dep->send = NULL;
+
erts_set_dist_entry_not_connected(dep);
erts_de_rwunlock(dep);
@@ -601,7 +619,13 @@ int erts_do_net_exits(DistEntry *dep, Eterm reason)
? am_connection_closed
: reason));
- clear_dist_entry(dep);
+ erts_resume_processes(suspendees);
+
+ delete_cache(cache);
+
+ free_de_out_queues(dep, obuf);
+ if (dep->transcode_ctx)
+ transcode_free_ctx(dep);
}
dec_no_nodes();
@@ -732,41 +756,6 @@ static void free_de_out_queues(DistEntry* dep, ErtsDistOutputBuf *obuf)
}
}
-static void clear_dist_entry(DistEntry *dep)
-{
- ErtsAtomCache *cache;
- ErtsProcList *suspendees;
- ErtsDistOutputBuf *obuf;
-
- erts_de_rwlock(dep);
- erts_atomic_set_nob(&dep->input_handler,
- (erts_aint_t) NIL);
- cache = dep->cache;
- dep->cache = NULL;
-
- erts_mtx_lock(&dep->qlock);
-
- erts_atomic64_set_nob(&dep->in, 0);
- erts_atomic64_set_nob(&dep->out, 0);
-
- obuf = clear_de_out_queues(dep);
- dep->state = ERTS_DE_STATE_IDLE;
- suspendees = get_suspended_on_de(dep, ERTS_DE_QFLGS_ALL);
-
- erts_mtx_unlock(&dep->qlock);
- erts_atomic_set_nob(&dep->dist_cmd_scheduled, 0);
- dep->send = NULL;
- erts_de_rwunlock(dep);
-
- erts_resume_processes(suspendees);
-
- delete_cache(cache);
-
- free_de_out_queues(dep, obuf);
- if (dep->transcode_ctx)
- transcode_free_ctx(dep);
-}
-
int erts_dsend_context_dtor(Binary* ctx_bin)
{
ErtsSendContext* ctx = ERTS_MAGIC_BIN_DATA(ctx_bin);
@@ -861,7 +850,7 @@ erts_dsig_send_m_exit(ErtsDSigData *dsdp, Eterm watcher, Eterm watched,
DeclareTmpHeapNoproc(ctl_heap,6);
int res;
- if (~dsdp->dep->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
+ if (~dsdp->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
/*
* Receiver does not support DOP_MONITOR_P_EXIT (see dsig_send_monitor)
*/
@@ -889,7 +878,7 @@ erts_dsig_send_monitor(ErtsDSigData *dsdp, Eterm watcher, Eterm watched,
DeclareTmpHeapNoproc(ctl_heap,5);
int res;
- if (~dsdp->dep->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
+ if (~dsdp->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
/*
* Receiver does not support DOP_MONITOR_P.
* Just avoid sending it and by doing that reduce this monitor
@@ -920,7 +909,7 @@ erts_dsig_send_demonitor(ErtsDSigData *dsdp, Eterm watcher,
DeclareTmpHeapNoproc(ctl_heap,5);
int res;
- if (~dsdp->dep->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
+ if (~dsdp->flags & (DFLAG_DIST_MONITOR | DFLAG_DIST_MONITOR_NAME)) {
/*
* Receiver does not support DOP_DEMONITOR_P (see dsig_send_monitor)
*/
@@ -940,7 +929,7 @@ erts_dsig_send_demonitor(ErtsDSigData *dsdp, Eterm watcher,
static int can_send_seqtrace_token(ErtsSendContext* ctx, Eterm token) {
Eterm label;
- if (ctx->dep->flags & DFLAG_BIG_SEQTRACE_LABELS) {
+ if (ctx->dsd.flags & DFLAG_BIG_SEQTRACE_LABELS) {
/* The other end is capable of handling arbitrary seq_trace labels. */
return 1;
}
@@ -1001,7 +990,7 @@ erts_dsig_send_msg(Eterm remote, Eterm message, ErtsSendContext* ctx)
send_token = (token != NIL && can_send_seqtrace_token(ctx, token));
- if (ctx->dep->flags & DFLAG_SEND_SENDER) {
+ if (ctx->dsd.flags & DFLAG_SEND_SENDER) {
dist_op = make_small(send_token ?
DOP_SEND_SENDER_TT :
DOP_SEND_SENDER);
@@ -1200,21 +1189,8 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote)
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
-#ifndef HAVE_VALGRIND_PRINTF_XML
-#define VALGRIND_PRINTF_XML VALGRIND_PRINTF
-#endif
-
# define PURIFY_MSG(msg) \
- do { \
- char buf__[1]; size_t bufsz__ = sizeof(buf__); \
- if (erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf__, &bufsz__) >= 0) { \
- VALGRIND_PRINTF_XML("<erlang_error_log>" \
- "%s, line %d: %s</erlang_error_log>\n", \
- __FILE__, __LINE__, msg); \
- } else { \
- VALGRIND_PRINTF("%s, line %d: %s", __FILE__, __LINE__, msg); \
- } \
- } while (0)
+ VALGRIND_PRINTF("%s, line %d: %s", __FILE__, __LINE__, msg)
#else
# define PURIFY_MSG(msg)
#endif
@@ -1231,13 +1207,13 @@ erts_dsig_send_group_leader(ErtsDSigData *dsdp, Eterm leader, Eterm remote)
int erts_net_message(Port *prt,
DistEntry *dep,
+ Uint32 conn_id,
byte *hbuf,
ErlDrvSizeT hlen,
byte *buf,
ErlDrvSizeT len)
{
ErtsDistExternal ede;
- byte *t;
Sint ctl_len;
Eterm arg;
Eterm from, to;
@@ -1255,7 +1231,6 @@ int erts_net_message(Port *prt,
Eterm token_size;
Uint tuple_arity;
int res;
- Uint32 connection_id;
#ifdef ERTS_DIST_MSG_DBG
ErlDrvSizeT orig_len = len;
#endif
@@ -1271,7 +1246,6 @@ int erts_net_message(Port *prt,
return 0;
}
-
ASSERT(hlen == 0);
if (len == 0) { /* HANDLE TICK !!! */
@@ -1284,15 +1258,7 @@ int erts_net_message(Port *prt,
bw(buf, len);
#endif
- if (dep->flags & DFLAG_DIST_HDR_ATOM_CACHE)
- t = buf;
- else {
- /* Skip PASS_THROUGH */
- t = buf+1;
- len--;
- }
-
- res = erts_prepare_dist_ext(&ede, t, len, dep, dep->cache, &connection_id);
+ res = erts_prepare_dist_ext(&ede, buf, len, dep, conn_id, dep->cache);
switch (res) {
case ERTS_PREP_DIST_EXT_CLOSED:
@@ -1334,10 +1300,9 @@ int erts_net_message(Port *prt,
PURIFY_MSG("data error");
goto decode_error;
}
- ctl_len = t - buf;
#ifdef ERTS_DIST_MSG_DBG
- erts_fprintf(stderr, "<<%s CTL: %T\n", len != orig_len ? "P" : " ", arg);
+ erts_fprintf(stderr, "<< CTL: %T\n", arg);
#endif
if (is_not_tuple(arg) ||
@@ -1376,10 +1341,7 @@ int erts_net_message(Port *prt,
from, to);
ASSERT(ldp->a.other.item == to);
ASSERT(eq(ldp->b.other.item, from));
-#ifdef DEBUG
- code =
-#endif
- erts_link_dist_insert(&ldp->a, dep->mld);
+ code = erts_link_dist_insert(&ldp->a, dep->mld);
ASSERT(code);
if (erts_proc_sig_send_link(NULL, to, &ldp->b))
@@ -1387,10 +1349,7 @@ int erts_net_message(Port *prt,
/* Failed to send signal; cleanup and reply noproc... */
-#ifdef DEBUG
- code =
-#endif
- erts_link_dist_delete(&ldp->a);
+ code = erts_link_dist_delete(&ldp->a);
ASSERT(code);
erts_link_release_both(ldp);
}
@@ -1791,7 +1750,7 @@ decode_error:
}
data_error:
UnUseTmpHeapNoproc(DIST_CTL_DEFAULT_SIZE);
- erts_kill_dist_connection(dep, connection_id);
+ erts_kill_dist_connection(dep, conn_id);
ERTS_CHK_NO_PROC_LOCKS;
return -1;
}
@@ -1847,7 +1806,7 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx)
while (1) {
switch (ctx->phase) {
case ERTS_DSIG_SEND_PHASE_INIT:
- ctx->flags = dsdp->dep->flags;
+ ctx->flags = dsdp->flags;
ctx->c_p = dsdp->proc;
if (!ctx->c_p || dsdp->no_suspend)
@@ -1937,6 +1896,12 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx)
ASSERT(ctx->obuf->ext_endp <= &ctx->obuf->data[0] + ctx->data_size);
ctx->data_size = ctx->obuf->ext_endp - ctx->obuf->extp;
+ if (ctx->data_size > (Uint) INT_MAX) {
+ free_dist_obuf(ctx->obuf);
+ ctx->obuf = NULL;
+ retval = ERTS_DSIG_SEND_TOO_LRG;
+ goto done;
+ }
ctx->obuf->hopefull_flags = ctx->u.ec.hopefull_flags;
/*
@@ -2102,13 +2067,14 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf)
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(dist_output)) {
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)),
"%T", prt->common.id);
erts_snprintf(remote_str, sizeof(DTRACE_CHARBUF_NAME(remote_str)),
- "%T", prt->dist_entry->sysname);
+ "%T", dep->sysname);
DTRACE4(dist_output, erts_this_node_sysname, port_str,
remote_str, size);
}
@@ -2164,13 +2130,14 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf)
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(dist_outputv)) {
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)),
"%T", prt->common.id);
erts_snprintf(remote_str, sizeof(DTRACE_CHARBUF_NAME(remote_str)),
- "%T", prt->dist_entry->sysname);
+ "%T", dep->sysname);
DTRACE4(dist_outputv, erts_this_node_sysname, port_str,
remote_str, size);
}
@@ -2208,7 +2175,7 @@ erts_dist_command(Port *prt, int initial_reds)
Uint32 flags;
Sint qsize, obufsize = 0;
ErtsDistOutputQueue oq, foq;
- DistEntry *dep = prt->dist_entry;
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
Uint (*send)(Port *prt, ErtsDistOutputBuf *obuf);
erts_aint32_t sched_flags;
ErtsSchedulerData *esdp = erts_get_scheduler_data();
@@ -2584,11 +2551,12 @@ dist_ctrl_get_data_notification_1(BIF_ALIST_1)
erts_aint32_t qflgs;
erts_aint_t qsize;
Eterm receiver = NIL;
+ Uint32 conn_id;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
- if (erts_dhandle_to_dist_entry(BIF_ARG_1) != dep)
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
BIF_ERROR(BIF_P, BADARG);
/*
@@ -2598,6 +2566,11 @@ dist_ctrl_get_data_notification_1(BIF_ALIST_1)
erts_de_rlock(dep);
+ if (dep->connection_id != conn_id) {
+ erts_de_runlock(dep);
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
ASSERT(dep->cid == BIF_P->common.id);
qflgs = erts_atomic32_read_acqb(&dep->qflgs);
@@ -2638,6 +2611,7 @@ dist_ctrl_put_data_2(BIF_ALIST_2)
DistEntry *dep;
ErlDrvSizeT size;
Eterm input_handler;
+ Uint32 conn_id;
if (is_binary(BIF_ARG_2))
size = binary_size(BIF_ARG_2);
@@ -2649,7 +2623,7 @@ dist_ctrl_put_data_2(BIF_ALIST_2)
else
BIF_ERROR(BIF_P, BADARG);
- dep = erts_dhandle_to_dist_entry(BIF_ARG_1);
+ dep = erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id);
if (!dep)
BIF_ERROR(BIF_P, BADARG);
@@ -2669,7 +2643,7 @@ dist_ctrl_put_data_2(BIF_ALIST_2)
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
- (void) erts_net_message(NULL, dep, NULL, 0, data, size);
+ (void) erts_net_message(NULL, dep, conn_id, NULL, 0, data, size);
/*
* We ignore any decode failures. On fatal failures the
* connection will be taken down by killing the
@@ -2693,13 +2667,18 @@ dist_get_stat_1(BIF_ALIST_1)
Sint64 read, write, pend;
Eterm res, *hp, **hpp;
Uint sz, *szp;
- DistEntry *dep = erts_dhandle_to_dist_entry(BIF_ARG_1);
+ Uint32 conn_id;
+ DistEntry *dep = erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id);
if (!dep)
BIF_ERROR(BIF_P, BADARG);
erts_de_rlock(dep);
+ if (dep->connection_id != conn_id) {
+ erts_de_runlock(dep);
+ BIF_ERROR(BIF_P, BADARG);
+ }
read = (Sint64) erts_atomic64_read_nob(&dep->in);
write = (Sint64) erts_atomic64_read_nob(&dep->out);
pend = (Sint64) erts_atomic_read_nob(&dep->qsize);
@@ -2730,19 +2709,25 @@ BIF_RETTYPE
dist_ctrl_input_handler_2(BIF_ALIST_2)
{
DistEntry *dep = ERTS_PROC_GET_DIST_ENTRY(BIF_P);
+ Uint32 conn_id;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
- if (erts_dhandle_to_dist_entry(BIF_ARG_1) != dep)
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
BIF_ERROR(BIF_P, BADARG);
if (is_not_internal_pid(BIF_ARG_2))
BIF_ERROR(BIF_P, BADARG);
+ erts_de_rlock(dep);
+ if (dep->connection_id != conn_id) {
+ erts_de_runlock(dep);
+ BIF_ERROR(BIF_P, BADARG);
+ }
erts_atomic_set_nob(&dep->input_handler,
(erts_aint_t) BIF_ARG_2);
-
+ erts_de_runlock(dep);
BIF_RET(am_ok);
}
@@ -2756,15 +2741,21 @@ dist_ctrl_get_data_1(BIF_ALIST_1)
Eterm *hp;
ProcBin *pb;
erts_aint_t qsize;
+ Uint32 conn_id;
if (!dep)
BIF_ERROR(BIF_P, EXC_NOTSUP);
- if (erts_dhandle_to_dist_entry(BIF_ARG_1) != dep)
+ if (erts_dhandle_to_dist_entry(BIF_ARG_1, &conn_id) != dep)
BIF_ERROR(BIF_P, BADARG);
erts_de_rlock(dep);
+ if (dep->connection_id != conn_id) {
+ erts_de_runlock(dep);
+ BIF_ERROR(BIF_P, BADARG);
+ }
+
if (dep->state == ERTS_DE_STATE_EXITING)
goto return_none;
@@ -2851,13 +2842,14 @@ erts_dist_port_not_busy(Port *prt)
{
#ifdef USE_VM_PROBES
if (DTRACE_ENABLED(dist_port_not_busy)) {
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
DTRACE_CHARBUF(port_str, 64);
DTRACE_CHARBUF(remote_str, 64);
erts_snprintf(port_str, sizeof(DTRACE_CHARBUF_NAME(port_str)),
"%T", prt->common.id);
erts_snprintf(remote_str, sizeof(DTRACE_CHARBUF_NAME(remote_str)),
- "%T", prt->dist_entry->sysname);
+ "%T", dep->sysname);
DTRACE3(dist_port_not_busy, erts_this_node_sysname,
port_str, remote_str);
}
@@ -2883,10 +2875,10 @@ static void kill_connection(DistEntry *dep)
}
void
-erts_kill_dist_connection(DistEntry *dep, Uint32 connection_id)
+erts_kill_dist_connection(DistEntry *dep, Uint32 conn_id)
{
erts_de_rwlock(dep);
- if (connection_id == dep->connection_id
+ if (conn_id == dep->connection_id
&& dep->state == ERTS_DE_STATE_CONNECTED) {
kill_connection(dep);
@@ -3222,23 +3214,6 @@ BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
else if (!dep)
goto system_limit; /* Should never happen!!! */
- erts_de_rlock(dep);
- de_locked = -1;
-
- if (dep->state == ERTS_DE_STATE_EXITING) {
- /* Suspend on dist entry waiting for the exit to finish */
- ErtsProcList *plp = erts_proclist_create(BIF_P);
- plp->next = NULL;
- erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, NULL);
- erts_mtx_lock(&dep->qlock);
- erts_proclist_store_last(&dep->suspended, plp);
- erts_mtx_unlock(&dep->qlock);
- goto yield;
- }
-
- erts_de_runlock(dep);
- de_locked = 0;
-
if (is_internal_pid(BIF_ARG_2)) {
if (BIF_P->common.id == BIF_ARG_2) {
ErtsSetupConnDistCtrl scdc;
@@ -3284,7 +3259,7 @@ BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
hp = HAlloc(BIF_P, 3);
}
else {
- int new;
+ Uint32 conn_id;
pp = erts_id2port_sflgs(BIF_ARG_2,
BIF_P,
@@ -3293,7 +3268,7 @@ BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
erts_de_rwlock(dep);
de_locked = 1;
- if (dep->state == ERTS_DE_STATE_EXITING)
+ if (dep->state != ERTS_DE_STATE_PENDING)
goto badarg;
if (!pp || (erts_atomic32_read_nob(&pp->state)
@@ -3303,49 +3278,39 @@ BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
if ((pp->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY) == 0)
goto badarg;
- if (dep->cid == BIF_ARG_2 && pp->dist_entry == dep)
- new = 0;
- else {
- if (dep->state != ERTS_DE_STATE_PENDING) {
- if (dep->state == ERTS_DE_STATE_IDLE)
- erts_set_dist_entry_pending(dep);
- else
- goto badarg;
- }
-
- if (pp->dist_entry || is_not_nil(dep->cid))
- goto badarg;
-
- erts_atomic32_read_bor_nob(&pp->state, ERTS_PORT_SFLG_DISTRIBUTION);
+ if (erts_prtsd_get(pp, ERTS_PRTSD_DIST_ENTRY) != NULL
+ || is_not_nil(dep->cid))
+ goto badarg;
- pp->dist_entry = dep;
+ erts_atomic32_read_bor_nob(&pp->state, ERTS_PORT_SFLG_DISTRIBUTION);
- ASSERT(pp->drv_ptr->outputv || pp->drv_ptr->output);
+ erts_prtsd_set(pp, ERTS_PRTSD_DIST_ENTRY, dep);
+ erts_prtsd_set(pp, ERTS_PRTSD_CONN_ID, (void*)(UWord)dep->connection_id);
- dep->send = (pp->drv_ptr->outputv
- ? dist_port_commandv
- : dist_port_command);
- ASSERT(dep->send);
+ ASSERT(pp->drv_ptr->outputv || pp->drv_ptr->output);
- /*
- * Dist-ports do not use the "busy port message queue" functionality, but
- * instead use "busy dist entry" functionality.
- */
- {
- ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
- erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL);
- }
+ dep->send = (pp->drv_ptr->outputv
+ ? dist_port_commandv
+ : dist_port_command);
+ ASSERT(dep->send);
- setup_connection_epiloge_rwunlock(BIF_P, dep, BIF_ARG_2, flags, version);
- de_locked = 0;
- new = !0;
+ /*
+ * Dist-ports do not use the "busy port message queue" functionality, but
+ * instead use "busy dist entry" functionality.
+ */
+ {
+ ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED;
+ erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL);
}
- hp = HAlloc(BIF_P, 3 + ERTS_MAGIC_REF_THING_SIZE);
- res = erts_build_dhandle(&hp, &BIF_P->off_heap, dep);
+ conn_id = dep->connection_id;
+ setup_connection_epiloge_rwunlock(BIF_P, dep, BIF_ARG_2, flags, version);
+ de_locked = 0;
+
+ hp = HAlloc(BIF_P, 3 + ERTS_DHANDLE_SIZE);
+ res = erts_build_dhandle(&hp, &BIF_P->off_heap, dep, conn_id);
res_tag = am_ok; /* Connection up */
- if (new)
- dep = NULL; /* inc of refc transferred to port (dist_entry field) */
+ dep = NULL; /* inc of refc transferred to port (dist_entry field) */
}
ASSERT(is_value(res) && is_value(res_tag));
@@ -3371,12 +3336,6 @@ BIF_RETTYPE erts_internal_create_dist_channel_4(BIF_ALIST_4)
return ret;
- yield:
- ERTS_BIF_PREP_YIELD4(ret,
- bif_export[BIF_erts_internal_create_dist_channel_4],
- BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3, BIF_ARG_4);
- goto done;
-
badarg:
ERTS_BIF_PREP_RET(ret, am_badarg);
goto done;
@@ -3398,8 +3357,7 @@ setup_connection_epiloge_rwunlock(Process *c_p, DistEntry *dep,
dep->creation = 0;
ASSERT(is_internal_port(ctrlr) || is_internal_pid(ctrlr));
- ASSERT(erts_atomic_read_nob(&dep->qsize) == 0
- || (dep->state == ERTS_DE_STATE_PENDING));
+ ASSERT(dep->state == ERTS_DE_STATE_PENDING);
if (flags & DFLAG_DIST_HDR_ATOM_CACHE)
create_cache(dep);
@@ -3445,37 +3403,20 @@ setup_connection_distctrl(Process *c_p, void *arg, int *redsp, ErlHeapFragment *
DistEntry *dep = scdcp->dep;
int dep_locked = 0;
Eterm *hp;
- erts_aint32_t state;
+ Uint32 conn_id;
if (redsp)
*redsp = 1;
- state = erts_atomic32_read_nob(&c_p->state);
-
- if (state & ERTS_PSFLG_EXITING)
- goto badarg;
+ ASSERT(!ERTS_PROC_IS_EXITING(c_p));
erts_de_rwlock(dep);
dep_locked = !0;
- if (dep->state == ERTS_DE_STATE_EXITING)
- goto badarg;
-
- if (ERTS_PROC_GET_DIST_ENTRY(c_p)) {
- if (dep == ERTS_PROC_GET_DIST_ENTRY(c_p)
- && (c_p->flags & F_DISTRIBUTION)
- && dep->cid == c_p->common.id) {
- goto connected;
- }
+ if (dep->state != ERTS_DE_STATE_PENDING)
goto badarg;
- }
- if (dep->state != ERTS_DE_STATE_PENDING) {
- if (dep->state == ERTS_DE_STATE_IDLE)
- erts_set_dist_entry_pending(dep);
- else
- goto badarg;
- }
+ conn_id = dep->connection_id;
if (is_not_nil(dep->cid))
goto badarg;
@@ -3490,18 +3431,17 @@ setup_connection_distctrl(Process *c_p, void *arg, int *redsp, ErlHeapFragment *
setup_connection_epiloge_rwunlock(c_p, dep, c_p->common.id,
scdcp->flags, scdcp->version);
-connected:
/* we take over previous inc in refc of dep */
if (!bpp) /* called directly... */
- return erts_make_dhandle(c_p, dep);
+ return erts_make_dhandle(c_p, dep, conn_id);
erts_free(ERTS_ALC_T_SETUP_CONN_ARG, arg);
- *bpp = new_message_buffer(ERTS_MAGIC_REF_THING_SIZE);
+ *bpp = new_message_buffer(ERTS_DHANDLE_SIZE);
hp = (*bpp)->mem;
- return erts_build_dhandle(&hp, &(*bpp)->off_heap, dep);
+ return erts_build_dhandle(&hp, &(*bpp)->off_heap, dep, conn_id);
badarg:
@@ -3542,34 +3482,30 @@ BIF_RETTYPE erts_internal_new_connection_1(BIF_ALIST_1)
erts_de_rwlock(dep);
switch (dep->state) {
- case ERTS_DE_STATE_PENDING:
case ERTS_DE_STATE_CONNECTED:
+ case ERTS_DE_STATE_EXITING:
+ case ERTS_DE_STATE_PENDING:
conn_id = dep->connection_id;
break;
case ERTS_DE_STATE_IDLE:
erts_set_dist_entry_pending(dep);
conn_id = dep->connection_id;
break;
- case ERTS_DE_STATE_EXITING:
- conn_id = (dep->connection_id + 1) & ERTS_DIST_CON_ID_MASK;
- break;
default:
erts_exit(ERTS_ABORT_EXIT, "Invalid dep->state (%d)\n", dep->state);
}
erts_de_rwunlock(dep);
- hp = HAlloc(BIF_P, 3 + ERTS_MAGIC_REF_THING_SIZE);
- dhandle = erts_build_dhandle(&hp, &BIF_P->off_heap, dep);
+ hp = HAlloc(BIF_P, ERTS_DHANDLE_SIZE);
+ dhandle = erts_build_dhandle(&hp, &BIF_P->off_heap, dep, conn_id);
erts_deref_dist_entry(dep);
- BIF_RET(TUPLE2(hp, make_small(conn_id), dhandle));
+ BIF_RET(dhandle);
}
-static Sint abort_connection(DistEntry* dep, Uint32 conn_id)
+Sint erts_abort_connection_rwunlock(DistEntry* dep)
{
- erts_de_rwlock(dep);
+ ERTS_LC_ASSERT(erts_lc_is_de_rwlocked(dep));
- if (dep->connection_id != conn_id)
- ;
- else if (dep->state == ERTS_DE_STATE_CONNECTED) {
+ if (dep->state == ERTS_DE_STATE_CONNECTED) {
kill_connection(dep);
}
else if (dep->state == ERTS_DE_STATE_PENDING) {
@@ -3598,7 +3534,6 @@ static Sint abort_connection(DistEntry* dep, Uint32 conn_id)
dep->send = NULL;
erts_set_dist_entry_not_connected(dep);
-
erts_de_rwunlock(dep);
schedule_con_monitor_link_cleanup(mld, THE_NON_VALUE,
@@ -3611,42 +3546,37 @@ static Sint abort_connection(DistEntry* dep, Uint32 conn_id)
delete_cache(cache);
free_de_out_queues(dep, obuf);
-
- /*
- * We wait to make DistEntry idle and accept new connection attempts
- * until all is cleared and deallocated. This to get some back pressure
- * against repeated failing connection attempts saturating all CPUs
- * with cleanup jobs.
- */
- erts_de_rwlock(dep);
- ASSERT(dep->state == ERTS_DE_STATE_EXITING);
- dep->state = ERTS_DE_STATE_IDLE;
- erts_de_rwunlock(dep);
return reds;
}
erts_de_rwunlock(dep);
return 0;
}
+static Sint abort_connection(DistEntry *dep, Uint32 conn_id)
+{
+ erts_de_rwlock(dep);
+ if (dep->connection_id == conn_id)
+ return erts_abort_connection_rwunlock(dep);
+ erts_de_rwunlock(dep);
+ return 0;
+}
+
BIF_RETTYPE erts_internal_abort_connection_2(BIF_ALIST_2)
{
DistEntry* dep;
- Eterm* tp;
+ Uint32 conn_id;
+ Sint reds;
- if (is_not_atom(BIF_ARG_1) || is_not_tuple_arity(BIF_ARG_2, 2)) {
- BIF_ERROR(BIF_P, BADARG);
- }
- tp = tuple_val(BIF_ARG_2);
- dep = erts_dhandle_to_dist_entry(tp[2]);
- if (is_not_small(tp[1]) || dep != erts_find_dist_entry(BIF_ARG_1)
+ if (is_not_atom(BIF_ARG_1))
+ BIF_ERROR(BIF_P, BADARG);
+ dep = erts_dhandle_to_dist_entry(BIF_ARG_2, &conn_id);
+ if (!dep || dep != erts_find_dist_entry(BIF_ARG_1)
|| dep == erts_this_dist_entry) {
BIF_ERROR(BIF_P, BADARG);
}
- if (dep) {
- Sint reds = abort_connection(dep, unsigned_val(tp[1]));
- BUMP_REDS(BIF_P, reds);
- }
+ reds = abort_connection(dep, conn_id);
+ BUMP_REDS(BIF_P, reds);
BIF_RET(am_true);
}
@@ -3677,14 +3607,14 @@ int erts_auto_connect(DistEntry* dep, Process *proc, ErtsProcLocks proc_locks)
}
/*
- * Send {auto_connect, Node, ConnId, DHandle} to net_kernel
+ * Send {auto_connect, Node, DHandle} to net_kernel
*/
mp = erts_alloc_message_heap(net_kernel, &nk_locks,
- 5 + ERTS_MAGIC_REF_THING_SIZE,
+ 4 + ERTS_DHANDLE_SIZE,
&hp, &ohp);
- dhandle = erts_build_dhandle(&hp, ohp, dep);
- msg = TUPLE4(hp, am_auto_connect, dep->sysname, make_small(conn_id),
- dhandle);
+ dhandle = erts_build_dhandle(&hp, ohp, dep, conn_id);
+ msg = TUPLE3(hp, am_auto_connect, dep->sysname, dhandle);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(proc, net_kernel, nk_locks, mp, msg);
erts_proc_unlock(net_kernel, nk_locks);
}
@@ -3949,28 +3879,22 @@ monitor_node(Process* p, Eterm Node, Eterm Bool, Eterm Options)
Node);
mdep = (ErtsMonitorDataExtended *) erts_monitor_to_data(mon);
if (created) {
-#ifdef DEBUG
int inserted =
-#endif
erts_monitor_dist_insert(&mdep->md.target, dep->mld);
- ASSERT(inserted);
+ ASSERT(inserted); (void)inserted;
ASSERT(mdep->dist->connection_id == dep->connection_id);
}
else if (mdep->dist->connection_id != dep->connection_id) {
ErtsMonitorDataExtended *mdep2;
ErtsMonitor *mon2;
-#ifdef DEBUG
int inserted;
-#endif
mdep2 = ((ErtsMonitorDataExtended *)
erts_monitor_create(ERTS_MON_TYPE_NODE, NIL,
p->common.id, Node, NIL));
mon2 = &mdep2->md.origin;
-#ifdef DEBUG
inserted =
-#endif
erts_monitor_dist_insert(&mdep->md.target, dep->mld);
- ASSERT(inserted);
+ ASSERT(inserted); (void)inserted;
ASSERT(mdep2->dist->connection_id == dep->connection_id);
mdep2->uptr.node_monitors = mdep->uptr.node_monitors;
diff --git a/erts/emulator/beam/dist.h b/erts/emulator/beam/dist.h
index dda2029a4c..845fab229a 100644
--- a/erts/emulator/beam/dist.h
+++ b/erts/emulator/beam/dist.h
@@ -136,6 +136,7 @@ typedef struct {
Eterm cid;
Eterm connection_id;
int no_suspend;
+ Uint32 flags;
} ErtsDSigData;
#define ERTS_DE_BUSY_LIMIT (1024*1024)
@@ -235,6 +236,7 @@ retry:
dsdp->cid = dep->cid;
dsdp->connection_id = dep->connection_id;
dsdp->no_suspend = no_suspend;
+ dsdp->flags = dep->flags;
if (dspl == ERTS_DSP_NO_LOCK)
erts_de_runlock(dep);
return res;
@@ -254,9 +256,9 @@ void erts_schedule_dist_command(Port *prt, DistEntry *dist_entry)
ERTS_LC_ASSERT(erts_lc_is_port_locked(prt));
ASSERT((erts_atomic32_read_nob(&prt->state)
& ERTS_PORT_SFLGS_DEAD) == 0);
- ASSERT(prt->dist_entry);
- dep = prt->dist_entry;
+ dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
+ ASSERT(dep);
id = prt->common.id;
}
else {
@@ -376,6 +378,7 @@ typedef struct {
#define ERTS_DSIG_SEND_OK 0
#define ERTS_DSIG_SEND_YIELD 1
#define ERTS_DSIG_SEND_CONTINUE 2
+#define ERTS_DSIG_SEND_TOO_LRG 3
extern int erts_dsig_send_link(ErtsDSigData *, Eterm, Eterm);
extern int erts_dsig_send_msg(Eterm, Eterm, ErtsSendContext*);
@@ -399,5 +402,7 @@ extern void erts_kill_dist_connection(DistEntry *dep, Uint32);
extern Uint erts_dist_cache_size(void);
+extern Sint erts_abort_connection_rwunlock(DistEntry *dep);
+
#endif
diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c
index 166d5c48a5..e6169ebeaa 100644
--- a/erts/emulator/beam/erl_alloc.c
+++ b/erts/emulator/beam/erl_alloc.c
@@ -111,7 +111,7 @@ typedef union {
char align_afa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AFAllctr_t))];
AOFFAllctr_t aoffa;
char align_aoffa[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(AOFFAllctr_t))];
-} ErtsAllocatorState_t;
+} ErtsAllocatorState_t erts_align_attribute(ERTS_CACHE_LINE_SIZE);
static ErtsAllocatorState_t std_alloc_state;
static ErtsAllocatorState_t ll_alloc_state;
@@ -4041,7 +4041,7 @@ debug_realloc(ErtsAlcType_t type, void *extra, void *ptr, Uint size)
erts_hdbg_chk_blks();
#endif
- if (old_size > size)
+ if (ptr && old_size > size)
sys_memset((void *) (((char *) ptr) + size),
0xf,
sizeof(Uint) + old_size - size);
@@ -4072,6 +4072,9 @@ debug_free(ErtsAlcType_t type, void *extra, void *ptr)
ASSERT(ERTS_ALC_N_MIN <= n && n <= ERTS_ALC_N_MAX);
+ if (!ptr)
+ return;
+
dptr = check_memory_fence(ptr, &size, n, ERTS_ALC_O_FREE);
#ifdef ERTS_ALC_A_EXEC
diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types
index 5409b89bab..f1e99820af 100644
--- a/erts/emulator/beam/erl_alloc.types
+++ b/erts/emulator/beam/erl_alloc.types
@@ -30,10 +30,10 @@
# name space).
# * Types, allocators, classes, and descriptions have different name
# spaces.
-# * The type, allocator, and class names INVALID are reserved and can
-# not be used.
+# * The type, allocator, and class names INVALID are reserved and
+# cannot be used.
# * The descriptions invalid_allocator, invalid_class, and invalid_type
-# are reserved and can not be used.
+# are reserved and cannot be used.
# * Declarations can be done conditionally by use of a
# +if <boolean_variable>
#
diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c
index a2610bf2e1..d465f6c6b9 100644
--- a/erts/emulator/beam/erl_bif_binary.c
+++ b/erts/emulator/beam/erl_bif_binary.c
@@ -208,8 +208,8 @@ typedef struct _ac_trie {
typedef struct _bm_data {
byte *x;
Sint len;
+ Sint *badshift;
Sint *goodshift;
- Sint badshift[ALPHABET_SIZE];
} BMData;
typedef struct _ac_find_all_state {
@@ -319,16 +319,104 @@ static void dump_ac_node(ACNode *node, int indent, int ch);
* The needed size of binary data for a search structure - given the
* accumulated string lengths.
*/
-#define BM_SIZE(StrLen) /* StrLen: length of searchstring */ \
-((MYALIGN(sizeof(Sint) * (StrLen))) + /* goodshift array */ \
- MYALIGN(StrLen) + /* searchstring saved */ \
- (MYALIGN(sizeof(BMData)))) /* Structure */
+#define BM_SIZE_SINGLE() /* Single byte search string */ \
+(MYALIGN(1) + /* searchstring saved */ \
+ (MYALIGN(sizeof(BMData)))) /* Structure */
+
+#define BM_SIZE_MULTI(StrLen) /* StrLen: length of searchstring */ \
+((MYALIGN(sizeof(Uint) * (StrLen))) + /* goodshift array */ \
+ (MYALIGN(sizeof(Uint) * ALPHABET_SIZE)) + /* badshift array */ \
+ MYALIGN(StrLen) + /* searchstring saved */ \
+ (MYALIGN(sizeof(BMData)))) /* Structure */
#define AC_SIZE(StrLens) /* StrLens: sum of all searchstring lengths */ \
((MYALIGN(sizeof(ACNode)) * \
((StrLens)+1)) + /* The actual nodes (including rootnode) */ \
MYALIGN(sizeof(ACTrie))) /* Structure */
+/*
+ * Boyer Moore - most obviously implemented more or less exactly as
+ * Christian Charras and Thierry Lecroq describe it in "Handbook of
+ * Exact String-Matching Algorithms"
+ * http://www-igm.univ-mlv.fr/~lecroq/string/
+ */
+
+/*
+ * Call this to compute badshifts array
+ */
+static void compute_badshifts(BMData *bmd)
+{
+ Sint i;
+ Sint m = bmd->len;
+
+ for (i = 0; i < ALPHABET_SIZE; ++i) {
+ bmd->badshift[i] = m;
+ }
+ for (i = 0; i < m - 1; ++i) {
+ bmd->badshift[bmd->x[i]] = m - i - 1;
+ }
+}
+
+/* Helper for "compute_goodshifts" */
+static void compute_suffixes(byte *x, Sint m, Sint *suffixes)
+{
+ int f,g,i;
+
+ suffixes[m - 1] = m;
+
+ f = 0; /* To avoid use before set warning */
+
+ g = m - 1;
+
+ for (i = m - 2; i >= 0; --i) {
+ if (i > g && suffixes[i + m - 1 - f] < i - g) {
+ suffixes[i] = suffixes[i + m - 1 - f];
+ } else {
+ if (i < g) {
+ g = i;
+ }
+ f = i;
+ while ( g >= 0 && x[g] == x[g + m - 1 - f] ) {
+ --g;
+ }
+ suffixes[i] = f - g;
+ }
+ }
+}
+
+/*
+ * Call this to compute goodshift array
+ */
+static void compute_goodshifts(BMData *bmd)
+{
+ Sint m = bmd->len;
+ byte *x = bmd->x;
+ Sint i, j;
+ Sint *suffixes = erts_alloc(ERTS_ALC_T_TMP, m * sizeof(Sint));
+
+ compute_suffixes(x, m, suffixes);
+
+ for (i = 0; i < m; ++i) {
+ bmd->goodshift[i] = m;
+ }
+
+ j = 0;
+
+ for (i = m - 1; i >= -1; --i) {
+ if (i == -1 || suffixes[i] == i + 1) {
+ while (j < m - 1 - i) {
+ if (bmd->goodshift[j] == m) {
+ bmd->goodshift[j] = m - 1 - i;
+ }
+ ++j;
+ }
+ }
+ }
+ for (i = 0; i <= m - 2; ++i) {
+ bmd->goodshift[m - 1 - suffixes[i]] = m - 1 - i;
+ }
+ erts_free(ERTS_ALC_T_TMP, suffixes);
+}
/*
* Callback for the magic binary
@@ -377,20 +465,37 @@ static ACTrie *create_acdata(MyAllocator *my, Uint len,
/*
* The same initialization of allocator and basic data for Boyer-Moore.
+ * For single byte, we don't use goodshift and badshift, only memchr.
*/
static BMData *create_bmdata(MyAllocator *my, byte *x, Uint len,
Binary **the_bin /* out */)
{
- Uint datasize = BM_SIZE(len);
+ Uint datasize;
BMData *bmd;
- Binary *mb = erts_create_magic_binary(datasize,cleanup_my_data_bm);
- byte *data = ERTS_MAGIC_BIN_DATA(mb);
+ Binary *mb;
+ byte *data;
+
+ if(len > 1) {
+ datasize = BM_SIZE_MULTI(len);
+ } else {
+ datasize = BM_SIZE_SINGLE();
+ }
+
+ mb = erts_create_magic_binary(datasize,cleanup_my_data_bm);
+ data = ERTS_MAGIC_BIN_DATA(mb);
init_my_allocator(my, datasize, data);
bmd = my_alloc(my, sizeof(BMData));
bmd->x = my_alloc(my,len);
sys_memcpy(bmd->x,x,len);
bmd->len = len;
- bmd->goodshift = my_alloc(my,sizeof(Uint) * len);
+
+ if(len > 1) {
+ bmd->goodshift = my_alloc(my, sizeof(Uint) * len);
+ bmd->badshift = my_alloc(my, sizeof(Uint) * ALPHABET_SIZE);
+ compute_badshifts(bmd);
+ compute_goodshifts(bmd);
+ }
+
*the_bin = mb;
return bmd;
}
@@ -711,91 +816,8 @@ static BFReturn ac_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
return (m == 0) ? BF_NOT_FOUND : BF_OK;
}
-/*
- * Boyer Moore - most obviously implemented more or less exactly as
- * Christian Charras and Thierry Lecroq describe it in "Handbook of
- * Exact String-Matching Algorithms"
- * http://www-igm.univ-mlv.fr/~lecroq/string/
- */
-
-/*
- * Call this to compute badshifts array
- */
-static void compute_badshifts(BMData *bmd)
-{
- Sint i;
- Sint m = bmd->len;
-
- for (i = 0; i < ALPHABET_SIZE; ++i) {
- bmd->badshift[i] = m;
- }
- for (i = 0; i < m - 1; ++i) {
- bmd->badshift[bmd->x[i]] = m - i - 1;
- }
-}
-
-/* Helper for "compute_goodshifts" */
-static void compute_suffixes(byte *x, Sint m, Sint *suffixes)
-{
- int f,g,i;
-
- suffixes[m - 1] = m;
-
- f = 0; /* To avoid use before set warning */
-
- g = m - 1;
-
- for (i = m - 2; i >= 0; --i) {
- if (i > g && suffixes[i + m - 1 - f] < i - g) {
- suffixes[i] = suffixes[i + m - 1 - f];
- } else {
- if (i < g) {
- g = i;
- }
- f = i;
- while ( g >= 0 && x[g] == x[g + m - 1 - f] ) {
- --g;
- }
- suffixes[i] = f - g;
- }
- }
-}
-
-/*
- * Call this to compute goodshift array
- */
-static void compute_goodshifts(BMData *bmd)
-{
- Sint m = bmd->len;
- byte *x = bmd->x;
- Sint i, j;
- Sint *suffixes = erts_alloc(ERTS_ALC_T_TMP, m * sizeof(Sint));
-
- compute_suffixes(x, m, suffixes);
-
- for (i = 0; i < m; ++i) {
- bmd->goodshift[i] = m;
- }
-
- j = 0;
-
- for (i = m - 1; i >= -1; --i) {
- if (i == -1 || suffixes[i] == i + 1) {
- while (j < m - 1 - i) {
- if (bmd->goodshift[j] == m) {
- bmd->goodshift[j] = m - 1 - i;
- }
- ++j;
- }
- }
- }
- for (i = 0; i <= m - 2; ++i) {
- bmd->goodshift[m - 1 - suffixes[i]] = m - 1 - i;
- }
- erts_free(ERTS_ALC_T_TMP, suffixes);
-}
-
#define BM_LOOP_FACTOR 10 /* Should we have a higher value? */
+#define MC_LOOP_FACTOR 8
static void bm_init_find_first_match(BinaryFindContext *ctx)
{
@@ -819,13 +841,38 @@ static BFReturn bm_find_first_match(BinaryFindContext *ctx, byte *haystack)
Sint i;
Sint j = state->pos;
register Uint reds = *reductions;
+ byte *pos_pointer;
+ Sint needle_last = blen - 1;
+ Sint mem_read = len - needle_last - j;
- while (j <= len - blen) {
+ if (mem_read <= 0) {
+ return BF_NOT_FOUND;
+ }
+ mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR);
+ ASSERT(mem_read > 0);
+
+ pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read);
+ if (pos_pointer == NULL) {
+ reds -= mem_read / MC_LOOP_FACTOR;
+ j += mem_read;
+ } else {
+ reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR;
+ j = pos_pointer - haystack - needle_last;
+ }
+
+ // Ensure we have at least one reduction before entering the loop
+ ++reds;
+
+ for(;;) {
+ if (j > len - blen) {
+ *reductions = reds;
+ return BF_NOT_FOUND;
+ }
if (--reds == 0) {
state->pos = j;
return BF_RESTART;
}
- for (i = blen - 1; i >= 0 && needle[i] == haystack[i + j]; --i)
+ for (i = needle_last; i >= 0 && needle[i] == haystack[i + j]; --i)
;
if (i < 0) { /* found */
*reductions = reds;
@@ -835,8 +882,6 @@ static BFReturn bm_find_first_match(BinaryFindContext *ctx, byte *haystack)
}
j += MAX(gs[i],bs[haystack[i+j]] - blen + 1 + i);
}
- *reductions = reds;
- return BF_NOT_FOUND;
}
static void bm_init_find_all(BinaryFindContext *ctx)
@@ -875,14 +920,38 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
Sint *gs = bmd->goodshift;
Sint *bs = bmd->badshift;
byte *needle = bmd->x;
- Sint i;
+ Sint i = -1; /* Use memchr on start and on every match */
Sint j = state->pos;
Uint m = state->m;
Uint allocated = state->allocated;
FindallData *out = state->out;
register Uint reds = *reductions;
+ byte *pos_pointer;
+ Sint needle_last = blen - 1;
+ Sint mem_read;
- while (j <= len - blen) {
+ for(;;) {
+ if (i < 0) {
+ mem_read = len - needle_last - j;
+ if(mem_read <= 0) {
+ goto done;
+ }
+ mem_read = MIN(mem_read, reds * MC_LOOP_FACTOR);
+ ASSERT(mem_read > 0);
+ pos_pointer = memchr(&haystack[j + needle_last], needle[needle_last], mem_read);
+ if (pos_pointer == NULL) {
+ reds -= mem_read / MC_LOOP_FACTOR;
+ j += mem_read;
+ } else {
+ reds -= (pos_pointer - &haystack[j]) / MC_LOOP_FACTOR;
+ j = pos_pointer - haystack - needle_last;
+ }
+ // Ensure we have at least one reduction when resuming the loop
+ ++reds;
+ }
+ if (j > len - blen) {
+ goto done;
+ }
if (--reds == 0) {
state->pos = j;
state->m = m;
@@ -890,7 +959,7 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
state->out = out;
return BF_RESTART;
}
- for (i = blen - 1; i >= 0 && needle[i] == haystack[i + j]; --i)
+ for (i = needle_last; i >= 0 && needle[i] == haystack[i + j]; --i)
;
if (i < 0) { /* found */
if (m >= allocated) {
@@ -912,6 +981,7 @@ static BFReturn bm_find_all_non_overlapping(BinaryFindContext *ctx, byte *haysta
j += MAX(gs[i],bs[haystack[i+j]] - blen + 1 + i);
}
}
+ done:
state->m = m;
state->out = out;
*reductions = reds;
@@ -931,6 +1001,7 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
Eterm t, b, comp_term = NIL;
Uint characters;
Uint words;
+ Uint size;
characters = 0;
words = 0;
@@ -946,11 +1017,12 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
if (binary_bitsize(b) != 0) {
goto badarg;
}
- if (binary_size(b) == 0) {
+ size = binary_size(b);
+ if (size == 0) {
goto badarg;
}
++words;
- characters += binary_size(b);
+ characters += size;
}
if (is_not_nil(t)) {
goto badarg;
@@ -979,16 +1051,13 @@ static int do_binary_match_compile(Eterm argument, Eterm *tag, Binary **binp)
Uint bitoffs, bitsize;
byte *temp_alloc = NULL;
MyAllocator my;
- BMData *bmd;
Binary *bin;
ERTS_GET_BINARY_BYTES(comp_term, bytes, bitoffs, bitsize);
if (bitoffs != 0) {
bytes = erts_get_aligned_binary_bytes(comp_term, &temp_alloc);
}
- bmd = create_bmdata(&my, bytes, characters, &bin);
- compute_badshifts(bmd);
- compute_goodshifts(bmd);
+ create_bmdata(&my, bytes, characters, &bin);
erts_free_aligned_binary_bytes(temp_alloc);
CHECK_ALLOCATOR(my);
*tag = am_bm;
@@ -3012,17 +3081,19 @@ static void dump_bm_data(BMData *bm)
}
}
erts_printf(">>\n");
- erts_printf("GoodShift array:\n");
- for (i = 0; i < bm->len; ++i) {
- erts_printf("GoodShift[%d]: %ld\n", i, bm->goodshift[i]);
- }
- erts_printf("BadShift array:\n");
- j = 0;
- for (i = 0; i < ALPHABET_SIZE; i += j) {
- for (j = 0; i + j < ALPHABET_SIZE && j < 6; ++j) {
- erts_printf("BS[%03d]:%02ld, ", i+j, bm->badshift[i+j]);
+ if(bm->len > 1) {
+ erts_printf("GoodShift array:\n");
+ for (i = 0; i < bm->len; ++i) {
+ erts_printf("GoodShift[%d]: %ld\n", i, bm->goodshift[i]);
+ }
+ erts_printf("BadShift array:\n");
+ j = 0;
+ for (i = 0; i < ALPHABET_SIZE; i += j) {
+ for (j = 0; i + j < ALPHABET_SIZE && j < 6; ++j) {
+ erts_printf("BS[%03d]:%02ld, ", i+j, bm->badshift[i+j]);
+ }
+ erts_printf("\n");
}
- erts_printf("\n");
}
}
diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c
index 4cda0948a0..639aee29dc 100644
--- a/erts/emulator/beam/erl_bif_ddll.c
+++ b/erts/emulator/beam/erl_bif_ddll.c
@@ -829,7 +829,7 @@ BIF_RETTYPE erl_ddll_format_error_int_1(BIF_ALIST_1)
"cannot be loaded/unloaded";
break;
case am_permanent:
- errstring = "DDLL driver is permanent an can not be unloaded/loaded";
+ errstring = "DDLL driver is permanent an cannot be unloaded/loaded";
break;
case am_not_loaded:
errstring = "DDLL driver is not loaded";
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 5789fa8e71..3b0f0d33fa 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -2093,17 +2093,6 @@ current_stacktrace(ErtsHeapFactory *hfact, Process* rp,
return res;
}
-#if defined(VALGRIND)
-static int check_if_xml(void)
-{
- char buf[1];
- size_t bufsz = sizeof(buf);
- return erts_sys_explicit_8bit_getenv("VALGRIND_LOG_XML", buf, &bufsz) >= 0;
-}
-#else
-#define check_if_xml() 0
-#endif
-
/*
* This function takes care of calls to erlang:system_info/1 when the argument
* is a tuple.
@@ -2200,15 +2189,9 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */
#endif
} else if (is_list(*tp)) {
#if defined(PURIFY)
-#define ERTS_ERROR_CHECKER_PRINTF purify_printf
-#define ERTS_ERROR_CHECKER_PRINTF_XML purify_printf
+# define ERTS_ERROR_CHECKER_PRINTF purify_printf
#elif defined(VALGRIND)
-#define ERTS_ERROR_CHECKER_PRINTF VALGRIND_PRINTF
-# ifndef HAVE_VALGRIND_PRINTF_XML
-# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF
-# else
-# define ERTS_ERROR_CHECKER_PRINTF_XML VALGRIND_PRINTF_XML
-# endif
+# define ERTS_ERROR_CHECKER_PRINTF VALGRIND_PRINTF
#endif
ErlDrvSizeT buf_size = 8*1024; /* Try with 8KB first */
char *buf = erts_alloc(ERTS_ALC_T_TMP, buf_size);
@@ -2224,12 +2207,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */
ASSERT(r == buf_size - 1);
}
buf[buf_size - 1 - r] = '\0';
- if (check_if_xml()) {
- ERTS_ERROR_CHECKER_PRINTF_XML("<erlang_info_log>"
- "%s</erlang_info_log>\n", buf);
- } else {
- ERTS_ERROR_CHECKER_PRINTF("%s\n", buf);
- }
+ ERTS_ERROR_CHECKER_PRINTF("%s\n", buf);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(am_true);
#undef ERTS_ERROR_CHECKER_PRINTF
@@ -2727,9 +2705,7 @@ BIF_RETTYPE system_info_1(BIF_ALIST_1)
goto bld_instruction_counts;
}
-#ifdef DEBUG
ASSERT(endp == hp);
-#endif
BIF_RET(res);
#endif /* #ifndef ERTS_OPCODE_COUNTER_SUPPORT */
@@ -4693,6 +4669,14 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2)
BIF_RET(am_notsup);
#endif
}
+ else if (ERTS_IS_ATOM_STR("ets_force_split", BIF_ARG_1)) {
+ if (is_tuple(BIF_ARG_2)) {
+ Eterm* tpl = tuple_val(BIF_ARG_2);
+
+ if (erts_ets_force_split(tpl[1], tpl[2] == am_true))
+ BIF_RET(am_ok);
+ }
+ }
}
BIF_ERROR(BIF_P, BADARG);
diff --git a/erts/emulator/beam/erl_bif_lists.c b/erts/emulator/beam/erl_bif_lists.c
index 73d327da3e..395be67a90 100644
--- a/erts/emulator/beam/erl_bif_lists.c
+++ b/erts/emulator/beam/erl_bif_lists.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2016. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -277,75 +277,121 @@ BIF_RETTYPE lists_member_2(BIF_ALIST_2)
BIF_RET2(am_false, CONTEXT_REDS - max_iter/10);
}
-BIF_RETTYPE lists_reverse_2(BIF_ALIST_2)
+static BIF_RETTYPE lists_reverse_alloc(Process *c_p,
+ Eterm list_in,
+ Eterm tail_in)
{
- Eterm list;
- Eterm tmp_list;
- Eterm result;
- Eterm* hp;
- Uint n;
- int max_iter;
-
- /*
- * Handle legal and illegal non-lists quickly.
- */
- if (is_nil(BIF_ARG_1)) {
- BIF_RET(BIF_ARG_2);
- } else if (is_not_list(BIF_ARG_1)) {
- error:
- BIF_ERROR(BIF_P, BADARG);
+ static const Uint CELLS_PER_RED = 40;
+
+ Eterm *heap_top, *heap_end;
+ Uint cells_left, max_cells;
+ Eterm list, tail;
+ Eterm lookahead;
+
+ list = list_in;
+ tail = tail_in;
+
+ cells_left = max_cells = CELLS_PER_RED * (1 + ERTS_BIF_REDS_LEFT(c_p));
+ lookahead = list;
+
+ while (cells_left != 0 && is_list(lookahead)) {
+ lookahead = CDR(list_val(lookahead));
+ cells_left--;
}
- /*
- * First use the rest of the remaning heap space.
- */
- list = BIF_ARG_1;
- result = BIF_ARG_2;
- hp = HEAP_TOP(BIF_P);
- n = HeapWordsLeft(BIF_P) / 2;
- while (n != 0 && is_list(list)) {
- Eterm* pair = list_val(list);
- result = CONS(hp, CAR(pair), result);
- list = CDR(pair);
- hp += 2;
- n--;
+ BUMP_REDS(c_p, (max_cells - cells_left) / CELLS_PER_RED);
+
+ if (is_not_list(lookahead) && is_not_nil(lookahead)) {
+ BIF_ERROR(c_p, BADARG);
}
- HEAP_TOP(BIF_P) = hp;
+
+ heap_top = HAlloc(c_p, 2 * (max_cells - cells_left));
+ heap_end = heap_top + 2 * (max_cells - cells_left);
+
+ while (heap_top < heap_end) {
+ Eterm *pair = list_val(list);
+
+ tail = CONS(heap_top, CAR(pair), tail);
+ list = CDR(pair);
+
+ ASSERT(is_list(list) || is_nil(list));
+
+ heap_top += 2;
+ }
+
if (is_nil(list)) {
- BIF_RET(result);
+ BIF_RET(tail);
}
- /*
- * Calculate length of remaining list (up to a suitable limit).
- */
- max_iter = CONTEXT_REDS * 40;
- n = 0;
- tmp_list = list;
- while (max_iter-- > 0 && is_list(tmp_list)) {
- tmp_list = CDR(list_val(tmp_list));
- n++;
+ ASSERT(is_list(tail) && cells_left == 0);
+ BIF_TRAP2(bif_export[BIF_lists_reverse_2], c_p, list, tail);
+}
+
+static BIF_RETTYPE lists_reverse_onheap(Process *c_p,
+ Eterm list_in,
+ Eterm tail_in)
+{
+ static const Uint CELLS_PER_RED = 60;
+
+ Eterm *heap_top, *heap_end;
+ Uint cells_left, max_cells;
+ Eterm list, tail;
+
+ list = list_in;
+ tail = tail_in;
+
+ cells_left = max_cells = CELLS_PER_RED * (1 + ERTS_BIF_REDS_LEFT(c_p));
+
+ ASSERT(HEAP_LIMIT(c_p) >= HEAP_TOP(c_p) + 2);
+ heap_end = HEAP_LIMIT(c_p) - 2;
+ heap_top = HEAP_TOP(c_p);
+
+ while (heap_top < heap_end && is_list(list)) {
+ Eterm *pair = list_val(list);
+
+ tail = CONS(heap_top, CAR(pair), tail);
+ list = CDR(pair);
+
+ heap_top += 2;
}
- if (is_not_nil(tmp_list) && is_not_list(tmp_list)) {
- goto error;
+
+ cells_left -= (heap_top - heap_end) / 2;
+ BUMP_REDS(c_p, (max_cells - cells_left) / CELLS_PER_RED);
+ HEAP_TOP(c_p) = heap_top;
+
+ if (is_nil(list)) {
+ BIF_RET(tail);
+ } else if (is_list(list)) {
+ ASSERT(is_list(tail));
+
+ if (cells_left > CELLS_PER_RED) {
+ return lists_reverse_alloc(c_p, list, tail);
+ }
+
+ BUMP_ALL_REDS(c_p);
+ BIF_TRAP2(bif_export[BIF_lists_reverse_2], c_p, list, tail);
}
- /*
- * Now do one HAlloc() and continue reversing.
- */
- hp = HAlloc(BIF_P, 2*n);
- while (n != 0 && is_list(list)) {
- Eterm* pair = list_val(list);
- result = CONS(hp, CAR(pair), result);
- list = CDR(pair);
- hp += 2;
- n--;
+ BIF_ERROR(c_p, BADARG);
+}
+
+BIF_RETTYPE lists_reverse_2(BIF_ALIST_2)
+{
+ /* Handle legal and illegal non-lists quickly. */
+ if (is_nil(BIF_ARG_1)) {
+ BIF_RET(BIF_ARG_2);
+ } else if (is_not_list(BIF_ARG_1)) {
+ BIF_ERROR(BIF_P, BADARG);
}
- if (is_nil(list)) {
- BIF_RET(result);
- } else {
- BUMP_ALL_REDS(BIF_P);
- BIF_TRAP2(bif_export[BIF_lists_reverse_2], BIF_P, list, result);
+
+ /* We build the reversal on the unused part of the heap if possible to save
+ * us the trouble of having to figure out the list size. We fall back to
+ * lists_reverse_alloc when we run out of space. */
+ if (HeapWordsLeft(BIF_P) > 8) {
+ return lists_reverse_onheap(BIF_P, BIF_ARG_1, BIF_ARG_2);
}
+
+ return lists_reverse_alloc(BIF_P, BIF_ARG_1, BIF_ARG_2);
}
BIF_RETTYPE
diff --git a/erts/emulator/beam/erl_bif_re.c b/erts/emulator/beam/erl_bif_re.c
index bbc64eb9aa..e0b9202fe7 100644
--- a/erts/emulator/beam/erl_bif_re.c
+++ b/erts/emulator/beam/erl_bif_re.c
@@ -532,10 +532,7 @@ re_compile(Process* p, Eterm arg1, Eterm arg2)
int options = 0;
int pflags = 0;
int unicode = 0;
-#ifdef DEBUG
int buffres;
-#endif
-
if (parse_options(arg2,&options,NULL,&pflags,NULL,NULL,NULL,NULL)
< 0) {
@@ -556,12 +553,8 @@ re_compile(Process* p, Eterm arg1, Eterm arg2)
BIF_ERROR(p,BADARG);
}
expr = erts_alloc(ERTS_ALC_T_RE_TMP_BUF, slen + 1);
-#ifdef DEBUG
- buffres =
-#endif
- erts_iolist_to_buf(arg1, expr, slen);
-
- ASSERT(buffres >= 0);
+ buffres = erts_iolist_to_buf(arg1, expr, slen);
+ ASSERT(buffres >= 0); (void)buffres;
expr[slen]='\0';
result = erts_pcre_compile2(expr, options, &errcode,
@@ -1052,9 +1045,7 @@ build_capture(Eterm capture_spec[CAPSPEC_SIZE], const pcre *code)
tmpb[ap->len] = '\0';
} else {
ErlDrvSizeT slen;
-#ifdef DEBUG
int buffres;
-#endif
if (erts_iolist_size(val, &slen)) {
goto error;
@@ -1068,11 +1059,8 @@ build_capture(Eterm capture_spec[CAPSPEC_SIZE], const pcre *code)
}
}
-#ifdef DEBUG
- buffres =
-#endif
- erts_iolist_to_buf(val, tmpb, slen);
- ASSERT(buffres >= 0);
+ buffres = erts_iolist_to_buf(val, tmpb, slen);
+ ASSERT(buffres >= 0); (void)buffres;
tmpb[slen] = '\0';
}
build_one_capture(code,&ri,&sallocated,has_dupnames,tmpb);
@@ -1145,9 +1133,7 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
const char *errstr = "";
int errofset = 0;
int capture_count;
-#ifdef DEBUG
int buffres;
-#endif
if (pflags & PARSE_FLAG_UNICODE &&
(!is_binary(arg2) || !is_binary(arg1) ||
@@ -1161,12 +1147,8 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
expr = erts_alloc(ERTS_ALC_T_RE_TMP_BUF, slen + 1);
-#ifdef DEBUG
- buffres =
-#endif
- erts_iolist_to_buf(arg2, expr, slen);
-
- ASSERT(buffres >= 0);
+ buffres = erts_iolist_to_buf(arg2, expr, slen);
+ ASSERT(buffres >= 0); (void)buffres;
expr[slen]='\0';
result = erts_pcre_compile2(expr, comp_options, &errcode,
@@ -1317,9 +1299,7 @@ re_run(Process *p, Eterm arg1, Eterm arg2, Eterm arg3)
restart.subject = (char *) (pb->bytes+offset);
restart.flags |= RESTART_FLAG_SUBJECT_IN_BINARY;
} else {
-#ifdef DEBUG
int buffres;
-#endif
handle_iolist:
if (erts_iolist_size(arg1, &slength)) {
erts_free(ERTS_ALC_T_RE_SUBJECT, restart.ovector);
@@ -1331,11 +1311,8 @@ handle_iolist:
}
restart.subject = erts_alloc(ERTS_ALC_T_RE_SUBJECT, slength);
-#ifdef DEBUG
- buffres =
-#endif
- erts_iolist_to_buf(arg1, restart.subject, slength);
- ASSERT(buffres >= 0);
+ buffres = erts_iolist_to_buf(arg1, restart.subject, slength);
+ ASSERT(buffres >= 0); (void)buffres;
}
if (pflags & PARSE_FLAG_REPORT_ERRORS) {
@@ -1457,10 +1434,7 @@ re_inspect_2(BIF_ALIST_2)
Eterm res;
const pcre *code;
byte *temp_alloc = NULL;
-#ifdef DEBUG
- int infores;
-#endif
-
+ int infores;
if (is_not_tuple(BIF_ARG_1) || (arityval(*tuple_val(BIF_ARG_1)) != 5)) {
goto error;
@@ -1484,12 +1458,8 @@ re_inspect_2(BIF_ALIST_2)
if (erts_pcre_fullinfo(code, NULL, PCRE_INFO_OPTIONS, &options) != 0)
goto error;
-#ifdef DEBUG
- infores =
-#endif
- erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top);
-
- ASSERT(infores == 0);
+ infores = erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMECOUNT, &top);
+ ASSERT(infores == 0); (void)infores;
if (top <= 0) {
hp = HAlloc(BIF_P, 3);
@@ -1497,18 +1467,10 @@ re_inspect_2(BIF_ALIST_2)
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(res);
}
-#ifdef DEBUG
- infores =
-#endif
- erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize);
-
+ infores = erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrysize);
ASSERT(infores == 0);
-#ifdef DEBUG
- infores =
-#endif
- erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable);
-
+ infores = erts_pcre_fullinfo(code, NULL, PCRE_INFO_NAMETABLE, &nametable);
ASSERT(infores == 0);
has_dupnames = ((options & PCRE_DUPNAMES) != 0);
diff --git a/erts/emulator/beam/erl_bif_unique.h b/erts/emulator/beam/erl_bif_unique.h
index 40b70667c0..944788c67c 100644
--- a/erts/emulator/beam/erl_bif_unique.h
+++ b/erts/emulator/beam/erl_bif_unique.h
@@ -242,11 +242,11 @@ erts_internal_ref_number_cmp(Uint32 num1[ERTS_REF_NUMBERS],
Uint32 num2[ERTS_REF_NUMBERS])
{
if (num1[2] != num2[2])
- return (int) ((Sint64) num1[2] - (Sint64) num2[2]);
+ return num1[2] > num2[2] ? 1 : -1;
if (num1[1] != num2[1])
- return (int) ((Sint64) num1[1] - (Sint64) num2[1]);
+ return num1[1] > num2[1] ? 1 : -1;
if (num1[0] != num2[0])
- return (int) ((Sint64) num1[0] - (Sint64) num2[0]);
+ return num1[0] > num2[0] ? 1 : -1;
return 0;
}
diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c
index 3a16913473..e82c776e70 100644
--- a/erts/emulator/beam/erl_bits.c
+++ b/erts/emulator/beam/erl_bits.c
@@ -144,6 +144,42 @@ erts_bs_start_match_2(Process *p, Eterm Binary, Uint Max)
return make_matchstate(ms);
}
+ErlBinMatchState *erts_bs_start_match_3(Process *p, Eterm Binary)
+{
+ Eterm Orig;
+ Uint offs;
+ Uint* hp;
+ Uint NeededSize;
+ ErlBinMatchState *ms;
+ Uint bitoffs;
+ Uint bitsize;
+ Uint total_bin_size;
+ ProcBin* pb;
+
+ ASSERT(is_binary(Binary));
+ total_bin_size = binary_size(Binary);
+ if ((total_bin_size >> (8*sizeof(Uint)-3)) != 0) {
+ return NULL;
+ }
+
+ NeededSize = ERL_BIN_MATCHSTATE_SIZE(0);
+ hp = HeapOnlyAlloc(p, NeededSize);
+ ms = (ErlBinMatchState *) hp;
+ ERTS_GET_REAL_BIN(Binary, Orig, offs, bitoffs, bitsize);
+ pb = (ProcBin *) boxed_val(Orig);
+ if (pb->thing_word == HEADER_PROC_BIN && pb->flags != 0) {
+ erts_emasculate_writable_binary(pb);
+ }
+
+ ms->thing_word = HEADER_BIN_MATCHSTATE(0);
+ (ms->mb).orig = Orig;
+ (ms->mb).base = binary_bytes(Orig);
+ (ms->mb).offset = 8 * offs + bitoffs;
+ (ms->mb).size = total_bin_size * 8 + (ms->mb).offset + bitsize;
+
+ return ms;
+}
+
#ifdef DEBUG
# define CHECK_MATCH_BUFFER(MB) check_match_buffer(MB)
diff --git a/erts/emulator/beam/erl_bits.h b/erts/emulator/beam/erl_bits.h
index 7beef5cfda..50d353e1fa 100644
--- a/erts/emulator/beam/erl_bits.h
+++ b/erts/emulator/beam/erl_bits.h
@@ -73,12 +73,16 @@ struct erl_bits_state {
typedef struct erl_bin_match_struct{
Eterm thing_word;
ErlBinMatchBuffer mb; /* Present match buffer */
- Eterm save_offset[1]; /* Saved offsets */
+ Eterm save_offset[1]; /* Saved offsets, only valid for contexts
+ * created through bs_start_match2. */
} ErlBinMatchState;
-#define ERL_BIN_MATCHSTATE_SIZE(_Max) ((sizeof(ErlBinMatchState) + (_Max)*sizeof(Eterm))/sizeof(Eterm))
-#define HEADER_BIN_MATCHSTATE(_Max) _make_header(ERL_BIN_MATCHSTATE_SIZE((_Max))-1, _TAG_HEADER_BIN_MATCHSTATE)
-#define HEADER_NUM_SLOTS(hdr) (header_arity(hdr)-sizeof(ErlBinMatchState)/sizeof(Eterm)+1)
+#define ERL_BIN_MATCHSTATE_SIZE(_Max) \
+ ((offsetof(ErlBinMatchState, save_offset) + (_Max)*sizeof(Eterm))/sizeof(Eterm))
+#define HEADER_BIN_MATCHSTATE(_Max) \
+ _make_header(ERL_BIN_MATCHSTATE_SIZE((_Max)) - 1, _TAG_HEADER_BIN_MATCHSTATE)
+#define HEADER_NUM_SLOTS(hdr) \
+ (header_arity(hdr) - (offsetof(ErlBinMatchState, save_offset) / sizeof(Eterm)) + 1)
#define make_matchstate(_Ms) make_boxed((Eterm*)(_Ms))
#define ms_matchbuffer(_Ms) &(((ErlBinMatchState*) boxed_val(_Ms))->mb)
@@ -144,6 +148,7 @@ void erts_bits_destroy_state(ERL_BITS_PROTO_0);
*/
Eterm erts_bs_start_match_2(Process *p, Eterm Bin, Uint Max);
+ErlBinMatchState *erts_bs_start_match_3(Process *p, Eterm Bin);
Eterm erts_bs_get_integer_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
Eterm erts_bs_get_binary_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
Eterm erts_bs_get_float_2(Process *p, Uint num_bits, unsigned flags, ErlBinMatchBuffer* mb);
diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c
index 36d83d93f4..df6f42edd3 100644
--- a/erts/emulator/beam/erl_db.c
+++ b/erts/emulator/beam/erl_db.c
@@ -90,7 +90,8 @@ enum DbIterSafety {
ITER_SAFE /* No need to fixate at all */
};
# define ITERATION_SAFETY(Proc,Tab) \
- ((IS_TREE_TABLE((Tab)->common.status) || ONLY_WRITER(Proc,Tab)) ? ITER_SAFE \
+ ((IS_TREE_TABLE((Tab)->common.status) || IS_CATREE_TABLE((Tab)->common.status) \
+ || ONLY_WRITER(Proc,Tab)) ? ITER_SAFE \
: (((Tab)->common.status & DB_FINE_LOCKED) ? ITER_UNSAFE : ITER_SAFE_LOCKED))
#define DID_TRAP(P,Ret) (!is_value(Ret) && ((P)->freason == TRAP))
@@ -359,6 +360,7 @@ typedef enum {
extern DbTableMethod db_hash;
extern DbTableMethod db_tree;
+extern DbTableMethod db_catree;
int user_requested_db_max_tabs;
int erts_ets_realloc_always_moves;
@@ -407,21 +409,17 @@ static void
free_dbtable(void *vtb)
{
DbTable *tb = (DbTable *) vtb;
-#ifdef HARDDEBUG
- if (erts_atomic_read_nob(&tb->common.memory_size) != sizeof(DbTable)) {
- erts_fprintf(stderr, "ets: free_dbtable memory remain=%ld fix=%x\n",
- erts_atomic_read_nob(&tb->common.memory_size)-sizeof(DbTable),
- tb->common.fixations);
- }
-#endif
- erts_rwmtx_destroy(&tb->common.rwlock);
- erts_mtx_destroy(&tb->common.fixlock);
- ASSERT(is_immed(tb->common.heir_data));
- if (tb->common.btid)
- erts_bin_release(tb->common.btid);
+ ASSERT(erts_atomic_read_nob(&tb->common.memory_size) == sizeof(DbTable));
+
+ erts_rwmtx_destroy(&tb->common.rwlock);
+ erts_mtx_destroy(&tb->common.fixlock);
+ ASSERT(is_immed(tb->common.heir_data));
+
+ if (tb->common.btid)
+ erts_bin_release(tb->common.btid);
- erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
+ erts_db_free(ERTS_ALC_T_DB_TABLE, tb, (void *) tb, sizeof(DbTable));
}
static void schedule_free_dbtable(DbTable* tb)
@@ -1076,7 +1074,7 @@ BIF_RETTYPE ets_update_element_3(BIF_ALIST_3)
DB_BIF_GET_TABLE(tb, DB_WRITE, LCK_WRITE_REC, BIF_ets_update_element_3);
UseTmpHeap(2,BIF_P);
- if (!(tb->common.status & (DB_SET | DB_ORDERED_SET))) {
+ if (!(tb->common.status & (DB_SET | DB_ORDERED_SET | DB_CA_ORDERED_SET))) {
goto bail_out;
}
if (is_tuple(BIF_ARG_3)) {
@@ -1165,7 +1163,7 @@ do_update_counter(Process *p, DbTable* tb,
UseTmpHeap(5, p);
- if (!(tb->common.status & (DB_SET | DB_ORDERED_SET))) {
+ if (!(tb->common.status & (DB_SET | DB_ORDERED_SET | DB_CA_ORDERED_SET))) {
goto bail_out;
}
if (is_integer(arg3)) { /* Incr */
@@ -1647,15 +1645,15 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
val = CAR(list_val(list));
if (val == am_bag) {
status |= DB_BAG;
- status &= ~(DB_SET | DB_DUPLICATE_BAG | DB_ORDERED_SET);
+ status &= ~(DB_SET | DB_DUPLICATE_BAG | DB_ORDERED_SET | DB_CA_ORDERED_SET);
}
else if (val == am_duplicate_bag) {
status |= DB_DUPLICATE_BAG;
- status &= ~(DB_SET | DB_BAG | DB_ORDERED_SET);
+ status &= ~(DB_SET | DB_BAG | DB_ORDERED_SET | DB_CA_ORDERED_SET);
}
else if (val == am_ordered_set) {
status |= DB_ORDERED_SET;
- status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG);
+ status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG | DB_CA_ORDERED_SET);
}
else if (is_tuple(val)) {
Eterm *tp = tuple_val(val);
@@ -1716,7 +1714,13 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2)
if (is_not_nil(list)) { /* bad opt or not a well formed list */
BIF_ERROR(BIF_P, BADARG);
}
- if (IS_HASH_TABLE(status)) {
+ if (IS_TREE_TABLE(status) && is_fine_locked && !(status & DB_PRIVATE)) {
+ meth = &db_catree;
+ status |= DB_CA_ORDERED_SET;
+ status &= ~(DB_SET | DB_BAG | DB_DUPLICATE_BAG | DB_ORDERED_SET);
+ status |= DB_FINE_LOCKED;
+ }
+ else if (IS_HASH_TABLE(status)) {
meth = &db_hash;
if (is_fine_locked && !(status & DB_PRIVATE)) {
status |= DB_FINE_LOCKED;
@@ -3506,6 +3510,7 @@ void init_db(ErtsDbSpinCount db_spin_count)
db_initialize_hash();
db_initialize_tree();
+ db_initialize_catree();
/* Non visual BIF to trap to. */
erts_init_trap_export(&ets_select_delete_continue_exp,
@@ -3647,6 +3652,7 @@ send_ets_transfer_message(Process *c_p, Process *proc,
hd_copy = copy_struct(heir_data, hd_sz, &hp, ohp);
sender = c_p->common.id;
msg = TUPLE4(hp, am_ETS_TRANSFER, tid, sender, hd_copy);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, proc, *locks, mp, msg);
}
@@ -4113,6 +4119,8 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
ret = am_duplicate_bag;
} else if (tb->common.status & DB_ORDERED_SET) {
ret = am_ordered_set;
+ } else if (tb->common.status & DB_CA_ORDERED_SET) {
+ ret = am_ordered_set;
} else { /*TT*/
ASSERT(tb->common.status & DB_BAG);
ret = am_bag;
@@ -4239,9 +4247,20 @@ static Eterm table_info(Process* p, DbTable* tb, Eterm What)
make_small(stats.max_chain_len),
make_small(stats.kept_items));
}
- else {
+ else if (IS_CATREE_TABLE(tb->common.status)) {
+ DbCATreeStats stats;
+ Eterm* hp;
+
+ db_calc_stats_catree(&tb->catree, &stats);
+ hp = HAlloc(p, 4);
+ ret = TUPLE3(hp,
+ make_small(stats.route_nodes),
+ make_small(stats.base_nodes),
+ make_small(stats.max_depth));
+
+ }
+ else
ret = am_false;
- }
}
return ret;
}
@@ -4408,6 +4427,12 @@ void erts_lcnt_enable_db_lock_count(DbTable *tb, int enable) {
if(IS_HASH_TABLE(tb->common.status)) {
erts_lcnt_enable_db_hash_lock_count(&tb->hash, enable);
+ } else if(IS_CATREE_TABLE(tb->common.status)) {
+ /* erts_lcnt_enable_db_catree_lock_count is not thread safe so
+ the table needs to get locked */
+ db_lock(tb, LCK_WRITE);
+ erts_lcnt_enable_db_catree_lock_count(&tb->catree, enable);
+ db_unlock(tb, LCK_WRITE);
}
}
@@ -4440,3 +4465,16 @@ void erts_lcnt_update_db_locks(int enable) {
#ifdef ETS_DBG_FORCE_TRAP
erts_aint_t erts_ets_dbg_force_trap = 0;
#endif
+
+int erts_ets_force_split(Eterm tid, int on)
+{
+ DbTable* tb = tid2tab(tid);
+ if (!tb || !IS_CATREE_TABLE(tb->common.type))
+ return 0;
+
+ db_lock(tb, LCK_WRITE);
+ if (!(tb->common.status & DB_DELETE))
+ db_catree_force_split(&tb->catree, on);
+ db_unlock(tb, LCK_WRITE);
+ return 1;
+}
diff --git a/erts/emulator/beam/erl_db.h b/erts/emulator/beam/erl_db.h
index 23975d208f..5955d42aae 100644
--- a/erts/emulator/beam/erl_db.h
+++ b/erts/emulator/beam/erl_db.h
@@ -66,6 +66,7 @@ typedef struct {
#include "erl_db_util.h" /* Flags */
#include "erl_db_hash.h" /* DbTableHash */
#include "erl_db_tree.h" /* DbTableTree */
+#include "erl_db_catree.h" /* DbTableCATree */
/*TT*/
Uint erts_get_ets_misc_mem_size(void);
@@ -90,6 +91,7 @@ union db_table {
DbTableCommon common; /* Any type of db table */
DbTableHash hash; /* Linear hash array specific data */
DbTableTree tree; /* AVL tree specific data */
+ DbTableCATree catree; /* CA tree specific data */
DbTableRelease release;
/*TT*/
};
@@ -128,6 +130,7 @@ extern Export ets_select_continue_exp;
extern erts_atomic_t erts_ets_misc_mem_size;
Eterm erts_ets_colliding_names(Process*, Eterm name, Uint cnt);
+int erts_ets_force_split(Eterm tid, int on);
Uint erts_db_get_max_tabs(void);
Eterm erts_db_make_tid(Process *c_p, DbTableCommon *tb);
@@ -284,6 +287,12 @@ ERTS_GLB_INLINE void erts_db_free(ErtsAlcType_t type,
void *ptr,
Uint size);
+ERTS_GLB_INLINE void erts_schedule_db_free(DbTableCommon* tab,
+ void (*free_func)(void *),
+ void *ptr,
+ ErtsThrPrgrLaterOp *lop,
+ Uint size);
+
ERTS_GLB_INLINE void erts_db_free_nt(ErtsAlcType_t type,
void *ptr,
Uint size);
@@ -304,6 +313,26 @@ erts_db_free(ErtsAlcType_t type, DbTable *tab, void *ptr, Uint size)
}
ERTS_GLB_INLINE void
+erts_schedule_db_free(DbTableCommon* tab,
+ void (*free_func)(void *),
+ void *ptr,
+ ErtsThrPrgrLaterOp *lop,
+ Uint size)
+{
+ ASSERT(ptr != 0);
+ ASSERT(((void *) tab) != ptr);
+ ASSERT(size == ERTS_ALC_DBG_BLK_SZ(ptr));
+
+ /*
+ * We update table memory stats here as table may already be gone
+ * when 'free_func' is finally called.
+ */
+ ERTS_DB_ALC_MEM_UPDATE_((DbTable*)tab, size, 0);
+
+ erts_schedule_thr_prgr_later_cleanup_op(free_func, ptr, lop, size);
+}
+
+ERTS_GLB_INLINE void
erts_db_free_nt(ErtsAlcType_t type, void *ptr, Uint size)
{
ASSERT(ptr != 0);
diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c
new file mode 100644
index 0000000000..b52a4a53fe
--- /dev/null
+++ b/erts/emulator/beam/erl_db_catree.c
@@ -0,0 +1,2225 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB and Kjell Winblad 1998-2018. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Implementation of ETS ordered_set table type with
+ * fine-grained synchronization.
+ *
+ * Author: Kjell Winblad
+ *
+ * This implementation is based on the contention adapting search tree
+ * (CA tree). The CA tree is a concurrent data structure that
+ * dynamically adapts its synchronization granularity based on how
+ * much contention is detected in locks. The following publication
+ * contains a detailed description of CA trees:
+ *
+ * A Contention Adapting Approach to Concurrent Ordered Sets
+ * Journal of Parallel and Distributed Computing, 2018
+ * Kjell Winblad and Konstantinos Sagonas
+ * https://doi.org/10.1016/j.jpdc.2017.11.007
+ *
+ * The following publication may also be interesting as it discusses
+ * how the CA tree can be used as an ETS ordered_set table type
+ * backend:
+ *
+ * More Scalable Ordered Set for ETS Using Adaptation
+ * In Thirteenth ACM SIGPLAN workshop on Erlang (2014)
+ * Kjell Winblad and Konstantinos Sagonas
+ * https://doi.org/10.1145/2633448.2633455
+ *
+ * This implementation of the ordered_set ETS table type is only
+ * activated when the options {write_concurrency, true}, public and
+ * ordered_set are passed to the ets:new/2 function. This
+ * implementation is expected to scale better than the default
+ * implementation (located in "erl_db_tree.c") when concurrent
+ * processes use the following ETS operations to operate on a table:
+ *
+ * delete/2, delete_object/2, first/1, insert/2 (single object),
+ * insert_new/2 (single object), lookup/2, lookup_element/2, member/2,
+ * next/2, take/2 and update_element/3 (single object).
+ *
+ * Currently, the implementation does not have scalable support for
+ * the other operations (e.g., select/2). These operations are handled
+ * by merging all locks so that all terms get protected by a single
+ * lock. This implementation may thus perform worse than the default
+ * implementation in some scenarios. For example, when concurrent
+ * processes access a table with the operations insert/2, delete/2 and
+ * select/2, the insert/2 and delete/2 operations will trigger splits
+ * of locks (to get more fine-grained synchronization) but this will
+ * quickly be undone by the select/2 operation if this operation is
+ * also called frequently.
+ *
+ * The default implementation has a static stack optimization (see
+ * get_static_stack in erl_db_tree.c). This implementation does not
+ * have such an optimization as it induces bad scalability when
+ * concurrent read operations are frequent (they all try to get hold
+ * of the same stack). The default implementation may thus perform
+ * better compared to this implementation in scenarios where the
+ * static stack optimization is useful. One such scenario is when only
+ * one process is accessing the table and this process is traversing
+ * the table with a sequence of next/2 calls.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "erl_vm.h"
+#include "global.h"
+#include "erl_process.h"
+#include "error.h"
+#define ERTS_WANT_DB_INTERNAL__
+#include "erl_db.h"
+#include "bif.h"
+#include "big.h"
+#include "erl_binary.h"
+
+#include "erl_db_catree.h"
+#include "erl_db_tree.h"
+#include "erl_db_tree_util.h"
+
+#ifdef DEBUG
+# define IF_DEBUG(X) X
+#else
+# define IF_DEBUG(X)
+#endif
+
+/*
+** Forward declarations
+*/
+
+static SWord do_free_base_node_cont(DbTableCATree *tb, SWord num_left);
+static SWord do_free_routing_nodes_catree_cont(DbTableCATree *tb, SWord num_left);
+static DbTableCATreeNode *catree_first_base_node_from_free_list(DbTableCATree *tb);
+
+/* Method interface functions */
+static int db_first_catree(Process *p, DbTable *tbl,
+ Eterm *ret);
+static int db_next_catree(Process *p, DbTable *tbl,
+ Eterm key, Eterm *ret);
+static int db_last_catree(Process *p, DbTable *tbl,
+ Eterm *ret);
+static int db_prev_catree(Process *p, DbTable *tbl,
+ Eterm key,
+ Eterm *ret);
+static int db_put_catree(DbTable *tbl, Eterm obj, int key_clash_fail);
+static int db_get_catree(Process *p, DbTable *tbl,
+ Eterm key, Eterm *ret);
+static int db_member_catree(DbTable *tbl, Eterm key, Eterm *ret);
+static int db_get_element_catree(Process *p, DbTable *tbl,
+ Eterm key,int ndex,
+ Eterm *ret);
+static int db_erase_catree(DbTable *tbl, Eterm key, Eterm *ret);
+static int db_erase_object_catree(DbTable *tbl, Eterm object,Eterm *ret);
+static int db_slot_catree(Process *p, DbTable *tbl,
+ Eterm slot_term, Eterm *ret);
+static int db_select_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, int reversed, Eterm *ret);
+static int db_select_count_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret);
+static int db_select_chunk_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Sint chunk_size,
+ int reversed, Eterm *ret);
+static int db_select_continue_catree(Process *p, DbTable *tbl,
+ Eterm continuation, Eterm *ret);
+static int db_select_count_continue_catree(Process *p, DbTable *tbl,
+ Eterm continuation, Eterm *ret);
+static int db_select_delete_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret);
+static int db_select_delete_continue_catree(Process *p, DbTable *tbl,
+ Eterm continuation, Eterm *ret);
+static int db_select_replace_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret);
+static int db_select_replace_continue_catree(Process *p, DbTable *tbl,
+ Eterm continuation, Eterm *ret);
+static int db_take_catree(Process *, DbTable *, Eterm, Eterm *);
+static void db_print_catree(fmtfn_t to, void *to_arg,
+ int show, DbTable *tbl);
+static int db_free_table_catree(DbTable *tbl);
+static SWord db_free_table_continue_catree(DbTable *tbl, SWord);
+static void db_foreach_offheap_catree(DbTable *,
+ void (*)(ErlOffHeap *, void *),
+ void *);
+static SWord db_delete_all_objects_catree(Process* p, DbTable* tbl, SWord reds);
+static int
+db_lookup_dbterm_catree(Process *, DbTable *, Eterm key, Eterm obj,
+ DbUpdateHandle*);
+static void db_finalize_dbterm_catree(int cret, DbUpdateHandle *);
+
+static void split_catree(DbTableCATree *tb,
+ DbTableCATreeNode* ERTS_RESTRICT base,
+ DbTableCATreeNode* ERTS_RESTRICT parent);
+static void join_catree(DbTableCATree *tb,
+ DbTableCATreeNode *thiz,
+ DbTableCATreeNode *parent);
+
+
+/*
+** External interface
+*/
+DbTableMethod db_catree =
+{
+ db_create_catree,
+ db_first_catree,
+ db_next_catree,
+ db_last_catree,
+ db_prev_catree,
+ db_put_catree,
+ db_get_catree,
+ db_get_element_catree,
+ db_member_catree,
+ db_erase_catree,
+ db_erase_object_catree,
+ db_slot_catree,
+ db_select_chunk_catree,
+ db_select_catree,
+ db_select_delete_catree,
+ db_select_continue_catree,
+ db_select_delete_continue_catree,
+ db_select_count_catree,
+ db_select_count_continue_catree,
+ db_select_replace_catree,
+ db_select_replace_continue_catree,
+ db_take_catree,
+ db_delete_all_objects_catree,
+ db_free_table_catree,
+ db_free_table_continue_catree,
+ db_print_catree,
+ db_foreach_offheap_catree,
+ db_lookup_dbterm_catree,
+ db_finalize_dbterm_catree
+
+};
+
+/*
+ * Constants
+ */
+
+#define ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION 200
+#define ERL_DB_CATREE_LOCK_SUCCESS_CONTRIBUTION (-1)
+#define ERL_DB_CATREE_LOCK_MORE_THAN_ONE_CONTRIBUTION (-10)
+#define ERL_DB_CATREE_HIGH_CONTENTION_LIMIT 1000
+#define ERL_DB_CATREE_LOW_CONTENTION_LIMIT (-1000)
+#define ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT 14
+
+/*
+ * Internal CA tree related helper functions and macros
+ */
+
+#define GET_ROUTE_NODE_KEY(node) (node->u.route.key.term)
+#define GET_BASE_NODE_LOCK(node) (&(node->u.base.lock))
+#define GET_ROUTE_NODE_LOCK(node) (&(node->u.route.lock))
+
+
+/* Helpers for reading and writing shared atomic variables */
+
+/* No memory barrier */
+#define GET_ROOT(tb) ((DbTableCATreeNode*)erts_atomic_read_nob(&(tb->root)))
+#define GET_LEFT(ca_tree_route_node) ((DbTableCATreeNode*)erts_atomic_read_nob(&(ca_tree_route_node->u.route.left)))
+#define GET_RIGHT(ca_tree_route_node) ((DbTableCATreeNode*)erts_atomic_read_nob(&(ca_tree_route_node->u.route.right)))
+#define SET_ROOT(tb, v) erts_atomic_set_nob(&((tb)->root), (erts_aint_t)(v))
+#define SET_LEFT(ca_tree_route_node, v) erts_atomic_set_nob(&(ca_tree_route_node->u.route.left), (erts_aint_t)(v));
+#define SET_RIGHT(ca_tree_route_node, v) erts_atomic_set_nob(&(ca_tree_route_node->u.route.right), (erts_aint_t)(v));
+
+
+/* Release or acquire barriers */
+#define GET_ROOT_ACQB(tb) ((DbTableCATreeNode*)erts_atomic_read_acqb(&(tb->root)))
+#define GET_LEFT_ACQB(ca_tree_route_node) ((DbTableCATreeNode*)erts_atomic_read_acqb(&(ca_tree_route_node->u.route.left)))
+#define GET_RIGHT_ACQB(ca_tree_route_node) ((DbTableCATreeNode*)erts_atomic_read_acqb(&(ca_tree_route_node->u.route.right)))
+#define SET_ROOT_RELB(tb, v) erts_atomic_set_relb(&((tb)->root), (erts_aint_t)(v))
+#define SET_LEFT_RELB(ca_tree_route_node, v) erts_atomic_set_relb(&(ca_tree_route_node->u.route.left), (erts_aint_t)(v));
+#define SET_RIGHT_RELB(ca_tree_route_node, v) erts_atomic_set_relb(&(ca_tree_route_node->u.route.right), (erts_aint_t)(v));
+
+/* Compares a key to the key in a route node */
+static ERTS_INLINE Sint cmp_key_route(Eterm key,
+ DbTableCATreeNode *obj)
+{
+ return CMP(key, GET_ROUTE_NODE_KEY(obj));
+}
+
+/*
+ * Used by the split_tree function
+ */
+static ERTS_INLINE
+int less_than_two_elements(TreeDbTerm *root)
+{
+ return root == NULL || (root->left == NULL && root->right == NULL);
+}
+
+/*
+ * Inserts a TreeDbTerm into a tree. Returns the new root.
+ */
+static ERTS_INLINE
+TreeDbTerm* insert_TreeDbTerm(DbTableCATree *tb,
+ TreeDbTerm *insert_to_root,
+ TreeDbTerm *value_to_insert) {
+ /* Non recursive insertion in AVL tree, building our own stack */
+ TreeDbTerm **tstack[STACK_NEED];
+ int tpos = 0;
+ int dstack[STACK_NEED+1];
+ int dpos = 0;
+ int state = 0;
+ TreeDbTerm * base = insert_to_root;
+ TreeDbTerm **this = &base;
+ Sint c;
+ Eterm key;
+ int dir;
+ TreeDbTerm *p1, *p2, *p;
+
+ key = GETKEY(tb, value_to_insert->dbterm.tpl);
+
+ dstack[dpos++] = DIR_END;
+ for (;;)
+ if (!*this) { /* Found our place */
+ state = 1;
+ *this = value_to_insert;
+ (*this)->balance = 0;
+ (*this)->left = (*this)->right = NULL;
+ break;
+ } else if ((c = cmp_key(&tb->common, key, *this)) < 0) {
+ /* go lefts */
+ dstack[dpos++] = DIR_LEFT;
+ tstack[tpos++] = this;
+ this = &((*this)->left);
+ } else { /* go right */
+ dstack[dpos++] = DIR_RIGHT;
+ tstack[tpos++] = this;
+ this = &((*this)->right);
+ }
+
+ while (state && ( dir = dstack[--dpos] ) != DIR_END) {
+ this = tstack[--tpos];
+ p = *this;
+ if (dir == DIR_LEFT) {
+ switch (p->balance) {
+ case 1:
+ p->balance = 0;
+ state = 0;
+ break;
+ case 0:
+ p->balance = -1;
+ break;
+ case -1: /* The icky case */
+ p1 = p->left;
+ if (p1->balance == -1) { /* Single LL rotation */
+ p->left = p1->right;
+ p1->right = p;
+ p->balance = 0;
+ (*this) = p1;
+ } else { /* Double RR rotation */
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+ p->left = p2->right;
+ p2->right = p;
+ p->balance = (p2->balance == -1) ? +1 : 0;
+ p1->balance = (p2->balance == 1) ? -1 : 0;
+ (*this) = p2;
+ }
+ (*this)->balance = 0;
+ state = 0;
+ break;
+ }
+ } else { /* dir == DIR_RIGHT */
+ switch (p->balance) {
+ case -1:
+ p->balance = 0;
+ state = 0;
+ break;
+ case 0:
+ p->balance = 1;
+ break;
+ case 1:
+ p1 = p->right;
+ if (p1->balance == 1) { /* Single RR rotation */
+ p->right = p1->left;
+ p1->left = p;
+ p->balance = 0;
+ (*this) = p1;
+ } else { /* Double RL rotation */
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+ p->right = p2->left;
+ p2->left = p;
+ p->balance = (p2->balance == 1) ? -1 : 0;
+ p1->balance = (p2->balance == -1) ? 1 : 0;
+ (*this) = p2;
+ }
+ (*this)->balance = 0;
+ state = 0;
+ break;
+ }
+ }
+ }
+ return base;
+}
+
+/*
+ * Split an AVL tree into two trees. The function stores the node
+ * containing the "split key" in the write back parameter
+ * split_key_wb. The function stores the left tree containing the keys
+ * that are smaller than the "split key" in the write back parameter
+ * left_wb and the tree containing the rest of the keys in the write
+ * back parameter right_wb.
+ */
+static void split_tree(DbTableCATree *tb,
+ TreeDbTerm *root,
+ TreeDbTerm **split_key_node_wb,
+ TreeDbTerm **left_wb,
+ TreeDbTerm **right_wb) {
+ TreeDbTerm * split_node = NULL;
+ TreeDbTerm * left_root;
+ TreeDbTerm * right_root;
+ if (root->left == NULL) { /* To get non empty split */
+ *right_wb = root->right;
+ *split_key_node_wb = root->right;
+ root->right = NULL;
+ root->balance = 0;
+ *left_wb = root;
+ return;
+ }
+ split_node = root;
+ left_root = split_node->left;
+ split_node->left = NULL;
+ right_root = split_node->right;
+ split_node->right = NULL;
+ right_root = insert_TreeDbTerm(tb, right_root, split_node);
+ *split_key_node_wb = split_node;
+ *left_wb = left_root;
+ *right_wb = right_root;
+}
+
+/*
+ * Used by the join_trees function
+ */
+static ERTS_INLINE int compute_tree_hight(TreeDbTerm * root)
+{
+ if(root == NULL) {
+ return 0;
+ } else {
+ TreeDbTerm * current_node = root;
+ int hight_so_far = 1;
+ while (current_node->left != NULL || current_node->right != NULL) {
+ if (current_node->balance == -1) {
+ current_node = current_node->left;
+ } else {
+ current_node = current_node->right;
+ }
+ hight_so_far = hight_so_far + 1;
+ }
+ return hight_so_far;
+ }
+}
+
+/*
+ * Used by the join_trees function
+ */
+static ERTS_INLINE
+TreeDbTerm* linkout_min_or_max_tree_node(TreeDbTerm **root, int is_min)
+{
+ TreeDbTerm **tstack[STACK_NEED];
+ int tpos = 0;
+ int dstack[STACK_NEED+1];
+ int dpos = 0;
+ int state = 0;
+ TreeDbTerm **this = root;
+ int dir;
+ TreeDbTerm *q = NULL;
+
+ dstack[dpos++] = DIR_END;
+ for (;;) {
+ if (!*this) { /* Failure */
+ return NULL;
+ } else if (is_min && (*this)->left != NULL) {
+ dstack[dpos++] = DIR_LEFT;
+ tstack[tpos++] = this;
+ this = &((*this)->left);
+ } else if (!is_min && (*this)->right != NULL) {
+ dstack[dpos++] = DIR_RIGHT;
+ tstack[tpos++] = this;
+ this = &((*this)->right);
+ } else { /* Min value, found the one to splice out */
+ q = (*this);
+ if (q->right == NULL) {
+ (*this) = q->left;
+ state = 1;
+ } else if (q->left == NULL) {
+ (*this) = q->right;
+ state = 1;
+ }
+ break;
+ }
+ }
+ while (state && ( dir = dstack[--dpos] ) != DIR_END) {
+ this = tstack[--tpos];
+ if (dir == DIR_LEFT) {
+ state = tree_balance_left(this);
+ } else {
+ state = tree_balance_right(this);
+ }
+ }
+ return q;
+}
+
+#define LINKOUT_MIN_TREE_NODE(root) linkout_min_or_max_tree_node(root, 1)
+#define LINKOUT_MAX_TREE_NODE(root) linkout_min_or_max_tree_node(root, 0)
+
+/*
+ * Joins two AVL trees where all the keys in the left one are smaller
+ * then the keys in the right one and returns the resulting tree.
+ *
+ * The algorithm is described on page 474 in D. E. Knuth. The Art of
+ * Computer Programming: Sorting and Searching,
+ * vol. 3. Addison-Wesley, 2nd edition, 1998.
+ */
+static TreeDbTerm* join_trees(TreeDbTerm *left_root_param,
+ TreeDbTerm *right_root_param)
+{
+ TreeDbTerm **tstack[STACK_NEED];
+ int tpos = 0;
+ int dstack[STACK_NEED+1];
+ int dpos = 0;
+ int state = 1;
+ TreeDbTerm **this;
+ int dir;
+ TreeDbTerm *p1, *p2, *p;
+ TreeDbTerm *left_root = left_root_param;
+ TreeDbTerm *right_root = right_root_param;
+ int left_height;
+ int right_height;
+ int current_height;
+ dstack[dpos++] = DIR_END;
+ if (left_root == NULL) {
+ return right_root;
+ } else if (right_root == NULL) {
+ return left_root;
+ }
+
+ left_height = compute_tree_hight(left_root);
+ right_height = compute_tree_hight(right_root);
+ if (left_height >= right_height) {
+ TreeDbTerm * new_root =
+ LINKOUT_MIN_TREE_NODE(&right_root);
+ int new_right_height = compute_tree_hight(right_root);
+ TreeDbTerm * current_node = left_root;
+ this = &left_root;
+ current_height = left_height;
+ while(current_height > new_right_height + 1) {
+ if (current_node->balance == -1) {
+ current_height = current_height - 2;
+ } else {
+ current_height = current_height - 1;
+ }
+ dstack[dpos++] = DIR_RIGHT;
+ tstack[tpos++] = this;
+ this = &((*this)->right);
+ current_node = current_node->right;
+ }
+ new_root->left = current_node;
+ new_root->right = right_root;
+ new_root->balance = new_right_height - current_height;
+ *this = new_root;
+ } else {
+ /* This case is symmetric to the previous case */
+ TreeDbTerm * new_root =
+ LINKOUT_MAX_TREE_NODE(&left_root);
+ int new_left_height = compute_tree_hight(left_root);
+ TreeDbTerm * current_node = right_root;
+ this = &right_root;
+ current_height = right_height;
+ while (current_height > new_left_height + 1) {
+ if (current_node->balance == 1) {
+ current_height = current_height - 2;
+ } else {
+ current_height = current_height - 1;
+ }
+ dstack[dpos++] = DIR_LEFT;
+ tstack[tpos++] = this;
+ this = &((*this)->left);
+ current_node = current_node->left;
+ }
+ new_root->right = current_node;
+ new_root->left = left_root;
+ new_root->balance = current_height - new_left_height;
+ *this = new_root;
+ }
+ /* Now we need to continue as if this was during the insert */
+ while (state && ( dir = dstack[--dpos] ) != DIR_END) {
+ this = tstack[--tpos];
+ p = *this;
+ if (dir == DIR_LEFT) {
+ switch (p->balance) {
+ case 1:
+ p->balance = 0;
+ state = 0;
+ break;
+ case 0:
+ p->balance = -1;
+ break;
+ case -1: /* The icky case */
+ p1 = p->left;
+ if (p1->balance == -1) { /* Single LL rotation */
+ p->left = p1->right;
+ p1->right = p;
+ p->balance = 0;
+ (*this) = p1;
+ } else { /* Double RR rotation */
+ p2 = p1->right;
+ p1->right = p2->left;
+ p2->left = p1;
+ p->left = p2->right;
+ p2->right = p;
+ p->balance = (p2->balance == -1) ? +1 : 0;
+ p1->balance = (p2->balance == 1) ? -1 : 0;
+ (*this) = p2;
+ }
+ (*this)->balance = 0;
+ state = 0;
+ break;
+ }
+ } else { /* dir == DIR_RIGHT */
+ switch (p->balance) {
+ case -1:
+ p->balance = 0;
+ state = 0;
+ break;
+ case 0:
+ p->balance = 1;
+ break;
+ case 1:
+ p1 = p->right;
+ if (p1->balance == 1) { /* Single RR rotation */
+ p->right = p1->left;
+ p1->left = p;
+ p->balance = 0;
+ (*this) = p1;
+ } else { /* Double RL rotation */
+ p2 = p1->left;
+ p1->left = p2->right;
+ p2->right = p1;
+ p->right = p2->left;
+ p2->left = p;
+ p->balance = (p2->balance == 1) ? -1 : 0;
+ p1->balance = (p2->balance == -1) ? 1 : 0;
+ (*this) = p2;
+ }
+ (*this)->balance = 0;
+ state = 0;
+ break;
+ }
+ }
+ }
+ /* Return the joined tree */
+ if (left_height >= right_height) {
+ return left_root;
+ } else {
+ return right_root;
+ }
+}
+
+#ifdef DEBUG
+# define FORCE_RANDOM_SPLIT_JOIN
+#endif
+#ifdef FORCE_RANDOM_SPLIT_JOIN
+static int dbg_fastrand(void)
+{
+ static int g_seed = 648835;
+ g_seed = (214013*g_seed+2531011);
+ return (g_seed>>16)&0x7FFF;
+}
+
+static void dbg_maybe_force_splitjoin(DbTableCATreeNode* base_node)
+{
+ switch (dbg_fastrand() % 8) {
+ case 1:
+ base_node->u.base.lock_statistics = 1+ERL_DB_CATREE_HIGH_CONTENTION_LIMIT;
+ break;
+ case 2:
+ base_node->u.base.lock_statistics = -1+ERL_DB_CATREE_LOW_CONTENTION_LIMIT;
+ break;
+ }
+}
+#else
+# define dbg_maybe_force_splitjoin(N)
+#endif /* FORCE_RANDOM_SPLIT_JOIN */
+
+static ERTS_INLINE
+int try_wlock_base_node(DbTableCATreeBaseNode *base_node)
+{
+ return EBUSY == erts_rwmtx_tryrwlock(&base_node->lock);
+}
+
+/*
+ * Locks a base node without adjusting the lock statistics
+ */
+static ERTS_INLINE
+void wlock_base_node_no_stats(DbTableCATreeNode *base_node)
+{
+ ASSERT(base_node->is_base_node);
+ erts_rwmtx_rwlock(&base_node->u.base.lock);
+}
+
+/*
+ * Locks a base node and adjusts the lock statistics according to if
+ * the lock was contended or not
+ */
+static ERTS_INLINE
+void wlock_base_node(DbTableCATreeNode *base_node)
+{
+ ASSERT(base_node->is_base_node);
+ if (try_wlock_base_node(&base_node->u.base)) {
+ /* The lock is contended */
+ wlock_base_node_no_stats(base_node);
+ base_node->u.base.lock_statistics += ERL_DB_CATREE_LOCK_FAILURE_CONTRIBUTION;
+ } else {
+ base_node->u.base.lock_statistics += ERL_DB_CATREE_LOCK_SUCCESS_CONTRIBUTION;
+ }
+}
+
+static ERTS_INLINE
+void wunlock_base_node(DbTableCATreeNode *base_node)
+{
+ erts_rwmtx_rwunlock(&base_node->u.base.lock);
+}
+
+static ERTS_INLINE
+void wunlock_adapt_base_node(DbTableCATree* tb,
+ DbTableCATreeNode* node,
+ DbTableCATreeNode* parent,
+ int current_level)
+{
+ dbg_maybe_force_splitjoin(node);
+ if ((!node->u.base.root && parent && !(tb->common.status
+ & DB_CATREE_FORCE_SPLIT))
+ || node->u.base.lock_statistics < ERL_DB_CATREE_LOW_CONTENTION_LIMIT) {
+ join_catree(tb, node, parent);
+ }
+ else if (node->u.base.lock_statistics > ERL_DB_CATREE_HIGH_CONTENTION_LIMIT
+ && current_level < ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT) {
+ split_catree(tb, node, parent);
+ }
+ else {
+ wunlock_base_node(node);
+ }
+}
+
+static ERTS_INLINE
+void rlock_base_node(DbTableCATreeNode *base_node)
+{
+ ASSERT(base_node->is_base_node);
+ erts_rwmtx_rlock(&base_node->u.base.lock);
+}
+
+static ERTS_INLINE
+void runlock_base_node(DbTableCATreeNode *base_node)
+{
+ ASSERT(base_node->is_base_node);
+ erts_rwmtx_runlock(&base_node->u.base.lock);
+}
+
+static ERTS_INLINE
+void lock_route_node(DbTableCATreeNode *route_node)
+{
+ ASSERT(!route_node->is_base_node);
+ erts_mtx_lock(&route_node->u.route.lock);
+}
+
+static ERTS_INLINE
+void unlock_route_node(DbTableCATreeNode *route_node)
+{
+ ASSERT(!route_node->is_base_node);
+ erts_mtx_unlock(&route_node->u.route.lock);
+}
+
+static ERTS_INLINE
+void init_root_iterator(DbTableCATree* tb, CATreeRootIterator* iter,
+ int read_only)
+{
+ iter->tb = tb;
+ iter->read_only = read_only;
+ iter->locked_bnode = NULL;
+ iter->next_route_key = THE_NON_VALUE;
+ iter->search_key = NULL;
+}
+
+static ERTS_INLINE
+void lock_iter_base_node(CATreeRootIterator* iter,
+ DbTableCATreeNode *base_node,
+ DbTableCATreeNode *parent,
+ int current_level)
+{
+ ASSERT(!iter->locked_bnode);
+ if (iter->read_only)
+ rlock_base_node(base_node);
+ else {
+ wlock_base_node(base_node);
+ iter->bnode_parent = parent;
+ iter->bnode_level = current_level;
+ }
+ iter->locked_bnode = base_node;
+}
+
+static ERTS_INLINE
+void unlock_iter_base_node(CATreeRootIterator* iter)
+{
+ ASSERT(iter->locked_bnode);
+ if (iter->read_only)
+ runlock_base_node(iter->locked_bnode);
+ else if (iter->locked_bnode->u.base.is_valid) {
+ wunlock_adapt_base_node(iter->tb, iter->locked_bnode,
+ iter->bnode_parent, iter->bnode_level);
+ }
+ else
+ wunlock_base_node(iter->locked_bnode);
+ iter->locked_bnode = NULL;
+}
+
+static ERTS_INLINE
+void destroy_root_iterator(CATreeRootIterator* iter)
+{
+ if (iter->locked_bnode)
+ unlock_iter_base_node(iter);
+ if (iter->search_key)
+ erts_free(ERTS_ALC_T_DB_TMP, iter->search_key);
+}
+
+
+typedef struct
+{
+ DbTableCATreeNode *parent;
+ int current_level;
+} FindBaseNode;
+
+static ERTS_INLINE
+DbTableCATreeNode* find_base_node(DbTableCATree* tb, Eterm key,
+ FindBaseNode* fbn)
+{
+ DbTableCATreeNode* ERTS_RESTRICT node = GET_ROOT_ACQB(tb);
+ if (fbn) {
+ fbn->parent = NULL;
+ fbn->current_level = 0;
+ }
+ while (!node->is_base_node) {
+ if (fbn) {
+ fbn->current_level++;
+ fbn->parent = node;
+ }
+ if (cmp_key_route(key, node) < 0) {
+ node = GET_LEFT_ACQB(node);
+ } else {
+ node = GET_RIGHT_ACQB(node);
+ }
+ }
+ return node;
+}
+
+static ERTS_INLINE
+DbTableCATreeNode* find_rlock_valid_base_node(DbTableCATree* tb, Eterm key)
+{
+ DbTableCATreeNode* base_node;
+
+ while (1) {
+ base_node = find_base_node(tb, key, NULL);
+ rlock_base_node(base_node);
+ if (base_node->u.base.is_valid)
+ break;
+ runlock_base_node(base_node);
+ }
+ return base_node;
+}
+
+static ERTS_INLINE
+DbTableCATreeNode* find_wlock_valid_base_node(DbTableCATree* tb, Eterm key,
+ FindBaseNode* fbn)
+{
+ DbTableCATreeNode* base_node;
+
+ while (1) {
+ base_node = find_base_node(tb, key, fbn);
+ wlock_base_node(base_node);
+ if (base_node->u.base.is_valid)
+ break;
+ wunlock_base_node(base_node);
+ }
+ return base_node;
+}
+
+static ERTS_INLINE
+Eterm copy_route_key(DbRouteKey* dst, Eterm key, Uint key_size)
+{
+ dst->size = key_size;
+ if (key_size != 0) {
+ Eterm* hp = &dst->heap[0];
+ ErlOffHeap tmp_offheap;
+ tmp_offheap.first = NULL;
+ dst->term = copy_struct(key, key_size, &hp, &tmp_offheap);
+ dst->oh = tmp_offheap.first;
+ }
+ else {
+ ASSERT(is_immed(key));
+ dst->term = key;
+ dst->oh = NULL;
+ }
+ return dst->term;
+}
+
+static ERTS_INLINE
+void destroy_route_key(DbRouteKey* key)
+{
+ if (key->oh) {
+ ErlOffHeap oh;
+ oh.first = key->oh;
+ erts_cleanup_offheap(&oh);
+ }
+}
+
+
+#ifdef ERTS_ENABLE_LOCK_CHECK
+# define LC_ORDER(ORDER) ORDER
+#else
+# define LC_ORDER(ORDER) NIL
+#endif
+
+#define sizeof_base_node() \
+ offsetof(DbTableCATreeNode, u.base.end_of_struct__)
+
+static DbTableCATreeNode *create_base_node(DbTableCATree *tb,
+ TreeDbTerm* root)
+{
+ DbTableCATreeNode *p;
+ erts_rwmtx_opt_t rwmtx_opt = ERTS_RWMTX_OPT_DEFAULT_INITER;
+ p = erts_db_alloc(ERTS_ALC_T_DB_TABLE, (DbTable *) tb,
+ sizeof_base_node());
+
+ p->is_base_node = 1;
+ p->u.base.root = root;
+ if (tb->common.type & DB_FREQ_READ)
+ rwmtx_opt.type = ERTS_RWMTX_TYPE_FREQUENT_READ;
+ if (erts_ets_rwmtx_spin_count >= 0)
+ rwmtx_opt.main_spincount = erts_ets_rwmtx_spin_count;
+
+ erts_rwmtx_init_opt(&p->u.base.lock, &rwmtx_opt,
+ "erl_db_catree_base_node",
+ NIL,
+ ERTS_LOCK_FLAGS_CATEGORY_DB);
+ p->u.base.lock_statistics = ((tb->common.status & DB_CATREE_FORCE_SPLIT)
+ ? INT_MAX : 0);
+ p->u.base.is_valid = 1;
+ return p;
+}
+
+static ERTS_INLINE Uint sizeof_route_node(Uint key_size)
+{
+ return (offsetof(DbTableCATreeNode, u.route.key.heap)
+ + key_size*sizeof(Eterm));
+}
+
+static DbTableCATreeNode*
+create_route_node(DbTableCATree *tb,
+ DbTableCATreeNode *left,
+ DbTableCATreeNode *right,
+ DbTerm * keyTerm,
+ DbTableCATreeNode* lc_parent)
+{
+ Eterm key = GETKEY(tb,keyTerm->tpl);
+ int key_size = size_object(key);
+ DbTableCATreeNode* p = erts_db_alloc(ERTS_ALC_T_DB_TABLE,
+ (DbTable *) tb,
+ sizeof_route_node(key_size));
+
+ copy_route_key(&p->u.route.key, key, key_size);
+ p->is_base_node = 0;
+ p->u.route.is_valid = 1;
+ erts_atomic_init_nob(&p->u.route.left, (erts_aint_t)left);
+ erts_atomic_init_nob(&p->u.route.right, (erts_aint_t)right);
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ /* Route node lock order is inverse tree depth (from leafs toward root) */
+ p->u.route.lc_order = (lc_parent == NULL ? MAX_SMALL :
+ lc_parent->u.route.lc_order - 1);
+ /*
+ * This assert may eventually fail as we don't increase 'lc_order' in join
+ * operations when route nodes move up in the tree.
+ * Tough luck if you run a lock-checking VM for such a long time on 32-bit.
+ */
+ ERTS_LC_ASSERT(p->u.route.lc_order >= 0);
+#endif
+ erts_mtx_init(&p->u.route.lock, "erl_db_catree_route_node",
+ LC_ORDER(make_small(p->u.route.lc_order)),
+ ERTS_LOCK_FLAGS_CATEGORY_DB);
+ return p;
+}
+
+static void do_free_base_node(void* vptr)
+{
+ DbTableCATreeNode *p = (DbTableCATreeNode *)vptr;
+ ASSERT(p->is_base_node);
+ erts_rwmtx_destroy(&p->u.base.lock);
+ erts_free(ERTS_ALC_T_DB_TABLE, p);
+}
+
+static void free_catree_base_node(DbTableCATree* tb, DbTableCATreeNode* p)
+{
+ ASSERT(p->is_base_node);
+ ERTS_DB_ALC_MEM_UPDATE_(tb, sizeof_base_node(), 0);
+ do_free_base_node(p);
+}
+
+static void do_free_route_node(void *vptr)
+{
+ DbTableCATreeNode *p = (DbTableCATreeNode *)vptr;
+ ASSERT(!p->is_base_node);
+ erts_mtx_destroy(&p->u.route.lock);
+ destroy_route_key(&p->u.route.key);
+ erts_free(ERTS_ALC_T_DB_TABLE, p);
+}
+
+static void free_catree_route_node(DbTableCATree* tb, DbTableCATreeNode* p)
+{
+ ASSERT(!p->is_base_node);
+ ERTS_DB_ALC_MEM_UPDATE_(tb, sizeof_route_node(p->u.route.key.size), 0);
+ do_free_route_node(p);
+}
+
+
+/*
+ * Returns the parent routing node of the specified
+ * route node 'child' if such a parent exists
+ * or NULL if 'child' is attached to the root.
+ */
+static ERTS_INLINE DbTableCATreeNode *
+parent_of(DbTableCATree *tb,
+ DbTableCATreeNode *child)
+{
+ Eterm key = GET_ROUTE_NODE_KEY(child);
+ DbTableCATreeNode *current = GET_ROOT_ACQB(tb);
+ DbTableCATreeNode *prev = NULL;
+
+ while (current != child) {
+ prev = current;
+ if (cmp_key_route(key, current) < 0) {
+ current = GET_LEFT_ACQB(current);
+ } else {
+ current = GET_RIGHT_ACQB(current);
+ }
+ }
+ return prev;
+}
+
+
+static ERTS_INLINE DbTableCATreeNode *
+leftmost_base_node(DbTableCATreeNode *root)
+{
+ DbTableCATreeNode *node = root;
+ while (!node->is_base_node) {
+ node = GET_LEFT_ACQB(node);
+ }
+ return node;
+}
+
+
+static ERTS_INLINE DbTableCATreeNode *
+rightmost_base_node(DbTableCATreeNode *root)
+{
+ DbTableCATreeNode *node = root;
+ while (!node->is_base_node) {
+ node = GET_RIGHT_ACQB(node);
+ }
+ return node;
+}
+
+
+static ERTS_INLINE DbTableCATreeNode *
+leftmost_route_node(DbTableCATreeNode *root)
+{
+ DbTableCATreeNode *node = root;
+ DbTableCATreeNode *prev_node = NULL;
+ while (!node->is_base_node) {
+ prev_node = node;
+ node = GET_LEFT_ACQB(node);
+ }
+ return prev_node;
+}
+
+static ERTS_INLINE DbTableCATreeNode*
+rightmost_route_node(DbTableCATreeNode *root)
+{
+ DbTableCATreeNode * node = root;
+ DbTableCATreeNode * prev_node = NULL;
+ while (!node->is_base_node) {
+ prev_node = node;
+ node = GET_RIGHT_ACQB(node);
+ }
+ return prev_node;
+}
+
+static ERTS_INLINE
+void init_tree_stack(DbTreeStack *stack,
+ TreeDbTerm **stack_array,
+ Uint init_slot)
+{
+ stack->array = stack_array;
+ stack->pos = 0;
+ stack->slot = init_slot;
+}
+
+static void join_catree(DbTableCATree *tb,
+ DbTableCATreeNode *thiz,
+ DbTableCATreeNode *parent)
+{
+ DbTableCATreeNode *gparent;
+ DbTableCATreeNode *neighbor;
+ DbTableCATreeNode *new_neighbor;
+ DbTableCATreeNode *neighbor_parent;
+
+ ASSERT(thiz->is_base_node);
+ if (parent == NULL) {
+ thiz->u.base.lock_statistics = 0;
+ wunlock_base_node(thiz);
+ return;
+ }
+ ASSERT(!parent->is_base_node);
+ if (GET_LEFT(parent) == thiz) {
+ neighbor = leftmost_base_node(GET_RIGHT_ACQB(parent));
+ if (try_wlock_base_node(&neighbor->u.base)) {
+ /* Failed to acquire lock */
+ thiz->u.base.lock_statistics = 0;
+ wunlock_base_node(thiz);
+ return;
+ } else if (!neighbor->u.base.is_valid) {
+ thiz->u.base.lock_statistics = 0;
+ wunlock_base_node(thiz);
+ wunlock_base_node(neighbor);
+ return;
+ } else {
+ lock_route_node(parent);
+ parent->u.route.is_valid = 0;
+ neighbor->u.base.is_valid = 0;
+ thiz->u.base.is_valid = 0;
+ gparent = NULL;
+ do {
+ if (gparent != NULL) {
+ unlock_route_node(gparent);
+ }
+ gparent = parent_of(tb, parent);
+ if (gparent != NULL)
+ lock_route_node(gparent);
+ } while (gparent != NULL && !gparent->u.route.is_valid);
+
+ if (gparent == NULL) {
+ SET_ROOT_RELB(tb, GET_RIGHT(parent));
+ } else if (GET_LEFT(gparent) == parent) {
+ SET_LEFT_RELB(gparent, GET_RIGHT(parent));
+ } else {
+ SET_RIGHT_RELB(gparent, GET_RIGHT(parent));
+ }
+ unlock_route_node(parent);
+ if (gparent != NULL) {
+ unlock_route_node(gparent);
+ }
+ {
+ TreeDbTerm* new_root = join_trees(thiz->u.base.root,
+ neighbor->u.base.root);
+ new_neighbor = create_base_node(tb, new_root);
+ }
+ if (GET_RIGHT(parent) == neighbor) {
+ neighbor_parent = gparent;
+ } else {
+ neighbor_parent = leftmost_route_node(GET_RIGHT(parent));
+ }
+ }
+ } else { /* Symetric case */
+ ASSERT(GET_RIGHT(parent) == thiz);
+ neighbor = rightmost_base_node(GET_LEFT_ACQB(parent));
+ if (try_wlock_base_node(&neighbor->u.base)) {
+ /* Failed to acquire lock */
+ thiz->u.base.lock_statistics = 0;
+ wunlock_base_node(thiz);
+ return;
+ } else if (!neighbor->u.base.is_valid) {
+ thiz->u.base.lock_statistics = 0;
+ wunlock_base_node(thiz);
+ wunlock_base_node(neighbor);
+ return;
+ } else {
+ lock_route_node(parent);
+ parent->u.route.is_valid = 0;
+ neighbor->u.base.is_valid = 0;
+ thiz->u.base.is_valid = 0;
+ gparent = NULL;
+ do {
+ if (gparent != NULL) {
+ unlock_route_node(gparent);
+ }
+ gparent = parent_of(tb, parent);
+ if (gparent != NULL) {
+ lock_route_node(gparent);
+ } else {
+ gparent = NULL;
+ }
+ } while (gparent != NULL && !gparent->u.route.is_valid);
+ if (gparent == NULL) {
+ SET_ROOT_RELB(tb, GET_LEFT(parent));
+ } else if (GET_RIGHT(gparent) == parent) {
+ SET_RIGHT_RELB(gparent, GET_LEFT(parent));
+ } else {
+ SET_LEFT_RELB(gparent, GET_LEFT(parent));
+ }
+ unlock_route_node(parent);
+ if (gparent != NULL) {
+ unlock_route_node(gparent);
+ }
+ {
+ TreeDbTerm* new_root = join_trees(neighbor->u.base.root,
+ thiz->u.base.root);
+ new_neighbor = create_base_node(tb, new_root);
+ }
+ if (GET_LEFT(parent) == neighbor) {
+ neighbor_parent = gparent;
+ } else {
+ neighbor_parent =
+ rightmost_route_node(GET_LEFT(parent));
+ }
+ }
+ }
+ /* Link in new neighbor and free nodes that are no longer in the tree */
+ if (neighbor_parent == NULL) {
+ SET_ROOT_RELB(tb, new_neighbor);
+ } else if (GET_LEFT(neighbor_parent) == neighbor) {
+ SET_LEFT_RELB(neighbor_parent, new_neighbor);
+ } else {
+ SET_RIGHT_RELB(neighbor_parent, new_neighbor);
+ }
+ wunlock_base_node(thiz);
+ wunlock_base_node(neighbor);
+ /* Free the parent and base */
+ erts_schedule_db_free(&tb->common,
+ do_free_route_node,
+ parent,
+ &parent->u.route.free_item,
+ sizeof_route_node(parent->u.route.key.size));
+ erts_schedule_db_free(&tb->common,
+ do_free_base_node,
+ thiz,
+ &thiz->u.base.free_item,
+ sizeof_base_node());
+ erts_schedule_db_free(&tb->common,
+ do_free_base_node,
+ neighbor,
+ &neighbor->u.base.free_item,
+ sizeof_base_node());
+}
+
+static void split_catree(DbTableCATree *tb,
+ DbTableCATreeNode* ERTS_RESTRICT base,
+ DbTableCATreeNode* ERTS_RESTRICT parent)
+{
+ TreeDbTerm *splitOutWriteBack;
+ DbTableCATreeNode* ERTS_RESTRICT new_left;
+ DbTableCATreeNode* ERTS_RESTRICT new_right;
+ DbTableCATreeNode* ERTS_RESTRICT new_route;
+
+ if (less_than_two_elements(base->u.base.root)) {
+ if (!(tb->common.status & DB_CATREE_FORCE_SPLIT))
+ base->u.base.lock_statistics = 0;
+ wunlock_base_node(base);
+ return;
+ } else {
+ TreeDbTerm *left_tree;
+ TreeDbTerm *right_tree;
+
+ split_tree(tb, base->u.base.root, &splitOutWriteBack,
+ &left_tree, &right_tree);
+
+ new_left = create_base_node(tb, left_tree);
+ new_right = create_base_node(tb, right_tree);
+ new_route = create_route_node(tb,
+ new_left,
+ new_right,
+ &splitOutWriteBack->dbterm,
+ parent);
+ if (parent == NULL) {
+ SET_ROOT_RELB(tb, new_route);
+ } else if(GET_LEFT(parent) == base) {
+ SET_LEFT_RELB(parent, new_route);
+ } else {
+ SET_RIGHT_RELB(parent, new_route);
+ }
+ base->u.base.is_valid = 0;
+ wunlock_base_node(base);
+ erts_schedule_db_free(&tb->common,
+ do_free_base_node,
+ base,
+ &base->u.base.free_item,
+ sizeof_base_node());
+ }
+}
+
+/*
+ * Helper functions for removing the table
+ */
+
+static void catree_add_base_node_to_free_list(
+ DbTableCATree *tb,
+ DbTableCATreeNode *base_node_container)
+{
+ base_node_container->u.base.next =
+ tb->base_nodes_to_free_list;
+ tb->base_nodes_to_free_list = base_node_container;
+}
+
+static void catree_deque_base_node_from_free_list(DbTableCATree *tb)
+{
+ if (tb->base_nodes_to_free_list == NULL) {
+ return; /* List empty */
+ } else {
+ DbTableCATreeNode *first = tb->base_nodes_to_free_list;
+ tb->base_nodes_to_free_list = first->u.base.next;
+ }
+}
+
+static DbTableCATreeNode *catree_first_base_node_from_free_list(
+ DbTableCATree *tb)
+{
+ return tb->base_nodes_to_free_list;
+}
+
+static SWord do_free_routing_nodes_catree_cont(DbTableCATree *tb, SWord num_left)
+{
+ DbTableCATreeNode *root;
+ DbTableCATreeNode *p;
+ for (;;) {
+ root = POP_NODE(&tb->free_stack_rnodes);
+ if (root == NULL) break;
+ else if(root->is_base_node) {
+ catree_add_base_node_to_free_list(tb, root);
+ break;
+ }
+ for (;;) {
+ if ((GET_LEFT(root) != NULL) &&
+ (p = GET_LEFT(root))->is_base_node) {
+ SET_LEFT(root, NULL);
+ catree_add_base_node_to_free_list(tb, p);
+ } else if ((GET_RIGHT(root) != NULL) &&
+ (p = GET_RIGHT(root))->is_base_node) {
+ SET_RIGHT(root, NULL);
+ catree_add_base_node_to_free_list(tb, p);
+ } else if ((p = GET_LEFT(root)) != NULL) {
+ SET_LEFT(root, NULL);
+ PUSH_NODE(&tb->free_stack_rnodes, root);
+ root = p;
+ } else if ((p = GET_RIGHT(root)) != NULL) {
+ SET_RIGHT(root, NULL);
+ PUSH_NODE(&tb->free_stack_rnodes, root);
+ root = p;
+ } else {
+ free_catree_route_node(tb, root);
+ if (--num_left >= 0) {
+ break;
+ } else {
+ return num_left; /* Done enough for now */
+ }
+ }
+ }
+ }
+ return num_left;
+}
+
+static SWord do_free_base_node_cont(DbTableCATree *tb, SWord num_left)
+{
+ TreeDbTerm *root;
+ TreeDbTerm *p;
+ DbTableCATreeNode *base_node_container =
+ catree_first_base_node_from_free_list(tb);
+ for (;;) {
+ root = POP_NODE(&tb->free_stack_elems);
+ if (root == NULL) break;
+ for (;;) {
+ if ((p = root->left) != NULL) {
+ root->left = NULL;
+ PUSH_NODE(&tb->free_stack_elems, root);
+ root = p;
+ } else if ((p = root->right) != NULL) {
+ root->right = NULL;
+ PUSH_NODE(&tb->free_stack_elems, root);
+ root = p;
+ } else {
+ free_term((DbTable*)tb, root);
+ if (--num_left >= 0) {
+ break;
+ } else {
+ return num_left; /* Done enough for now */
+ }
+ }
+ }
+ }
+ catree_deque_base_node_from_free_list(tb);
+ free_catree_base_node(tb, base_node_container);
+ base_node_container = catree_first_base_node_from_free_list(tb);
+ if (base_node_container != NULL) {
+ PUSH_NODE(&tb->free_stack_elems, base_node_container->u.base.root);
+ }
+ return num_left;
+}
+
+
+/*
+** Initialization function
+*/
+
+void db_initialize_catree(void)
+{
+ return;
+};
+
+/*
+** Table interface routines (i.e., what's called by the bif's)
+*/
+
+int db_create_catree(Process *p, DbTable *tbl)
+{
+ DbTableCATree *tb = &tbl->catree;
+ DbTableCATreeNode *root;
+
+ root = create_base_node(tb, NULL);
+ tb->deletion = 0;
+ tb->base_nodes_to_free_list = NULL;
+ erts_atomic_init_relb(&(tb->root), (erts_aint_t)root);
+ return DB_ERROR_NONE;
+}
+
+static int db_first_catree(Process *p, DbTable *tbl, Eterm *ret)
+{
+ TreeDbTerm *root;
+ CATreeRootIterator iter;
+ int result;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ root = *catree_find_first_root(&iter);
+ if (!root) {
+ TreeDbTerm **pp = catree_find_next_root(&iter, NULL);
+ root = pp ? *pp : NULL;
+ }
+
+ result = db_first_tree_common(p, tbl, root, ret, NULL);
+
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_next_catree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTreeStack stack;
+ TreeDbTerm * stack_array[STACK_NEED];
+ TreeDbTerm **rootp;
+ CATreeRootIterator iter;
+ int result;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ iter.next_route_key = key;
+ rootp = catree_find_next_root(&iter, NULL);
+
+ do {
+ init_tree_stack(&stack, stack_array, 0);
+ result = db_next_tree_common(p, tbl, (rootp ? *rootp : NULL), key, ret, &stack);
+ if (result != DB_ERROR_NONE || *ret != am_EOT)
+ break;
+
+ rootp = catree_find_next_root(&iter, NULL);
+ } while (rootp);
+
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_last_catree(Process *p, DbTable *tbl, Eterm *ret)
+{
+ TreeDbTerm *root;
+ CATreeRootIterator iter;
+ int result;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ root = *catree_find_last_root(&iter);
+ if (!root) {
+ TreeDbTerm **pp = catree_find_prev_root(&iter, NULL);
+ root = pp ? *pp : NULL;
+ }
+
+ result = db_last_tree_common(p, tbl, root, ret, NULL);
+
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_prev_catree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTreeStack stack;
+ TreeDbTerm * stack_array[STACK_NEED];
+ TreeDbTerm **rootp;
+ CATreeRootIterator iter;
+ int result;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ iter.next_route_key = key;
+ rootp = catree_find_prev_root(&iter, NULL);
+
+ do {
+ init_tree_stack(&stack, stack_array, 0);
+ result = db_prev_tree_common(p, tbl, (rootp ? *rootp : NULL), key, ret,
+ &stack);
+ if (result != DB_ERROR_NONE || *ret != am_EOT)
+ break;
+ rootp = catree_find_prev_root(&iter, NULL);
+ } while (rootp);
+
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_put_catree(DbTable *tbl, Eterm obj, int key_clash_fail)
+{
+ DbTableCATree *tb = &tbl->catree;
+ Eterm key = GETKEY(&tb->common, tuple_val(obj));
+ FindBaseNode fbn;
+ DbTableCATreeNode* node = find_wlock_valid_base_node(tb, key, &fbn);
+ int result = db_put_tree_common(&tb->common, &node->u.base.root, obj,
+ key_clash_fail, NULL);
+ wunlock_adapt_base_node(tb, node, fbn.parent, fbn.current_level);
+ return result;
+}
+
+static int db_get_catree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ DbTableCATreeNode* node = find_rlock_valid_base_node(tb, key);
+ int result = db_get_tree_common(p, &tb->common,
+ node->u.base.root,
+ key, ret, NULL);
+ runlock_base_node(node);
+ return result;
+}
+
+TreeDbTerm** catree_find_root(Eterm key, CATreeRootIterator* iter)
+{
+ FindBaseNode fbn;
+ DbTableCATreeNode* base_node;
+
+ while (1) {
+ base_node = find_base_node(iter->tb, key, &fbn);
+ lock_iter_base_node(iter, base_node, fbn.parent, fbn.current_level);
+ if (base_node->u.base.is_valid)
+ break;
+ unlock_iter_base_node(iter);
+ }
+ return &base_node->u.base.root;
+}
+
+
+TreeDbTerm** catree_find_prev_from_pb_key_root(Eterm key,
+ CATreeRootIterator* iter)
+{
+#ifdef DEBUG
+ DbTableCATreeNode *rejected_base = NULL;
+#endif
+ DbTableCATreeNode *node;
+ DbTableCATreeNode *parent;
+ DbTableCATreeNode* next_route_node;
+ int current_level;
+
+ ASSERT(!iter->locked_bnode);
+
+ while (1) {
+ node = GET_ROOT_ACQB(iter->tb);
+ current_level = 0;
+ parent = NULL;
+ next_route_node = NULL;
+ while (!node->is_base_node) {
+ current_level++;
+ parent = node;
+ if (cmp_partly_bound(key, GET_ROUTE_NODE_KEY(node)) <= 0) {
+ next_route_node = node;
+ node = GET_LEFT_ACQB(node);
+ } else {
+ node = GET_RIGHT_ACQB(node);
+ }
+ }
+ ASSERT(node != rejected_base);
+ lock_iter_base_node(iter, node, parent, current_level);
+ if (node->u.base.is_valid) {
+ iter->next_route_key = (next_route_node ?
+ next_route_node->u.route.key.term :
+ THE_NON_VALUE);
+ return &node->u.base.root;
+ }
+ /* Retry */
+ unlock_iter_base_node(iter);
+#ifdef DEBUG
+ rejected_base = node;
+#endif
+ }
+}
+
+static Eterm copy_iter_search_key(CATreeRootIterator* iter, Eterm key)
+{
+ Uint key_size;
+
+ if (is_immed(key))
+ return key;
+
+ if (iter->search_key) {
+ ASSERT(key != iter->search_key->term);
+ destroy_route_key(iter->search_key);
+ }
+ key_size = size_object(key);
+ if (!iter->search_key || key_size > iter->search_key->size) {
+ iter->search_key = erts_realloc(ERTS_ALC_T_DB_TMP,
+ iter->search_key,
+ (offsetof(DbRouteKey, heap)
+ + key_size*sizeof(Eterm)));
+ }
+ return copy_route_key(iter->search_key, key, key_size);
+}
+
+TreeDbTerm** catree_find_nextprev_root(CATreeRootIterator *iter, int next,
+ Eterm *keyp)
+{
+#ifdef DEBUG
+ DbTableCATreeNode *rejected_invalid = NULL;
+ DbTableCATreeNode *rejected_empty = NULL;
+#endif
+ DbTableCATreeNode *node;
+ DbTableCATreeNode *parent;
+ DbTableCATreeNode* next_route_node;
+ Eterm key = iter->next_route_key;
+ int current_level;
+
+ if (iter->locked_bnode) {
+ if (keyp)
+ *keyp = copy_iter_search_key(iter, *keyp);
+ unlock_iter_base_node(iter);
+ }
+
+ if (is_non_value(key))
+ return NULL;
+
+ while (1) {
+ node = GET_ROOT_ACQB(iter->tb);
+ current_level = 0;
+ parent = NULL;
+ next_route_node = NULL;
+ while (!node->is_base_node) {
+ current_level++;
+ parent = node;
+ if (next) {
+ if (cmp_key_route(key,node) < 0) {
+ next_route_node = node;
+ node = GET_LEFT_ACQB(node);
+ } else {
+ node = GET_RIGHT_ACQB(node);
+ }
+ }
+ else {
+ if (cmp_key_route(key,node) > 0) {
+ next_route_node = node;
+ node = GET_RIGHT_ACQB(node);
+ } else {
+ node = GET_LEFT_ACQB(node);
+ }
+ }
+ }
+ ASSERT(node != rejected_invalid);
+ lock_iter_base_node(iter, node, parent, current_level);
+ if (node->u.base.is_valid) {
+ ASSERT(node != rejected_empty);
+ if (node->u.base.root) {
+ iter->next_route_key = (next_route_node ?
+ next_route_node->u.route.key.term :
+ THE_NON_VALUE);
+ iter->locked_bnode = node;
+ return &node->u.base.root;
+ }
+ if (!next_route_node) {
+ unlock_iter_base_node(iter);
+ return NULL;
+ }
+ key = next_route_node->u.route.key.term;
+ IF_DEBUG(rejected_empty = node);
+ }
+ else
+ IF_DEBUG(rejected_invalid = node);
+
+ /* Retry */
+ unlock_iter_base_node(iter);
+ }
+}
+
+TreeDbTerm** catree_find_next_root(CATreeRootIterator *iter, Eterm* keyp)
+{
+ return catree_find_nextprev_root(iter, 1, keyp);
+}
+
+TreeDbTerm** catree_find_prev_root(CATreeRootIterator *iter, Eterm* keyp)
+{
+ return catree_find_nextprev_root(iter, 0, keyp);
+}
+
+
+TreeDbTerm** catree_find_next_from_pb_key_root(Eterm key,
+ CATreeRootIterator* iter)
+{
+#ifdef DEBUG
+ DbTableCATreeNode *rejected_base = NULL;
+#endif
+ DbTableCATreeNode *node;
+ DbTableCATreeNode *parent;
+ DbTableCATreeNode* next_route_node;
+ int current_level;
+
+ ASSERT(!iter->locked_bnode);
+
+ while (1) {
+ node = GET_ROOT_ACQB(iter->tb);
+ current_level = 0;
+ parent = NULL;
+ next_route_node = NULL;
+ while (!node->is_base_node) {
+ current_level++;
+ parent = node;
+ if (cmp_partly_bound(key, GET_ROUTE_NODE_KEY(node)) >= 0) {
+ next_route_node = node;
+ node = GET_RIGHT_ACQB(node);
+ } else {
+ node = GET_LEFT_ACQB(node);
+ }
+ }
+ ASSERT(node != rejected_base);
+ lock_iter_base_node(iter, node, parent, current_level);
+ if (node->u.base.is_valid) {
+ iter->next_route_key = (next_route_node ?
+ next_route_node->u.route.key.term :
+ THE_NON_VALUE);
+ return &node->u.base.root;
+ }
+ /* Retry */
+ unlock_iter_base_node(iter);
+#ifdef DEBUG
+ rejected_base = node;
+#endif
+ }
+}
+
+static TreeDbTerm** catree_find_firstlast_root(CATreeRootIterator* iter,
+ int first)
+{
+#ifdef DEBUG
+ DbTableCATreeNode *rejected_base = NULL;
+#endif
+ DbTableCATreeNode *node;
+ DbTableCATreeNode* next_route_node;
+ int current_level;
+
+ while (1) {
+ node = GET_ROOT_ACQB(iter->tb);
+ current_level = 0;
+ next_route_node = NULL;
+ while (!node->is_base_node) {
+ current_level++;
+ next_route_node = node;
+ node = first ? GET_LEFT_ACQB(node) : GET_RIGHT_ACQB(node);
+ }
+ ASSERT(node != rejected_base);
+ lock_iter_base_node(iter, node, next_route_node, current_level);
+ if (node->u.base.is_valid) {
+ iter->next_route_key = (next_route_node ?
+ next_route_node->u.route.key.term :
+ THE_NON_VALUE);
+ return &node->u.base.root;
+ }
+ /* Retry */
+ unlock_iter_base_node(iter);
+#ifdef DEBUG
+ rejected_base = node;
+#endif
+ }
+}
+
+TreeDbTerm** catree_find_first_root(CATreeRootIterator* iter)
+{
+ return catree_find_firstlast_root(iter, 1);
+}
+
+TreeDbTerm** catree_find_last_root(CATreeRootIterator* iter)
+{
+ return catree_find_firstlast_root(iter, 0);
+}
+
+static int db_member_catree(DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ DbTableCATreeNode* node = find_rlock_valid_base_node(tb, key);
+ int result = db_member_tree_common(&tb->common,
+ node->u.base.root,
+ key, ret, NULL);
+ runlock_base_node(node);
+ return result;
+}
+
+static int db_get_element_catree(Process *p, DbTable *tbl,
+ Eterm key, int ndex, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ DbTableCATreeNode* node = find_rlock_valid_base_node(tb, key);
+ int result = db_get_element_tree_common(p, &tb->common,
+ node->u.base.root,
+ key, ndex, ret, NULL);
+ runlock_base_node(node);
+ return result;
+}
+
+static int db_erase_catree(DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ FindBaseNode fbn;
+ DbTableCATreeNode* node = find_wlock_valid_base_node(tb, key, &fbn);
+ int result = db_erase_tree_common(tbl, &node->u.base.root, key,
+ ret, NULL);
+ wunlock_adapt_base_node(tb, node, fbn.parent, fbn.current_level);
+ return result;
+}
+
+static int db_erase_object_catree(DbTable *tbl, Eterm object, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ Eterm key = GETKEY(&tb->common, tuple_val(object));
+ FindBaseNode fbn;
+ DbTableCATreeNode* node = find_wlock_valid_base_node(tb, key, &fbn);
+ int result = db_erase_object_tree_common(tbl,
+ &node->u.base.root,
+ object,
+ ret,
+ NULL);
+ wunlock_adapt_base_node(tb, node, fbn.parent, fbn.current_level);
+ return result;
+}
+
+
+static int db_slot_catree(Process *p, DbTable *tbl,
+ Eterm slot_term, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_slot_tree_common(p, tbl, *catree_find_first_root(&iter),
+ slot_term, ret, NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_continue_catree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_select_continue_tree_common(p, &tbl->common,
+ continuation, ret, NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, int reverse, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_select_tree_common(p, tbl, tid, pattern, reverse, ret,
+ NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_count_continue_catree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_select_count_continue_tree_common(p, tbl,
+ continuation, ret, NULL,
+ &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_count_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_select_count_tree_common(p, tbl,
+ tid, pattern, ret, NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_chunk_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Sint chunk_size,
+ int reversed, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ result = db_select_chunk_tree_common(p, tbl,
+ tid, pattern, chunk_size, reversed, ret,
+ NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_delete_continue_catree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
+{
+ DbTreeStack stack;
+ TreeDbTerm * stack_array[STACK_NEED];
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 0);
+ init_tree_stack(&stack, stack_array, 0);
+ result = db_select_delete_continue_tree_common(p, tbl, continuation, ret,
+ &stack, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_delete_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ DbTreeStack stack;
+ TreeDbTerm * stack_array[STACK_NEED];
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 0);
+ init_tree_stack(&stack, stack_array, 0);
+ result = db_select_delete_tree_common(p, tbl,
+ tid, pattern, ret, &stack,
+ &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_replace_catree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 0);
+ result = db_select_replace_tree_common(p, tbl,
+ tid, pattern, ret, NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_select_replace_continue_catree(Process *p, DbTable *tbl,
+ Eterm continuation, Eterm *ret)
+{
+ int result;
+ CATreeRootIterator iter;
+
+ init_root_iterator(&tbl->catree, &iter, 0);
+ result = db_select_replace_continue_tree_common(p, tbl, continuation, ret,
+ NULL, &iter);
+ destroy_root_iterator(&iter);
+ return result;
+}
+
+static int db_take_catree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableCATree *tb = &tbl->catree;
+ FindBaseNode fbn;
+ DbTableCATreeNode* node = find_wlock_valid_base_node(tb, key, &fbn);
+ int result = db_take_tree_common(p, tbl, &node->u.base.root, key,
+ ret, NULL);
+ wunlock_adapt_base_node(tb, node, fbn.parent, fbn.current_level);
+ return result;
+}
+
+/*
+** Other interface routines (not directly coupled to one bif)
+*/
+
+
+/* Display tree contents (for dump) */
+static void db_print_catree(fmtfn_t to, void *to_arg,
+ int show, DbTable *tbl)
+{
+ CATreeRootIterator iter;
+ TreeDbTerm** root;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ root = catree_find_first_root(&iter);
+ do {
+ db_print_tree_common(to, to_arg, show, *root, tbl);
+ root = catree_find_next_root(&iter, NULL);
+ } while (root);
+ destroy_root_iterator(&iter);
+}
+
+/* Release all memory occupied by a single table */
+static int db_free_table_catree(DbTable *tbl)
+{
+ while (db_free_table_continue_catree(tbl, ERTS_SWORD_MAX) < 0)
+ ;
+ return 1;
+}
+
+static SWord db_free_table_continue_catree(DbTable *tbl, SWord reds)
+{
+ DbTableCATreeNode *first_base_node;
+ DbTableCATree *tb = &tbl->catree;
+ if (!tb->deletion) {
+ tb->deletion = 1;
+ tb->free_stack_elems.array =
+ erts_db_alloc(ERTS_ALC_T_DB_STK,
+ (DbTable *) tb,
+ sizeof(TreeDbTerm *) * STACK_NEED);
+ tb->free_stack_elems.pos = 0;
+ tb->free_stack_elems.slot = 0;
+ tb->free_stack_rnodes.array =
+ erts_db_alloc(ERTS_ALC_T_DB_STK,
+ (DbTable *) tb,
+ sizeof(DbTableCATreeNode *) * STACK_NEED);
+ tb->free_stack_rnodes.pos = 0;
+ tb->free_stack_rnodes.size = STACK_NEED;
+ PUSH_NODE(&tb->free_stack_rnodes, GET_ROOT(tb));
+ tb->is_routing_nodes_freed = 0;
+ tb->base_nodes_to_free_list = NULL;
+ }
+ if ( ! tb->is_routing_nodes_freed ) {
+ reds = do_free_routing_nodes_catree_cont(tb, reds);
+ if (reds < 0) {
+ return reds; /* Not finished */
+ } else {
+ tb->is_routing_nodes_freed = 1; /* Ready with the routing nodes */
+ first_base_node = catree_first_base_node_from_free_list(tb);
+ PUSH_NODE(&tb->free_stack_elems, first_base_node->u.base.root);
+ }
+ }
+ while (catree_first_base_node_from_free_list(tb) != NULL) {
+ reds = do_free_base_node_cont(tb, reds);
+ if (reds < 0) {
+ return reds; /* Continue later */
+ }
+ }
+ /* Time to free the main structure*/
+ erts_db_free(ERTS_ALC_T_DB_STK,
+ (DbTable *) tb,
+ (void *) tb->free_stack_elems.array,
+ sizeof(TreeDbTerm *) * STACK_NEED);
+ erts_db_free(ERTS_ALC_T_DB_STK,
+ (DbTable *) tb,
+ (void *) tb->free_stack_rnodes.array,
+ sizeof(DbTableCATreeNode *) * STACK_NEED);
+ return 1;
+}
+
+static SWord db_delete_all_objects_catree(Process* p, DbTable* tbl, SWord reds)
+{
+ reds = db_free_table_continue_catree(tbl, reds);
+ if (reds < 0)
+ return reds;
+ db_create_catree(p, tbl);
+ erts_atomic_set_nob(&tbl->catree.common.nitems, 0);
+ return reds;
+}
+
+
+static void db_foreach_offheap_catree(DbTable *tbl,
+ void (*func)(ErlOffHeap *, void *),
+ void *arg)
+{
+ CATreeRootIterator iter;
+ TreeDbTerm** root;
+
+ init_root_iterator(&tbl->catree, &iter, 1);
+ root = catree_find_first_root(&iter);
+ do {
+ db_foreach_offheap_tree_common(*root, func, arg);
+ root = catree_find_next_root(&iter, NULL);
+ } while (root);
+ destroy_root_iterator(&iter);
+}
+
+static int db_lookup_dbterm_catree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
+ DbUpdateHandle *handle)
+{
+ DbTableCATree *tb = &tbl->catree;
+ FindBaseNode fbn;
+ DbTableCATreeNode* node = find_wlock_valid_base_node(tb, key, &fbn);
+ int res = db_lookup_dbterm_tree_common(p, tbl, &node->u.base.root, key,
+ obj, handle, NULL);
+ if (res == 0) {
+ wunlock_adapt_base_node(tb, node, fbn.parent, fbn.current_level);
+ } else {
+ /* db_finalize_dbterm_catree will unlock */
+ handle->u.catree.base_node = node;
+ handle->u.catree.parent = fbn.parent;
+ handle->u.catree.current_level = fbn.current_level;
+ }
+ return res;
+}
+
+static void db_finalize_dbterm_catree(int cret, DbUpdateHandle *handle)
+{
+ DbTableCATree *tb = &(handle->tb->catree);
+ db_finalize_dbterm_tree_common(cret, handle, NULL);
+ wunlock_adapt_base_node(tb, handle->u.catree.base_node,
+ handle->u.catree.parent,
+ handle->u.catree.current_level);
+ return;
+}
+
+#ifdef ERTS_ENABLE_LOCK_COUNT
+static void erts_lcnt_enable_db_catree_lock_count_helper(DbTableCATree *tb,
+ DbTableCATreeNode *node,
+ int enable)
+{
+ erts_lcnt_ref_t *lcnt_ref;
+ erts_lock_flags_t lock_type;
+ if (node->is_base_node) {
+ lcnt_ref = &GET_BASE_NODE_LOCK(node)->lcnt;
+ lock_type = ERTS_LOCK_TYPE_RWMUTEX;
+ } else {
+ erts_lcnt_enable_db_catree_lock_count_helper(tb, GET_LEFT(node), enable);
+ erts_lcnt_enable_db_catree_lock_count_helper(tb, GET_RIGHT(node), enable);
+ lcnt_ref = &GET_ROUTE_NODE_LOCK(node)->lcnt;
+ lock_type = ERTS_LOCK_TYPE_MUTEX;
+ }
+ if (enable) {
+ erts_lcnt_install_new_lock_info(lcnt_ref, "db_hash_slot", tb->common.the_name,
+ lock_type | ERTS_LOCK_FLAGS_CATEGORY_DB);
+ } else {
+ erts_lcnt_uninstall(lcnt_ref);
+ }
+}
+
+void erts_lcnt_enable_db_catree_lock_count(DbTableCATree *tb, int enable)
+{
+ erts_lcnt_enable_db_catree_lock_count_helper(tb, GET_ROOT(tb), enable);
+}
+#endif /* ERTS_ENABLE_LOCK_COUNT */
+
+void db_catree_force_split(DbTableCATree* tb, int on)
+{
+ CATreeRootIterator iter;
+ TreeDbTerm** root;
+
+ init_root_iterator(tb, &iter, 1);
+ root = catree_find_first_root(&iter);
+ do {
+ iter.locked_bnode->u.base.lock_statistics = (on ? INT_MAX : 0);
+ root = catree_find_next_root(&iter, NULL);
+ } while (root);
+ destroy_root_iterator(&iter);
+
+ if (on)
+ tb->common.status |= DB_CATREE_FORCE_SPLIT;
+ else
+ tb->common.status &= ~DB_CATREE_FORCE_SPLIT;
+}
+
+void db_calc_stats_catree(DbTableCATree* tb, DbCATreeStats* stats)
+{
+ DbTableCATreeNode* stack[ERL_DB_CATREE_MAX_ROUTE_NODE_LAYER_HEIGHT];
+ DbTableCATreeNode* node;
+ Uint depth = 0;
+
+ stats->route_nodes = 0;
+ stats->base_nodes = 0;
+ stats->max_depth = 0;
+
+ node = GET_ROOT(tb);
+ do {
+ while (!node->is_base_node) {
+ stats->route_nodes++;
+ ASSERT(depth < sizeof(stack)/sizeof(*stack));
+ stack[depth++] = node; /* PUSH parent */
+ if (stats->max_depth < depth)
+ stats->max_depth = depth;
+ node = GET_LEFT(node);
+ }
+ stats->base_nodes++;
+
+ while (depth > 0) {
+ DbTableCATreeNode* parent = stack[depth-1];
+ if (node == GET_LEFT(parent)) {
+ node = GET_RIGHT(parent);
+ break;
+ }
+ else {
+ ASSERT(node == GET_RIGHT(parent));
+ node = parent;
+ depth--; /* POP parent */
+ }
+ }
+ } while (depth > 0);
+}
+
+#ifdef HARDDEBUG
+
+/*
+ * Not called, but kept as it might come to use
+ */
+static inline int my_check_table_tree(TreeDbTerm *t)
+{
+ int lh, rh;
+ if (t == NULL)
+ return 0;
+ lh = my_check_table_tree(t->left);
+ rh = my_check_table_tree(t->right);
+ if ((rh - lh) != t->balance) {
+ erts_fprintf(stderr, "Invalid tree balance for this node:\n");
+ erts_fprintf(stderr,"balance = %d, left = 0x%08X, right = 0x%08X\n",
+ t->balance, t->left, t->right);
+ erts_fprintf(stderr,"\nDump:\n---------------------------------\n");
+ erts_fprintf(stderr,"\n---------------------------------\n");
+ abort();
+ }
+ return ((rh > lh) ? rh : lh) + 1;
+}
+
+#endif
diff --git a/erts/emulator/beam/erl_db_catree.h b/erts/emulator/beam/erl_db_catree.h
new file mode 100644
index 0000000000..418837be8e
--- /dev/null
+++ b/erts/emulator/beam/erl_db_catree.h
@@ -0,0 +1,133 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Implementation of ETS ordered_set table type with
+ * fine-grained synchronization.
+ *
+ * Author: Kjell Winblad
+ *
+ * "erl_db_catree.c" contains more details about the implementation.
+ *
+ */
+
+#ifndef _DB_CATREE_H
+#define _DB_CATREE_H
+
+struct DbTableCATreeNode;
+
+typedef struct {
+ Eterm term;
+ struct erl_off_heap_header* oh;
+ Uint size;
+ Eterm heap[1];
+} DbRouteKey;
+
+typedef struct {
+ erts_rwmtx_t lock; /* The lock for this base node */
+ Sint lock_statistics;
+ int is_valid; /* If this base node is still valid */
+ TreeDbTerm *root; /* The root of the sequential tree */
+ ErtsThrPrgrLaterOp free_item; /* Used when freeing using thread progress */
+ struct DbTableCATreeNode * next; /* Used when gradually deleting */
+
+ char end_of_struct__;
+} DbTableCATreeBaseNode;
+
+typedef struct {
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ Sint lc_order;
+#endif
+ ErtsThrPrgrLaterOp free_item; /* Used when freeing using thread progress */
+ erts_mtx_t lock; /* Used when joining route nodes */
+ int is_valid; /* If this route node is still valid */
+ erts_atomic_t left;
+ erts_atomic_t right;
+ DbRouteKey key;
+} DbTableCATreeRouteNode;
+
+typedef struct DbTableCATreeNode {
+ int is_base_node;
+ union {
+ DbTableCATreeRouteNode route;
+ DbTableCATreeBaseNode base;
+ } u;
+} DbTableCATreeNode;
+
+typedef struct {
+ Uint pos; /* Current position on stack */
+ Uint size; /* The size of the stack array */
+ DbTableCATreeNode** array; /* The stack */
+} CATreeNodeStack;
+
+typedef struct db_table_catree {
+ DbTableCommon common;
+
+ /* CA Tree-specific fields */
+ erts_atomic_t root; /* The tree root (DbTableCATreeNode*) */
+ Uint deletion; /* Being deleted */
+ DbTreeStack free_stack_elems;/* Used for deletion ...*/
+ CATreeNodeStack free_stack_rnodes;
+ DbTableCATreeNode *base_nodes_to_free_list;
+ int is_routing_nodes_freed;
+} DbTableCATree;
+
+typedef struct {
+ DbTableCATree* tb;
+ Eterm next_route_key;
+ DbTableCATreeNode* locked_bnode;
+ DbTableCATreeNode* bnode_parent;
+ int bnode_level;
+ int read_only;
+ DbRouteKey* search_key;
+} CATreeRootIterator;
+
+
+void db_initialize_catree(void);
+
+int db_create_catree(Process *p, DbTable *tbl);
+
+
+TreeDbTerm** catree_find_root(Eterm key, CATreeRootIterator*);
+
+TreeDbTerm** catree_find_next_from_pb_key_root(Eterm key, CATreeRootIterator*);
+TreeDbTerm** catree_find_prev_from_pb_key_root(Eterm key, CATreeRootIterator*);
+TreeDbTerm** catree_find_nextprev_root(CATreeRootIterator*, int next, Eterm* keyp);
+TreeDbTerm** catree_find_next_root(CATreeRootIterator*, Eterm* keyp);
+TreeDbTerm** catree_find_prev_root(CATreeRootIterator*, Eterm* keyp);
+TreeDbTerm** catree_find_first_root(CATreeRootIterator*);
+TreeDbTerm** catree_find_last_root(CATreeRootIterator*);
+
+
+#ifdef ERTS_ENABLE_LOCK_COUNT
+void erts_lcnt_enable_db_catree_lock_count(DbTableCATree *tb, int enable);
+#endif
+
+void db_catree_force_split(DbTableCATree*, int on);
+
+typedef struct {
+ Uint route_nodes;
+ Uint base_nodes;
+ Uint max_depth;
+} DbCATreeStats;
+void db_calc_stats_catree(DbTableCATree*, DbCATreeStats*);
+
+
+#endif /* _DB_CATREE_H */
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index b988a19cf4..f05a3b51c9 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -150,6 +150,22 @@ static ERTS_INLINE Uint hash_to_ix(DbTableHash* tb, HashValue hval)
}
+static ERTS_INLINE FixedDeletion* alloc_fixdel(DbTableHash* tb)
+{
+ FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
+ (DbTable *) tb,
+ sizeof(FixedDeletion));
+ ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
+ return fixd;
+}
+
+static ERTS_INLINE void free_fixdel(DbTableHash* tb, FixedDeletion* fixd)
+{
+ erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb,
+ fixd, sizeof(FixedDeletion));
+ ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion));
+}
+
static ERTS_INLINE int link_fixdel(DbTableHash* tb,
FixedDeletion* fixd,
erts_aint_t fixated_by_me)
@@ -160,8 +176,7 @@ static ERTS_INLINE int link_fixdel(DbTableHash* tb,
was_next = erts_atomic_read_acqb(&tb->fixdel);
do { /* Lockless atomic insertion in linked list: */
if (NFIXED(tb) <= fixated_by_me) {
- erts_db_free(ERTS_ALC_T_DB_FIX_DEL, (DbTable*)tb,
- fixd, sizeof(FixedDeletion));
+ free_fixdel(tb, fixd);
return 0; /* raced by unfixer */
}
exp_next = was_next;
@@ -180,10 +195,7 @@ static ERTS_INLINE int link_fixdel(DbTableHash* tb,
static int add_fixed_deletion(DbTableHash* tb, int ix,
erts_aint_t fixated_by_me)
{
- FixedDeletion* fixd = (FixedDeletion*) erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
+ FixedDeletion* fixd = alloc_fixdel(tb);
fixd->slot = ix;
fixd->all = 0;
return link_fixdel(tb, fixd, fixated_by_me);
@@ -637,11 +649,7 @@ restart:
free_me = fixdel;
fixdel = fixdel->next;
- erts_db_free(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- (void *) free_me,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion));
+ free_fixdel(tb, free_me);
work++;
}
@@ -2338,11 +2346,10 @@ static SWord db_mark_all_deleted_hash(DbTable *tbl, SWord reds)
}
else {
/* First call */
- fixdel = erts_db_alloc(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(sizeof(FixedDeletion));
- link_fixdel(tb, fixdel, 0);
+ int ok;
+ fixdel = alloc_fixdel(tb);
+ ok = link_fixdel(tb, fixdel, 0);
+ ASSERT(ok); (void)ok;
i = 0;
}
@@ -2444,11 +2451,7 @@ static SWord db_free_table_continue_hash(DbTable *tbl, SWord reds)
FixedDeletion *fx = fixdel;
fixdel = fx->next;
- erts_db_free(ERTS_ALC_T_DB_FIX_DEL,
- (DbTable *) tb,
- (void *) fx,
- sizeof(FixedDeletion));
- ERTS_ETS_MISC_MEM_ADD(-sizeof(FixedDeletion));
+ free_fixdel(tb, fx);
if (--reds < 0) {
erts_atomic_set_relb(&tb->fixdel, (erts_aint_t)fixdel);
return reds; /* Not done */
@@ -2728,13 +2731,9 @@ static int free_seg(DbTableHash *tb, int free_records)
* sure no lingering threads are still hanging in BUCKET macro
* with an old segtab pointer.
*/
- Uint sz = SIZEOF_EXT_SEGTAB(est->nsegs);
- ASSERT(sz == ERTS_ALC_DBG_BLK_SZ(est));
- ERTS_DB_ALC_MEM_UPDATE_(tb, sz, 0);
- erts_schedule_thr_prgr_later_cleanup_op(dealloc_ext_segtab,
- est,
- &est->lop,
- sz);
+ erts_schedule_db_free(&tb->common, dealloc_ext_segtab,
+ est, &est->lop,
+ SIZEOF_EXT_SEGTAB(est->nsegs));
}
else
erts_db_free(ERTS_ALC_T_DB_SEG, (DbTable*)tb, est,
@@ -3104,7 +3103,7 @@ Ldone:
handle->dbterm = &b->dbterm;
handle->flags = flags;
handle->new_size = b->dbterm.size;
- handle->lck = lck;
+ handle->u.hash.lck = lck;
return 1;
}
@@ -3117,7 +3116,7 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
DbTableHash *tb = &tbl->hash;
HashDbTerm **bp = (HashDbTerm **) handle->bp;
HashDbTerm *b = *bp;
- erts_rwmtx_t* lck = (erts_rwmtx_t*) handle->lck;
+ erts_rwmtx_t* lck = handle->u.hash.lck;
HashDbTerm* free_me = NULL;
ERTS_LC_ASSERT(IS_HASH_WLOCKED(tb, lck)); /* locked by db_lookup_dbterm_hash */
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 788718ab09..f5fac9dcb6 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -48,34 +48,13 @@
#include "erl_binary.h"
#include "erl_db_tree.h"
+#include "erl_db_tree_util.h"
#define GETKEY_WITH_POS(Keypos, Tplp) (*((Tplp) + Keypos))
#define NITEMS(tb) ((int)erts_atomic_read_nob(&(tb)->common.nitems))
-/*
-** A stack of this size is enough for an AVL tree with more than
-** 0xFFFFFFFF elements. May be subject to change if
-** the datatype of the element counter is changed to a 64 bit integer.
-** The Maximal height of an AVL tree is calculated as:
-** h(n) <= 1.4404 * log(n + 2) - 0.328
-** Where n denotes the number of nodes, h(n) the height of the tree
-** with n nodes and log is the binary logarithm.
-*/
-
-#define STACK_NEED 50
#define TREE_MAX_ELEMENTS 0xFFFFFFFFUL
-#define PUSH_NODE(Dtt, Tdt) \
- ((Dtt)->array[(Dtt)->pos++] = Tdt)
-
-#define POP_NODE(Dtt) \
- (((Dtt)->pos) ? \
- (Dtt)->array[--((Dtt)->pos)] : NULL)
-
-#define TOP_NODE(Dtt) \
- ((Dtt->pos) ? \
- (Dtt)->array[(Dtt)->pos - 1] : NULL)
-
#define TOPN_NODE(Dtt, Pos) \
(((Pos) < Dtt->pos) ? \
(Dtt)->array[(Dtt)->pos - ((Pos) + 1)] : NULL)
@@ -89,10 +68,12 @@
/* Obtain table static stack if available. NULL if not.
** Must be released with release_stack()
*/
-static DbTreeStack* get_static_stack(DbTableTree* tb)
+ERTS_INLINE static DbTreeStack* get_static_stack(DbTableTree* tb)
{
- if (!erts_atomic_xchg_acqb(&tb->is_stack_busy, 1)) {
- return &tb->static_stack;
+ if (tb != NULL) {
+ ASSERT(IS_TREE_TABLE(tb->common.type));
+ if (!erts_atomic_xchg_acqb(&tb->is_stack_busy, 1))
+ return &tb->static_stack;
}
return NULL;
}
@@ -100,13 +81,15 @@ static DbTreeStack* get_static_stack(DbTableTree* tb)
/* Obtain static stack if available, otherwise empty dynamic stack.
** Must be released with release_stack()
*/
-static DbTreeStack* get_any_stack(DbTableTree* tb)
+static DbTreeStack* get_any_stack(DbTable* tb, DbTableTree* stack_container)
{
DbTreeStack* stack;
- if (!erts_atomic_xchg_acqb(&tb->is_stack_busy, 1)) {
- return &tb->static_stack;
+ if (stack_container != NULL) {
+ ASSERT(IS_TREE_TABLE(stack_container->common.type));
+ if (!erts_atomic_xchg_acqb(&stack_container->is_stack_busy, 1))
+ return &stack_container->static_stack;
}
- stack = erts_db_alloc(ERTS_ALC_T_DB_STK, (DbTable *) tb,
+ stack = erts_db_alloc(ERTS_ALC_T_DB_STK, tb,
sizeof(DbTreeStack) + sizeof(TreeDbTerm*) * STACK_NEED);
stack->pos = 0;
stack->slot = 0;
@@ -114,62 +97,62 @@ static DbTreeStack* get_any_stack(DbTableTree* tb)
return stack;
}
-static void release_stack(DbTableTree* tb, DbTreeStack* stack)
+static void release_stack(DbTable* tb, DbTableTree* stack_container, DbTreeStack* stack)
{
- if (stack == &tb->static_stack) {
- ASSERT(erts_atomic_read_nob(&tb->is_stack_busy) == 1);
- erts_atomic_set_relb(&tb->is_stack_busy, 0);
- }
- else {
- erts_db_free(ERTS_ALC_T_DB_STK, (DbTable *) tb,
- (void *) stack, sizeof(DbTreeStack) + sizeof(TreeDbTerm*) * STACK_NEED);
+ if (stack_container != NULL) {
+ ASSERT(IS_TREE_TABLE(stack_container->common.type));
+ if (stack == &stack_container->static_stack) {
+ ASSERT(erts_atomic_read_nob(&stack_container->is_stack_busy) == 1);
+ erts_atomic_set_relb(&stack_container->is_stack_busy, 0);
+ return;
+ }
}
+ erts_db_free(ERTS_ALC_T_DB_STK, tb,
+ (void *) stack, sizeof(DbTreeStack) + sizeof(TreeDbTerm*) * STACK_NEED);
}
-static ERTS_INLINE void reset_static_stack(DbTableTree* tb)
+static ERTS_INLINE void reset_stack(DbTreeStack* stack)
{
- tb->static_stack.pos = 0;
- tb->static_stack.slot = 0;
+ if (stack != NULL) {
+ stack->pos = 0;
+ stack->slot = 0;
+ }
}
-static ERTS_INLINE void free_term(DbTableTree *tb, TreeDbTerm* p)
+static ERTS_INLINE void reset_static_stack(DbTableTree* tb)
{
- db_free_term((DbTable*)tb, p, offsetof(TreeDbTerm, dbterm));
+ if (tb != NULL) {
+ ASSERT(IS_TREE_TABLE(tb->common.type));
+ reset_stack(&tb->static_stack);
+ }
}
-static ERTS_INLINE TreeDbTerm* new_dbterm(DbTableTree *tb, Eterm obj)
+static ERTS_INLINE TreeDbTerm* new_dbterm(DbTableCommon *tb, Eterm obj)
{
TreeDbTerm* p;
- if (tb->common.compress) {
- p = db_store_term_comp(&tb->common, NULL, offsetof(TreeDbTerm,dbterm), obj);
+ if (tb->compress) {
+ p = db_store_term_comp(tb, NULL, offsetof(TreeDbTerm,dbterm), obj);
}
else {
- p = db_store_term(&tb->common, NULL, offsetof(TreeDbTerm,dbterm), obj);
+ p = db_store_term(tb, NULL, offsetof(TreeDbTerm,dbterm), obj);
}
return p;
}
-static ERTS_INLINE TreeDbTerm* replace_dbterm(DbTableTree *tb, TreeDbTerm* old,
+static ERTS_INLINE TreeDbTerm* replace_dbterm(DbTableCommon *tb, TreeDbTerm* old,
Eterm obj)
{
TreeDbTerm* p;
ASSERT(old != NULL);
- if (tb->common.compress) {
- p = db_store_term_comp(&tb->common, &(old->dbterm), offsetof(TreeDbTerm,dbterm), obj);
+ if (tb->compress) {
+ p = db_store_term_comp(tb, &(old->dbterm), offsetof(TreeDbTerm,dbterm), obj);
}
else {
- p = db_store_term(&tb->common, &(old->dbterm), offsetof(TreeDbTerm,dbterm), obj);
+ p = db_store_term(tb, &(old->dbterm), offsetof(TreeDbTerm,dbterm), obj);
}
return p;
}
/*
-** Some macros for "direction stacks"
-*/
-#define DIR_LEFT 0
-#define DIR_RIGHT 1
-#define DIR_END 2
-
-/*
* Number of records to delete before trapping.
*/
#define DELETE_RECORD_LIMIT 12000
@@ -208,31 +191,37 @@ static void do_dump_tree2(DbTableTree*, int to, void *to_arg, int show,
** Datatypes
*/
+enum ms_key_boundness {
+ /* Order significant, larger means more "boundness" => less iteration */
+ MS_KEY_UNBOUND = 0,
+ MS_KEY_PARTIALLY_BOUND = 1,
+ MS_KEY_BOUND = 2,
+ MS_KEY_IMPOSSIBLE = 3
+};
+
/*
* This structure is filled in by analyze_pattern() for the select
* functions.
*/
struct mp_info {
- int something_can_match; /* The match_spec is not "impossible" */
- int some_limitation; /* There is some limitation on the search
- * area, i. e. least and/or most is set.*/
- int got_partial; /* The limitation has a partially bound
- * key */
+ enum ms_key_boundness key_boundness;
Eterm least; /* The lowest matching key (possibly
* partially bound expression) */
Eterm most; /* The highest matching key (possibly
* partially bound expression) */
-
- TreeDbTerm **save_term; /* If the key is completely bound, this
- * will be the Tree node we're searching
- * for, otherwise it will be useless */
Binary *mp; /* The compiled match program */
};
+struct select_common {
+ TreeDbTerm **root;
+};
+
+
/*
* Used by doit_select(_chunk)
*/
struct select_context {
+ struct select_common common;
Process *p;
Eterm accum;
Binary *mp;
@@ -248,6 +237,7 @@ struct select_context {
* Used by doit_select_count
*/
struct select_count_context {
+ struct select_common common;
Process *p;
Binary *mp;
Eterm end_condition;
@@ -261,8 +251,10 @@ struct select_count_context {
* Used by doit_select_delete
*/
struct select_delete_context {
+ struct select_common common;
Process *p;
- DbTableTree *tb;
+ DbTableCommon *tb;
+ DbTreeStack *stack;
Uint accum;
Binary *mp;
Eterm end_condition;
@@ -276,8 +268,9 @@ struct select_delete_context {
* Used by doit_select_replace
*/
struct select_replace_context {
+ struct select_common common;
Process *p;
- DbTableTree *tb;
+ DbTableCommon *tb;
Binary *mp;
Eterm end_condition;
Eterm *lastobj;
@@ -292,75 +285,83 @@ typedef int (*extra_match_validator_t)(int keypos, Eterm match, Eterm guard, Ete
/*
** Forward declarations
*/
-static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key);
-static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
- Eterm object);
+static TreeDbTerm *linkout_tree(DbTableCommon *tb, TreeDbTerm **root,
+ Eterm key, DbTreeStack *stack);
+static TreeDbTerm *linkout_object_tree(DbTableCommon *tb, TreeDbTerm **root,
+ Eterm object, DbTableTree *stack);
static SWord do_free_tree_continue(DbTableTree *tb, SWord reds);
-static void free_term(DbTableTree *tb, TreeDbTerm* p);
-static int balance_left(TreeDbTerm **this);
-static int balance_right(TreeDbTerm **this);
+static void free_term(DbTable *tb, TreeDbTerm* p);
+int tree_balance_left(TreeDbTerm **this);
+int tree_balance_right(TreeDbTerm **this);
static int delsub(TreeDbTerm **this);
-static TreeDbTerm *slot_search(Process *p, DbTableTree *tb, Sint slot);
-static TreeDbTerm *find_node(DbTableTree *tb, Eterm key);
-static TreeDbTerm **find_node2(DbTableTree *tb, Eterm key);
-static TreeDbTerm **find_ptr(DbTableTree *tb, DbTreeStack*, TreeDbTerm *this);
-static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack*, Eterm key);
-static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack*, Eterm key);
-static TreeDbTerm *find_next_from_pb_key(DbTableTree *tb, DbTreeStack*,
- Eterm key);
-static TreeDbTerm *find_prev_from_pb_key(DbTableTree *tb, DbTreeStack*,
- Eterm key);
-static void traverse_backwards(DbTableTree *tb,
+static TreeDbTerm *slot_search(Process *p, TreeDbTerm *root, Sint slot,
+ DbTable *tb, DbTableTree *stack_container,
+ CATreeRootIterator *iter);
+static TreeDbTerm *find_node(DbTableCommon *tb, TreeDbTerm *root,
+ Eterm key, DbTableTree *stack_container);
+static TreeDbTerm **find_node2(DbTableCommon *tb, TreeDbTerm **root, Eterm key);
+static TreeDbTerm **find_ptr(DbTableCommon *tb, TreeDbTerm **root,
+ DbTreeStack *stack, TreeDbTerm *this);
+static TreeDbTerm *find_next(DbTableCommon *tb, TreeDbTerm *root,
+ DbTreeStack* stack, Eterm key);
+static TreeDbTerm *find_prev(DbTableCommon *tb, TreeDbTerm *root,
+ DbTreeStack* stack, Eterm key);
+static TreeDbTerm *find_next_from_pb_key(DbTable*, TreeDbTerm*** rootpp,
+ DbTreeStack* stack, Eterm key,
+ CATreeRootIterator*);
+static TreeDbTerm *find_prev_from_pb_key(DbTable*, TreeDbTerm*** rootpp,
+ DbTreeStack* stack, Eterm key,
+ CATreeRootIterator*);
+typedef int traverse_doit_funcT(DbTableCommon*, TreeDbTerm*,
+ struct select_common*, int forward);
+
+static void traverse_backwards(DbTableCommon *tb,
DbTreeStack*,
Eterm lastkey,
- int (*doit)(DbTableTree *tb,
- TreeDbTerm *,
- void *,
- int),
- void *context);
-static void traverse_forward(DbTableTree *tb,
+ traverse_doit_funcT*,
+ struct select_common *context,
+ CATreeRootIterator*);
+static void traverse_forward(DbTableCommon *tb,
DbTreeStack*,
Eterm lastkey,
- int (*doit)(DbTableTree *tb,
- TreeDbTerm *,
- void *,
- int),
- void *context);
-static void traverse_update_backwards(DbTableTree *tb,
+ traverse_doit_funcT*,
+ struct select_common *context,
+ CATreeRootIterator*);
+static void traverse_update_backwards(DbTableCommon *tb,
DbTreeStack*,
Eterm lastkey,
- int (*doit)(DbTableTree *tb,
+ int (*doit)(DbTableCommon *tb,
TreeDbTerm **, // out
- void *,
+ struct select_common*,
int),
- void *context);
-static int key_given(DbTableTree *tb, Eterm pattern, TreeDbTerm ***ret,
- Eterm *partly_bound_key);
-static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key);
+ struct select_common*,
+ CATreeRootIterator*);
+static enum ms_key_boundness key_boundness(DbTableCommon *tb,
+ Eterm pattern, Eterm *keyp);
static Sint do_cmp_partly_bound(Eterm a, Eterm b, int *done);
-static int analyze_pattern(DbTableTree *tb, Eterm pattern,
+static int analyze_pattern(DbTableCommon *tb, Eterm pattern,
extra_match_validator_t extra_validator, /* Optional callback */
struct mp_info *mpi);
-static int doit_select(DbTableTree *tb,
- TreeDbTerm *this,
- void *ptr,
+static int doit_select(DbTableCommon *tb,
+ TreeDbTerm *this,
+ struct select_common* ptr,
int forward);
-static int doit_select_count(DbTableTree *tb,
+static int doit_select_count(DbTableCommon *tb,
TreeDbTerm *this,
- void *ptr,
+ struct select_common*,
int forward);
-static int doit_select_chunk(DbTableTree *tb,
+static int doit_select_chunk(DbTableCommon *tb,
TreeDbTerm *this,
- void *ptr,
+ struct select_common*,
int forward);
-static int doit_select_delete(DbTableTree *tb,
+static int doit_select_delete(DbTableCommon *tb,
TreeDbTerm *this,
- void *ptr,
+ struct select_common*,
int forward);
-static int doit_select_replace(DbTableTree *tb,
+static int doit_select_replace(DbTableCommon *tb,
TreeDbTerm **this_ptr,
- void *ptr,
+ struct select_common*,
int forward);
static int partly_bound_can_match_lesser(Eterm partly_bound_1,
@@ -508,18 +509,18 @@ int db_create_tree(Process *p, DbTable *tbl)
return DB_ERROR_NONE;
}
-static int db_first_tree(Process *p, DbTable *tbl, Eterm *ret)
+int db_first_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm *ret, DbTableTree *stack_container)
{
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
TreeDbTerm *this;
- if (( this = tb->root ) == NULL) {
+ if (( this = root ) == NULL) {
*ret = am_EOT;
return DB_ERROR_NONE;
}
/* Walk down the tree to the left */
- if ((stack = get_static_stack(tb)) != NULL) {
+ if ((stack = get_static_stack(stack_container)) != NULL) {
stack->pos = stack->slot = 0;
}
while (this->left != NULL) {
@@ -529,23 +530,27 @@ static int db_first_tree(Process *p, DbTable *tbl, Eterm *ret)
if (stack) {
PUSH_NODE(stack, this);
stack->slot = 1;
- release_stack(tb,stack);
+ release_stack(tbl,stack_container,stack);
}
*ret = db_copy_key(p, tbl, &this->dbterm);
return DB_ERROR_NONE;
}
-static int db_next_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+static int db_first_tree(Process *p, DbTable *tbl, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
- DbTreeStack* stack;
+ return db_first_tree_common(p, tbl, tb->root, ret, tb);
+}
+
+int db_next_tree_common(Process *p, DbTable *tbl,
+ TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTreeStack* stack)
+{
TreeDbTerm *this;
- if (is_atom(key) && key == am_EOT)
+ if (key == am_EOT)
return DB_ERROR_BADKEY;
- stack = get_any_stack(tb);
- this = find_next(tb, stack, key);
- release_stack(tb,stack);
+ this = find_next(&tbl->common, root, stack, key);
if (this == NULL) {
*ret = am_EOT;
return DB_ERROR_NONE;
@@ -554,18 +559,27 @@ static int db_next_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
return DB_ERROR_NONE;
}
-static int db_last_tree(Process *p, DbTable *tbl, Eterm *ret)
+static int db_next_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ DbTreeStack* stack = get_any_stack(tbl, tb);
+ int ret_val = db_next_tree_common(p, tbl, tb->root, key, ret, stack);
+ release_stack(tbl,tb,stack);
+ return ret_val;
+}
+
+int db_last_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm *ret, DbTableTree *stack_container)
+{
TreeDbTerm *this;
DbTreeStack* stack;
- if (( this = tb->root ) == NULL) {
+ if (( this = root ) == NULL) {
*ret = am_EOT;
return DB_ERROR_NONE;
}
/* Walk down the tree to the right */
- if ((stack = get_static_stack(tb)) != NULL) {
+ if ((stack = get_static_stack(stack_container)) != NULL) {
stack->pos = stack->slot = 0;
}
while (this->right != NULL) {
@@ -574,24 +588,27 @@ static int db_last_tree(Process *p, DbTable *tbl, Eterm *ret)
}
if (stack) {
PUSH_NODE(stack, this);
- stack->slot = NITEMS(tb);
- release_stack(tb,stack);
+ stack->slot = NITEMS(tbl);
+ release_stack(tbl,stack_container,stack);
}
*ret = db_copy_key(p, tbl, &this->dbterm);
return DB_ERROR_NONE;
}
-static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+static int db_last_tree(Process *p, DbTable *tbl, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_last_tree_common(p, tbl, tb->root, ret, tb);
+}
+
+int db_prev_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTreeStack* stack)
+{
TreeDbTerm *this;
- DbTreeStack* stack;
- if (is_atom(key) && key == am_EOT)
+ if (key == am_EOT)
return DB_ERROR_BADKEY;
- stack = get_any_stack(tb);
- this = find_prev(tb, stack, key);
- release_stack(tb,stack);
+ this = find_prev(&tbl->common, root, stack, key);
if (this == NULL) {
*ret = am_EOT;
return DB_ERROR_NONE;
@@ -600,25 +617,30 @@ static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
return DB_ERROR_NONE;
}
-static ERTS_INLINE Sint cmp_key(DbTableTree* tb, Eterm key, TreeDbTerm* obj) {
- return CMP(key, GETKEY(tb,obj->dbterm.tpl));
+static int db_prev_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableTree *tb = &tbl->tree;
+ DbTreeStack* stack = get_any_stack(tbl, tb);
+ int res = db_prev_tree_common(p, tbl, tb->root, key, ret, stack);
+ release_stack(tbl,tb,stack);
+ return res;
}
-static ERTS_INLINE int cmp_key_eq(DbTableTree* tb, Eterm key, TreeDbTerm* obj) {
+static ERTS_INLINE int cmp_key_eq(DbTableCommon* tb, Eterm key, TreeDbTerm* obj) {
Eterm obj_key = GETKEY(tb,obj->dbterm.tpl);
return is_same(key, obj_key) || CMP(key, obj_key) == 0;
}
-static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail)
+int db_put_tree_common(DbTableCommon *tb, TreeDbTerm **root, Eterm obj,
+ int key_clash_fail, DbTableTree *stack_container)
{
- DbTableTree *tb = &tbl->tree;
/* Non recursive insertion in AVL tree, building our own stack */
TreeDbTerm **tstack[STACK_NEED];
int tpos = 0;
int dstack[STACK_NEED+1];
int dpos = 0;
int state = 0;
- TreeDbTerm **this = &tb->root;
+ TreeDbTerm **this = root;
Sint c;
Eterm key;
int dir;
@@ -626,14 +648,14 @@ static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail)
key = GETKEY(tb, tuple_val(obj));
- reset_static_stack(tb);
+ reset_static_stack(stack_container);
dstack[dpos++] = DIR_END;
for (;;)
if (!*this) { /* Found our place */
state = 1;
- if (erts_atomic_inc_read_nob(&tb->common.nitems) >= TREE_MAX_ELEMENTS) {
- erts_atomic_dec_nob(&tb->common.nitems);
+ if (erts_atomic_inc_read_nob(&tb->nitems) >= TREE_MAX_ELEMENTS) {
+ erts_atomic_dec_nob(&tb->nitems);
return DB_ERROR_SYSRES;
}
*this = new_dbterm(tb, obj);
@@ -724,9 +746,15 @@ static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail)
return DB_ERROR_NONE;
}
-static int db_get_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+static int db_put_tree(DbTable *tbl, Eterm obj, int key_clash_fail)
{
DbTableTree *tb = &tbl->tree;
+ return db_put_tree_common(&tb->common, &tb->root, obj, key_clash_fail, tb);
+}
+
+int db_get_tree_common(Process *p, DbTableCommon *tb, TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTableTree *stack_container)
+{
Eterm copy;
Eterm *hp, *hend;
TreeDbTerm *this;
@@ -737,13 +765,13 @@ static int db_get_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
* The list created around it is purely for interface conformance.
*/
- this = find_node(tb,key);
+ this = find_node(tb,root,key,stack_container);
if (this == NULL) {
*ret = NIL;
} else {
hp = HAlloc(p, this->dbterm.size + 2);
hend = hp + this->dbterm.size + 2;
- copy = db_copy_object_from_ets(&tb->common, &this->dbterm, &hp, &MSO(p));
+ copy = db_copy_object_from_ets(tb, &this->dbterm, &hp, &MSO(p));
*ret = CONS(hp, copy, NIL);
hp += 2;
HRelease(p,hend,hp);
@@ -751,18 +779,28 @@ static int db_get_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
return DB_ERROR_NONE;
}
-static int db_member_tree(DbTable *tbl, Eterm key, Eterm *ret)
+static int db_get_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_get_tree_common(p, &tb->common, tb->root, key, ret, tb);
+}
- *ret = (find_node(tb,key) == NULL) ? am_false : am_true;
+int db_member_tree_common(DbTableCommon *tb, TreeDbTerm *root, Eterm key, Eterm *ret,
+ DbTableTree *stack_container)
+{
+ *ret = (find_node(tb,root,key,stack_container) == NULL) ? am_false : am_true;
return DB_ERROR_NONE;
}
-static int db_get_element_tree(Process *p, DbTable *tbl,
- Eterm key, int ndex, Eterm *ret)
+static int db_member_tree(DbTable *tbl, Eterm key, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_member_tree_common(&tb->common, tb->root, key, ret, tb);
+}
+
+int db_get_element_tree_common(Process *p, DbTableCommon *tb, TreeDbTerm *root, Eterm key,
+ int ndex, Eterm *ret, DbTableTree *stack_container)
+{
/*
* Look the node up:
*/
@@ -776,49 +814,69 @@ static int db_get_element_tree(Process *p, DbTable *tbl,
* around the element here either.
*/
- this = find_node(tb,key);
+ this = find_node(tb,root,key,stack_container);
if (this == NULL) {
return DB_ERROR_BADKEY;
} else {
if (ndex > arityval(this->dbterm.tpl[0])) {
return DB_ERROR_BADPARAM;
}
- *ret = db_copy_element_from_ets(&tb->common, p, &this->dbterm, ndex, &hp, 0);
+ *ret = db_copy_element_from_ets(tb, p, &this->dbterm, ndex, &hp, 0);
}
return DB_ERROR_NONE;
}
-static int db_erase_tree(DbTable *tbl, Eterm key, Eterm *ret)
+static int db_get_element_tree(Process *p, DbTable *tbl,
+ Eterm key, int ndex, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_get_element_tree_common(p, &tb->common, tb->root, key,
+ ndex, ret, tb);
+}
+
+int db_erase_tree_common(DbTable *tbl, TreeDbTerm **root, Eterm key, Eterm *ret,
+ DbTreeStack *stack /* NULL if no static stack */)
+{
TreeDbTerm *res;
*ret = am_true;
- if ((res = linkout_tree(tb, key)) != NULL) {
- free_term(tb, res);
+ if ((res = linkout_tree(&tbl->common, root,key, stack)) != NULL) {
+ free_term(tbl, res);
}
return DB_ERROR_NONE;
}
-static int db_erase_object_tree(DbTable *tbl, Eterm object, Eterm *ret)
+static int db_erase_tree(DbTable *tbl, Eterm key, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_erase_tree_common(tbl, &tb->root, key, ret, &tb->static_stack);
+}
+
+int db_erase_object_tree_common(DbTable *tbl, TreeDbTerm **root, Eterm object,
+ Eterm *ret, DbTableTree *stack_container)
+{
TreeDbTerm *res;
*ret = am_true;
- if ((res = linkout_object_tree(tb, object)) != NULL) {
- free_term(tb, res);
+ if ((res = linkout_object_tree(&tbl->common, root, object, stack_container)) != NULL) {
+ free_term(tbl, res);
}
return DB_ERROR_NONE;
}
-
-static int db_slot_tree(Process *p, DbTable *tbl,
- Eterm slot_term, Eterm *ret)
+static int db_erase_object_tree(DbTable *tbl, Eterm object, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_erase_object_tree_common(tbl, &tb->root, object, ret, tb);
+}
+
+int db_slot_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm slot_term, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator *iter)
+{
Sint slot;
TreeDbTerm *st;
Eterm *hp, *hend;
@@ -834,10 +892,10 @@ static int db_slot_tree(Process *p, DbTable *tbl,
if (is_not_small(slot_term) ||
((slot = signed_val(slot_term)) < 0) ||
- (slot > NITEMS(tb)))
+ (slot > NITEMS(tbl)))
return DB_ERROR_BADPARAM;
- if (slot == NITEMS(tb)) {
+ if (slot == NITEMS(tbl)) {
*ret = am_EOT;
return DB_ERROR_NONE;
}
@@ -847,20 +905,27 @@ static int db_slot_tree(Process *p, DbTable *tbl,
* are counted from 1 and up.
*/
++slot;
- st = slot_search(p, tb, slot);
+ st = slot_search(p, root, slot, tbl, stack_container, iter);
if (st == NULL) {
*ret = am_false;
return DB_ERROR_UNSPEC;
}
hp = HAlloc(p, st->dbterm.size + 2);
hend = hp + st->dbterm.size + 2;
- copy = db_copy_object_from_ets(&tb->common, &st->dbterm, &hp, &MSO(p));
+ copy = db_copy_object_from_ets(&tbl->common, &st->dbterm, &hp, &MSO(p));
*ret = CONS(hp, copy, NIL);
hp += 2;
HRelease(p,hend,hp);
return DB_ERROR_NONE;
}
+static int db_slot_tree(Process *p, DbTable *tbl,
+ Eterm slot_term, Eterm *ret)
+{
+ DbTableTree *tb = &tbl->tree;
+ return db_slot_tree_common(p, tbl, tb->root, slot_term, ret, tb, NULL);
+}
+
static BIF_RETTYPE ets_select_reverse(BIF_ALIST_3)
@@ -926,19 +991,14 @@ static BIF_RETTYPE bif_trap3(Export *bif,
{
BIF_TRAP3(bif, p, p1, p2, p3);
}
-
-/*
-** This is called either when the select bif traps or when ets:select/1
-** is called. It does mostly the same as db_select_tree and may in either case
-** trap to itself again (via the ets:select/1 bif).
-** Note that this is common for db_select_tree and db_select_chunk_tree.
-*/
-static int db_select_continue_tree(Process *p,
- DbTable *tbl,
- Eterm continuation,
- Eterm *ret)
+
+int db_select_continue_tree_common(Process *p,
+ DbTableCommon *tb,
+ Eterm continuation,
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
{
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_context sc;
unsigned sz;
@@ -951,7 +1011,6 @@ static int db_select_continue_tree(Process *p,
Sint chunk_size;
Sint reverse;
-
#define RET_TO_BIF(Term, State) do { *ret = (Term); return State; } while(0);
/* Decode continuation. We know it's a tuple but not the arity or
@@ -980,28 +1039,37 @@ static int db_select_continue_tree(Process *p,
sc.end_condition = NIL;
sc.lastobj = NULL;
sc.max = 1000;
- sc.keypos = tb->common.keypos;
+ sc.keypos = tb->keypos;
sc.chunk_size = chunk_size;
reverse = unsigned_val(tptr[7]);
sc.got = signed_val(tptr[8]);
- stack = get_any_stack(tb);
- if (chunk_size) {
- if (reverse) {
- traverse_backwards(tb, stack, lastkey, &doit_select_chunk, &sc);
- } else {
- traverse_forward(tb, stack, lastkey, &doit_select_chunk, &sc);
- }
- } else {
- if (reverse) {
- traverse_forward(tb, stack, lastkey, &doit_select, &sc);
- } else {
- traverse_backwards(tb, stack, lastkey, &doit_select, &sc);
- }
+ if (iter) {
+ iter->next_route_key = lastkey;
+ sc.common.root = catree_find_nextprev_root(iter, !!reverse != !!chunk_size, NULL);
}
- release_stack(tb,stack);
+ else
+ sc.common.root = &((DbTableTree*)tb)->root;
+
+ if (sc.common.root) {
+ stack = get_any_stack((DbTable*)tb, stack_container);
+ if (chunk_size) {
+ if (reverse) {
+ traverse_backwards(tb, stack, lastkey, &doit_select_chunk, &sc.common, iter);
+ } else {
+ traverse_forward(tb, stack, lastkey, &doit_select_chunk, &sc.common, iter);
+ }
+ } else {
+ if (reverse) {
+ traverse_forward(tb, stack, lastkey, &doit_select, &sc.common, iter);
+ } else {
+ traverse_backwards(tb, stack, lastkey, &doit_select, &sc.common, iter);
+ }
+ }
+ release_stack((DbTable*)tb,stack_container,stack);
- BUMP_REDS(p, 1000 - sc.max);
+ BUMP_REDS(p, 1000 - sc.max);
+ }
if (sc.max > 0 || (chunk_size && sc.got == chunk_size)) {
if (chunk_size) {
@@ -1082,13 +1150,29 @@ static int db_select_continue_tree(Process *p,
#undef RET_TO_BIF
}
+
+/*
+** This is called either when the select bif traps or when ets:select/1
+** is called. It does mostly the same as db_select_tree and may in either case
+** trap to itself again (via the ets:select/1 bif).
+** Note that this is common for db_select_tree and db_select_chunk_tree.
+*/
+static int db_select_continue_tree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
+{
+ DbTableTree *tb = &tbl->tree;
+ return db_select_continue_tree_common(p, &tb->common,
+ continuation, ret, tb, NULL);
+}
-
-static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
- Eterm pattern, int reverse, Eterm *ret)
+int db_select_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, int reverse, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
{
/* Strategy: Traverse backwards to build resulting list from tail to head */
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_context sc;
struct mp_info mpi;
@@ -1121,42 +1205,62 @@ static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
sc.got = 0;
sc.chunk_size = 0;
- if ((errcode = analyze_pattern(tb, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
+ if ((errcode = analyze_pattern(&tb->common, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
RET_TO_BIF(NIL,errcode);
}
- if (!mpi.something_can_match) {
+ if (mpi.key_boundness == MS_KEY_IMPOSSIBLE) {
RET_TO_BIF(NIL,DB_ERROR_NONE);
/* can't possibly match anything */
}
sc.mp = mpi.mp;
- if (!mpi.got_partial && mpi.some_limitation &&
- CMP_EQ(mpi.least,mpi.most)) {
- doit_select(tb,*(mpi.save_term),&sc,0 /* direction doesn't matter */);
+ if (mpi.key_boundness == MS_KEY_BOUND) {
+ ASSERT(CMP_EQ(mpi.least, mpi.most));
+ if (iter)
+ sc.common.root = catree_find_root(mpi.least, iter);
+ else
+ sc.common.root = &tb->tree.root;
+ this = find_node(&tb->common, *sc.common.root, mpi.least, NULL);
+ if (this)
+ doit_select(&tb->common, this, &sc.common, 0 /* direction doesn't matter */);
RET_TO_BIF(sc.accum,DB_ERROR_NONE);
}
- stack = get_any_stack(tb);
+ stack = get_any_stack((DbTable*)tb,stack_container);
if (reverse) {
- if (mpi.some_limitation) {
- if ((this = find_prev_from_pb_key(tb, stack, mpi.least)) != NULL) {
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_prev_from_pb_key(tb, &sc.common.root, stack, mpi.least, iter);
+ if (this)
lastkey = GETKEY(tb, this->dbterm.tpl);
- }
sc.end_condition = mpi.most;
}
- traverse_forward(tb, stack, lastkey, &doit_select, &sc);
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_first_root(iter);
+ else
+ sc.common.root = &tb->tree.root;
+ }
+ traverse_forward(&tb->common, stack, lastkey, &doit_select, &sc.common, iter);
} else {
- if (mpi.some_limitation) {
- if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_next_from_pb_key(tb, &sc.common.root, stack, mpi.most, iter);
+ if (this)
+ lastkey = GETKEY(tb, this->dbterm.tpl);
sc.end_condition = mpi.least;
}
- traverse_backwards(tb, stack, lastkey, &doit_select, &sc);
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_last_root(iter);
+ else
+ sc.common.root = &tb->tree.root;
+ }
+ traverse_backwards(&tb->common, stack, lastkey, &doit_select, &sc.common, iter);
}
- release_stack(tb,stack);
+ release_stack((DbTable*)tb,stack_container,stack);
#ifdef HARDDEBUG
erts_fprintf(stderr,"Least: %T\n", mpi.least);
erts_fprintf(stderr,"Most: %T\n", mpi.most);
@@ -1192,16 +1296,20 @@ static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
}
-
-/*
-** This is called either when the select_count bif traps.
-*/
-static int db_select_count_continue_tree(Process *p,
- DbTable *tbl,
- Eterm continuation,
- Eterm *ret)
+static int db_select_tree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, int reverse, Eterm *ret)
+{
+ return db_select_tree_common(p, tbl, tid,
+ pattern, reverse, ret, &tbl->tree, NULL);
+}
+
+int db_select_count_continue_tree_common(Process *p,
+ DbTable *tb,
+ Eterm continuation,
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
{
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_count_context sc;
unsigned sz;
@@ -1213,7 +1321,6 @@ static int db_select_count_continue_tree(Process *p,
Eterm *tptr;
Eterm egot;
-
#define RET_TO_BIF(Term, State) do { *ret = (Term); return State; } while(0);
/* Decode continuation. We know it's a tuple and everything else as
@@ -1245,11 +1352,21 @@ static int db_select_count_continue_tree(Process *p,
sc.got = unsigned_val(tptr[5]);
}
- stack = get_any_stack(tb);
- traverse_backwards(tb, stack, lastkey, &doit_select_count, &sc);
- release_stack(tb,stack);
+ if (iter) {
+ iter->next_route_key = lastkey;
+ sc.common.root = catree_find_prev_root(iter, NULL);
+ }
+ else {
+ sc.common.root = &tb->tree.root;
+ }
- BUMP_REDS(p, 1000 - sc.max);
+ if (sc.common.root) {
+ stack = get_any_stack(tb, stack_container);
+ traverse_backwards(&tb->common, stack, lastkey, &doit_select_count, &sc.common, iter);
+ release_stack(tb,stack_container,stack);
+
+ BUMP_REDS(p, 1000 - sc.max);
+ }
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.got,p), DB_ERROR_NONE);
@@ -1285,11 +1402,25 @@ static int db_select_count_continue_tree(Process *p,
#undef RET_TO_BIF
}
-
-static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
- Eterm pattern, Eterm *ret)
+/*
+** This is called either when the select_count bif traps.
+*/
+static int db_select_count_continue_tree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_select_count_continue_tree_common(p, tbl,
+ continuation, ret, tb, NULL);
+}
+
+
+int db_select_count_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
+{
DbTreeStack* stack;
struct select_count_context sc;
struct mp_info mpi;
@@ -1303,7 +1434,6 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
Eterm egot;
Eterm mpb;
-
#define RET_TO_BIF(Term,RetVal) do { \
if (mpi.mp != NULL) { \
erts_bin_free(mpi.mp); \
@@ -1321,33 +1451,46 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
sc.keypos = tb->common.keypos;
sc.got = 0;
- if ((errcode = analyze_pattern(tb, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
+ if ((errcode = analyze_pattern(&tb->common, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
RET_TO_BIF(NIL,errcode);
}
- if (!mpi.something_can_match) {
+ if (mpi.key_boundness == MS_KEY_IMPOSSIBLE) {
RET_TO_BIF(make_small(0),DB_ERROR_NONE);
/* can't possibly match anything */
}
sc.mp = mpi.mp;
- if (!mpi.got_partial && mpi.some_limitation &&
- CMP_EQ(mpi.least,mpi.most)) {
- doit_select_count(tb,*(mpi.save_term),&sc,0 /* dummy */);
+ if (mpi.key_boundness == MS_KEY_BOUND) {
+ ASSERT(CMP_EQ(mpi.least, mpi.most));
+ if (iter)
+ sc.common.root = catree_find_root(mpi.least, iter);
+ else
+ sc.common.root = &((DbTable*)tb)->tree.root;
+ this = find_node(&tb->common, *sc.common.root, mpi.least, NULL);
+ if (this)
+ doit_select_count(&tb->common, this, &sc.common, 0 /* dummy */);
RET_TO_BIF(erts_make_integer(sc.got,p),DB_ERROR_NONE);
}
- stack = get_any_stack(tb);
- if (mpi.some_limitation) {
- if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ stack = get_any_stack((DbTable*)tb, stack_container);
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_next_from_pb_key(tb, &sc.common.root, stack, mpi.most, iter);
+ if (this)
+ lastkey = GETKEY(tb, this->dbterm.tpl);
sc.end_condition = mpi.least;
}
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_last_root(iter);
+ else
+ sc.common.root = &tb->tree.root;
+ }
- traverse_backwards(tb, stack, lastkey, &doit_select_count, &sc);
- release_stack(tb,stack);
+ traverse_backwards(&tb->common, stack, lastkey, &doit_select_count, &sc.common, iter);
+ release_stack((DbTable*)tb,stack_container,stack);
BUMP_REDS(p, 1000 - sc.max);
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.got,p),DB_ERROR_NONE);
@@ -1383,12 +1526,21 @@ static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
}
-static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
- Eterm pattern, Sint chunk_size,
- int reverse,
- Eterm *ret)
+static int db_select_count_tree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_select_count_tree_common(p, tbl,
+ tid, pattern, ret, tb, NULL);
+}
+
+
+int db_select_chunk_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, Sint chunk_size,
+ int reverse, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
+{
DbTreeStack* stack;
struct select_context sc;
struct mp_info mpi;
@@ -1401,7 +1553,6 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
int errcode;
Eterm mpb;
-
#define RET_TO_BIF(Term,RetVal) do { \
if (mpi.mp != NULL) { \
erts_bin_free(mpi.mp); \
@@ -1421,20 +1572,26 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
sc.got = 0;
sc.chunk_size = chunk_size;
- if ((errcode = analyze_pattern(tb, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
+ if ((errcode = analyze_pattern(&tb->common, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
RET_TO_BIF(NIL,errcode);
}
- if (!mpi.something_can_match) {
+ if (mpi.key_boundness == MS_KEY_IMPOSSIBLE) {
RET_TO_BIF(am_EOT,DB_ERROR_NONE);
/* can't possibly match anything */
}
sc.mp = mpi.mp;
- if (!mpi.got_partial && mpi.some_limitation &&
- CMP_EQ(mpi.least,mpi.most)) {
- doit_select(tb,*(mpi.save_term),&sc, 0 /* direction doesn't matter */);
+ if (mpi.key_boundness == MS_KEY_BOUND) {
+ ASSERT(CMP_EQ(mpi.least, mpi.most));
+ if (iter)
+ sc.common.root = catree_find_root(mpi.least, iter);
+ else
+ sc.common.root = &tb->tree.root;
+ this = find_node(&tb->common, *sc.common.root, mpi.least, NULL);
+ if (this)
+ doit_select(&tb->common, this, &sc.common, 0 /* direction doesn't matter */);
if (sc.accum != NIL) {
hp=HAlloc(p, 3);
RET_TO_BIF(TUPLE2(hp,sc.accum,am_EOT),DB_ERROR_NONE);
@@ -1443,25 +1600,39 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
}
}
- stack = get_any_stack(tb);
+ stack = get_any_stack((DbTable*)tb,stack_container);
if (reverse) {
- if (mpi.some_limitation) {
- if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_next_from_pb_key(tb, &sc.common.root, stack, mpi.most, iter);
+ if (this)
+ lastkey = GETKEY(tb, this->dbterm.tpl);
sc.end_condition = mpi.least;
}
- traverse_backwards(tb, stack, lastkey, &doit_select_chunk, &sc);
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_last_root(iter);
+ else
+ sc.common.root = &tb->tree.root;
+ }
+ traverse_backwards(&tb->common, stack, lastkey, &doit_select_chunk, &sc.common, iter);
} else {
- if (mpi.some_limitation) {
- if ((this = find_prev_from_pb_key(tb, stack, mpi.least)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_prev_from_pb_key(tb, &sc.common.root, stack, mpi.least, iter);
+ if (this)
+ lastkey = GETKEY(tb, this->dbterm.tpl);
sc.end_condition = mpi.most;
}
- traverse_forward(tb, stack, lastkey, &doit_select_chunk, &sc);
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_first_root(iter);
+ else
+ sc.common.root = &tb->tree.root;
+ }
+ traverse_forward(&tb->common, stack, lastkey, &doit_select_chunk, &sc.common, iter);
}
- release_stack(tb,stack);
+ release_stack((DbTable*)tb,stack_container,stack);
BUMP_REDS(p, 1000 - sc.max);
if (sc.max > 0 || sc.got == chunk_size) {
@@ -1530,15 +1701,25 @@ static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
}
-/*
-** This is called when select_delete traps
-*/
-static int db_select_delete_continue_tree(Process *p,
- DbTable *tbl,
- Eterm continuation,
- Eterm *ret)
+static int db_select_chunk_tree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Sint chunk_size,
+ int reverse,
+ Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ return db_select_chunk_tree_common(p, tbl,
+ tid, pattern, chunk_size,
+ reverse, ret, tb, NULL);
+}
+
+
+int db_select_delete_continue_tree_common(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret,
+ DbTreeStack* stack,
+ CATreeRootIterator* iter)
+{
struct select_delete_context sc;
unsigned sz;
Eterm *hp;
@@ -1549,10 +1730,9 @@ static int db_select_delete_continue_tree(Process *p,
Eterm *tptr;
Eterm eaccsum;
-
#define RET_TO_BIF(Term, State) do { \
if (sc.erase_lastterm) { \
- free_term(tb, sc.lastterm); \
+ free_term(tbl, sc.lastterm); \
} \
*ret = (Term); \
return State; \
@@ -1571,7 +1751,8 @@ static int db_select_delete_continue_tree(Process *p,
mp = erts_db_get_match_prog_binary_unchecked(tptr[4]);
sc.p = p;
- sc.tb = tb;
+ sc.tb = &tbl->common;
+ sc.stack = stack;
if (is_big(tptr[5])) {
sc.accum = big_to_uint32(tptr[5]);
} else {
@@ -1580,17 +1761,26 @@ static int db_select_delete_continue_tree(Process *p,
sc.mp = mp;
sc.end_condition = NIL;
sc.max = 1000;
- sc.keypos = tb->common.keypos;
+ sc.keypos = tbl->common.keypos;
- ASSERT(!erts_atomic_read_nob(&tb->is_stack_busy));
- traverse_backwards(tb, &tb->static_stack, lastkey, &doit_select_delete, &sc);
+ if (iter) {
+ iter->next_route_key = lastkey;
+ sc.common.root = catree_find_prev_root(iter, NULL);
+ }
+ else {
+ sc.common.root = &tbl->tree.root;
+ }
- BUMP_REDS(p, 1000 - sc.max);
+ if (sc.common.root) {
+ traverse_backwards(&tbl->common, stack, lastkey, &doit_select_delete, &sc.common, iter);
+
+ BUMP_REDS(p, 1000 - sc.max);
+ }
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.accum, p), DB_ERROR_NONE);
}
- key = GETKEY(tb, (sc.lastterm)->dbterm.tpl);
+ key = GETKEY(&tbl->common, (sc.lastterm)->dbterm.tpl);
if (end_condition != NIL &&
cmp_partly_bound(end_condition,key) > 0) { /* done anyway */
RET_TO_BIF(erts_make_integer(sc.accum,p),DB_ERROR_NONE);
@@ -1620,10 +1810,23 @@ static int db_select_delete_continue_tree(Process *p,
#undef RET_TO_BIF
}
-static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
- Eterm pattern, Eterm *ret)
+static int db_select_delete_continue_tree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
{
DbTableTree *tb = &tbl->tree;
+ ASSERT(!erts_atomic_read_nob(&tb->is_stack_busy));
+ return db_select_delete_continue_tree_common(p, tbl, continuation, ret,
+ &tb->static_stack, NULL);
+}
+
+int db_select_delete_tree_common(Process *p, DbTable *tbl,
+ Eterm tid, Eterm pattern,
+ Eterm *ret,
+ DbTreeStack* stack,
+ CATreeRootIterator* iter)
+{
struct select_delete_context sc;
struct mp_info mpi;
Eterm lastkey = THE_NON_VALUE;
@@ -1641,7 +1844,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
erts_bin_free(mpi.mp); \
} \
if (sc.erase_lastterm) { \
- free_term(tb, sc.lastterm); \
+ free_term(tbl, sc.lastterm); \
} \
*ret = (Term); \
return RetVal; \
@@ -1655,42 +1858,57 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
sc.p = p;
sc.max = 1000;
sc.end_condition = NIL;
- sc.keypos = tb->common.keypos;
- sc.tb = tb;
+ sc.keypos = tbl->common.keypos;
+ sc.tb = &tbl->common;
+ sc.stack = stack;
- if ((errcode = analyze_pattern(tb, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
+ if ((errcode = analyze_pattern(&tbl->common, pattern, NULL, &mpi)) != DB_ERROR_NONE) {
RET_TO_BIF(0,errcode);
}
- if (!mpi.something_can_match) {
+ if (mpi.key_boundness == MS_KEY_IMPOSSIBLE) {
RET_TO_BIF(make_small(0),DB_ERROR_NONE);
/* can't possibly match anything */
}
sc.mp = mpi.mp;
- if (!mpi.got_partial && mpi.some_limitation &&
- CMP_EQ(mpi.least,mpi.most)) {
- doit_select_delete(tb,*(mpi.save_term),&sc, 0 /* direction doesn't
+ if (mpi.key_boundness == MS_KEY_BOUND) {
+ ASSERT(CMP_EQ(mpi.least, mpi.most));
+ if (iter)
+ sc.common.root = catree_find_root(mpi.least, iter);
+ else
+ sc.common.root = &tbl->tree.root;
+ this = find_node(&tbl->common, *sc.common.root, mpi.least, NULL);
+ if (this)
+ doit_select_delete(&tbl->common, this, &sc.common, 0 /* direction doesn't
matter */);
RET_TO_BIF(erts_make_integer(sc.accum,p),DB_ERROR_NONE);
}
- if (mpi.some_limitation) {
- if ((this = find_next_from_pb_key(tb, &tb->static_stack, mpi.most)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_next_from_pb_key(tbl, &sc.common.root, stack, mpi.most, iter);
+ if (this)
+ lastkey = GETKEY(&tbl->common, this->dbterm.tpl);
sc.end_condition = mpi.least;
}
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_last_root(iter);
+ else
+ sc.common.root = &tbl->tree.root;
+ }
- traverse_backwards(tb, &tb->static_stack, lastkey, &doit_select_delete, &sc);
+ traverse_backwards(&tbl->common, stack, lastkey,
+ &doit_select_delete, &sc.common, iter);
BUMP_REDS(p, 1000 - sc.max);
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.accum,p), DB_ERROR_NONE);
}
- key = GETKEY(tb, (sc.lastterm)->dbterm.tpl);
+ key = GETKEY(&tbl->common, (sc.lastterm)->dbterm.tpl);
sz = size_object(key);
if (IS_USMALL(0, sc.accum)) {
hp = HAlloc(p, sz + ERTS_MAGIC_REF_THING_SIZE + 6);
@@ -1714,7 +1932,7 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
/* Don't free mpi.mp, so don't use macro */
if (sc.erase_lastterm) {
- free_term(tb, sc.lastterm);
+ free_term(tbl, sc.lastterm);
}
*ret = bif_trap1(&ets_select_delete_continue_exp, p, continuation);
return DB_ERROR_NONE;
@@ -1723,12 +1941,21 @@ static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
}
-static int db_select_replace_continue_tree(Process *p,
+static int db_select_delete_tree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ DbTableTree *tb = &tbl->tree;
+ return db_select_delete_tree_common(p, tbl, tid, pattern, ret,
+ &tb->static_stack, NULL);
+}
+
+int db_select_replace_continue_tree_common(Process *p,
DbTable *tbl,
Eterm continuation,
- Eterm *ret)
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
{
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_replace_context sc;
unsigned sz;
@@ -1764,7 +1991,7 @@ static int db_select_replace_continue_tree(Process *p,
sc.end_condition = NIL;
sc.lastobj = NULL;
sc.max = 1000;
- sc.keypos = tb->common.keypos;
+ sc.keypos = tbl->common.keypos;
if (is_big(tptr[5])) {
sc.replaced = big_to_uint32(tptr[5]);
} else {
@@ -1772,9 +1999,18 @@ static int db_select_replace_continue_tree(Process *p,
}
prev_replaced = sc.replaced;
- stack = get_any_stack(tb);
- traverse_update_backwards(tb, stack, lastkey, &doit_select_replace, &sc);
- release_stack(tb,stack);
+ if (iter) {
+ iter->next_route_key = lastkey;
+ sc.common.root = catree_find_prev_root(iter, NULL);
+ }
+ else {
+ sc.common.root = &tbl->tree.root;
+ }
+
+ stack = get_any_stack(tbl, stack_container);
+ traverse_update_backwards(&tbl->common, stack, lastkey, &doit_select_replace,
+ &sc.common, iter);
+ release_stack(tbl, stack_container,stack);
// the more objects we've replaced, the more reductions we've consumed
BUMP_REDS(p, MIN(2000, (1000 - sc.max) + (sc.replaced - prev_replaced)));
@@ -1782,7 +2018,7 @@ static int db_select_replace_continue_tree(Process *p,
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.replaced,p), DB_ERROR_NONE);
}
- key = GETKEY(tb, sc.lastobj);
+ key = GETKEY(tbl, sc.lastobj);
if (end_condition != NIL &&
(cmp_partly_bound(end_condition,key) > 0)) {
/* done anyway */
@@ -1813,10 +2049,20 @@ static int db_select_replace_continue_tree(Process *p,
#undef RET_TO_BIF
}
-static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
- Eterm pattern, Eterm *ret)
+static int db_select_replace_continue_tree(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret)
+{
+ return db_select_replace_continue_tree_common(p, tbl, continuation, ret,
+ &tbl->tree, NULL);
+}
+
+int db_select_replace_tree_common(Process *p, DbTable *tbl,
+ Eterm tid, Eterm pattern, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter)
{
- DbTableTree *tb = &tbl->tree;
DbTreeStack* stack;
struct select_replace_context sc;
struct mp_info mpi;
@@ -1843,56 +2089,64 @@ static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
sc.lastobj = NULL;
sc.p = p;
- sc.tb = tb;
+ sc.tb = &tbl->common;
sc.max = 1000;
sc.end_condition = NIL;
- sc.keypos = tb->common.keypos;
+ sc.keypos = tbl->common.keypos;
sc.replaced = 0;
- if ((errcode = analyze_pattern(tb, pattern, db_match_keeps_key, &mpi)) != DB_ERROR_NONE) {
+ if ((errcode = analyze_pattern(&tbl->common, pattern, db_match_keeps_key, &mpi)) != DB_ERROR_NONE) {
RET_TO_BIF(NIL,errcode);
}
- if (!mpi.something_can_match) {
+ if (mpi.key_boundness == MS_KEY_IMPOSSIBLE) {
RET_TO_BIF(make_small(0),DB_ERROR_NONE);
/* can't possibly match anything */
}
sc.mp = mpi.mp;
- stack = get_static_stack(tb);
- if (!mpi.got_partial && mpi.some_limitation &&
- CMP_EQ(mpi.least,mpi.most)) {
- TreeDbTerm* term = *(mpi.save_term);
- doit_select_replace(tb,mpi.save_term,&sc,0 /* dummy */);
- if (stack != NULL) {
- if (TOP_NODE(stack) == term)
- // throw away potentially invalid reference
- REPLACE_TOP_NODE(stack, *(mpi.save_term));
- release_stack(tb, stack);
+ if (mpi.key_boundness == MS_KEY_BOUND) {
+ TreeDbTerm** pp;
+ ASSERT(CMP_EQ(mpi.least, mpi.most));
+ if (iter)
+ sc.common.root = catree_find_root(mpi.least, iter);
+ else
+ sc.common.root = &tbl->tree.root;
+ pp = find_node2(&tbl->common, sc.common.root, mpi.least);
+ if (pp) {
+ doit_select_replace(&tbl->common, pp, &sc.common, 0 /* dummy */);
+ reset_static_stack(stack_container); /* may refer replaced term */
}
RET_TO_BIF(erts_make_integer(sc.replaced,p),DB_ERROR_NONE);
}
- if (stack == NULL)
- stack = get_any_stack(tb);
+ stack = get_any_stack(tbl,stack_container);
- if (mpi.some_limitation) {
- if ((this = find_next_from_pb_key(tb, stack, mpi.most)) != NULL) {
- lastkey = GETKEY(tb, this->dbterm.tpl);
- }
+ if (mpi.key_boundness == MS_KEY_PARTIALLY_BOUND) {
+ this = find_next_from_pb_key(tbl, &sc.common.root, stack, mpi.most, iter);
+ if (this)
+ lastkey = GETKEY(tbl, this->dbterm.tpl);
sc.end_condition = mpi.least;
}
+ else {
+ ASSERT(mpi.key_boundness == MS_KEY_UNBOUND);
+ if (iter)
+ sc.common.root = catree_find_last_root(iter);
+ else
+ sc.common.root = &tbl->tree.root;
+ }
- traverse_update_backwards(tb, stack, lastkey, &doit_select_replace, &sc);
- release_stack(tb,stack);
+ traverse_update_backwards(&tbl->common, stack, lastkey, &doit_select_replace,
+ &sc.common, iter);
+ release_stack(tbl,stack_container,stack);
// the more objects we've replaced, the more reductions we've consumed
BUMP_REDS(p, MIN(2000, (1000 - sc.max) + sc.replaced));
if (sc.max > 0) {
RET_TO_BIF(erts_make_integer(sc.replaced,p),DB_ERROR_NONE);
}
- key = GETKEY(tb, sc.lastobj);
+ key = GETKEY(tbl, sc.lastobj);
sz = size_object(key);
if (IS_USMALL(0, sc.replaced)) {
hp = HAlloc(p, sz + ERTS_MAGIC_REF_THING_SIZE + 6);
@@ -1922,52 +2176,72 @@ static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
}
-static int db_take_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+static int db_select_replace_tree(Process *p, DbTable *tbl, Eterm tid,
+ Eterm pattern, Eterm *ret)
+{
+ return db_select_replace_tree_common(p, tbl, tid, pattern, ret,
+ &tbl->tree, NULL);
+}
+
+int db_take_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root,
+ Eterm key, Eterm *ret,
+ DbTreeStack *stack /* NULL if no static stack */)
{
- DbTableTree *tb = &tbl->tree;
TreeDbTerm *this;
*ret = NIL;
- this = linkout_tree(tb, key);
+ this = linkout_tree(&tbl->common, root, key, stack);
if (this) {
Eterm copy, *hp, *hend;
hp = HAlloc(p, this->dbterm.size + 2);
hend = hp + this->dbterm.size + 2;
- copy = db_copy_object_from_ets(&tb->common,
+ copy = db_copy_object_from_ets(&tbl->common,
&this->dbterm, &hp, &MSO(p));
*ret = CONS(hp, copy, NIL);
hp += 2;
HRelease(p, hend, hp);
- free_term(tb, this);
+ free_term(tbl, this);
}
return DB_ERROR_NONE;
}
+static int db_take_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
+{
+ DbTableTree *tb = &tbl->tree;
+ return db_take_tree_common(p, tbl, &tb->root,
+ key, ret, &tb->static_stack);
+}
+
/*
** Other interface routines (not directly coupled to one bif)
*/
-
-/* Display tree contents (for dump) */
-static void db_print_tree(fmtfn_t to, void *to_arg,
- int show,
- DbTable *tbl)
+void db_print_tree_common(fmtfn_t to, void *to_arg,
+ int show, TreeDbTerm *root, DbTable *tbl)
{
- DbTableTree *tb = &tbl->tree;
#ifdef TREE_DEBUG
if (show)
erts_print(to, to_arg, "\nTree data dump:\n"
"------------------------------------------------\n");
- do_dump_tree2(&tbl->tree, to, to_arg, show, tb->root, 0);
+ do_dump_tree2(&tbl->common, to, to_arg, show, root, 0);
if (show)
erts_print(to, to_arg, "\n"
"------------------------------------------------\n");
#else
- erts_print(to, to_arg, "Ordered set (AVL tree), Elements: %d\n", NITEMS(tb));
+ erts_print(to, to_arg, "Ordered set (AVL tree), Elements: %d\n", NITEMS(tbl));
#endif
}
+/* Display tree contents (for dump) */
+static void db_print_tree(fmtfn_t to, void *to_arg,
+ int show,
+ DbTable *tbl)
+{
+ DbTableTree *tb = &tbl->tree;
+ db_print_tree_common(to, to_arg, show, tb->root, tbl);
+}
+
/* release all memory occupied by a single table */
static int db_free_empty_table_tree(DbTable *tbl)
{
@@ -1992,8 +2266,10 @@ static SWord db_free_table_continue_tree(DbTable *tbl, SWord reds)
(DbTable *) tb,
(void *) tb->static_stack.array,
sizeof(TreeDbTerm *) * STACK_NEED);
- ASSERT(erts_atomic_read_nob(&tb->common.memory_size)
- == sizeof(DbTable));
+ ASSERT((erts_atomic_read_nob(&tb->common.memory_size)
+ == sizeof(DbTable)) ||
+ (erts_atomic_read_nob(&tb->common.memory_size)
+ == (sizeof(DbTable) + sizeof(DbFixation))));
}
return reds;
}
@@ -2012,11 +2288,18 @@ static void do_db_tree_foreach_offheap(TreeDbTerm *,
void (*)(ErlOffHeap *, void *),
void *);
+void db_foreach_offheap_tree_common(TreeDbTerm *root,
+ void (*func)(ErlOffHeap *, void *),
+ void * arg)
+{
+ do_db_tree_foreach_offheap(root, func, arg);
+}
+
static void db_foreach_offheap_tree(DbTable *tbl,
void (*func)(ErlOffHeap *, void *),
void * arg)
{
- do_db_tree_foreach_offheap(tbl->tree.root, func, arg);
+ db_foreach_offheap_tree_common(tbl->tree.root, func, arg);
}
@@ -2041,13 +2324,14 @@ do_db_tree_foreach_offheap(TreeDbTerm *tdbt,
do_db_tree_foreach_offheap(tdbt->right, func, arg);
}
-static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key) {
+static TreeDbTerm *linkout_tree(DbTableCommon *tb, TreeDbTerm **root,
+ Eterm key, DbTreeStack *stack) {
TreeDbTerm **tstack[STACK_NEED];
int tpos = 0;
int dstack[STACK_NEED+1];
int dpos = 0;
int state = 0;
- TreeDbTerm **this = &tb->root;
+ TreeDbTerm **this = root;
Sint c;
int dir;
TreeDbTerm *q = NULL;
@@ -2058,7 +2342,7 @@ static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key) {
* keep the balance. As in insert, we do the stacking ourselves.
*/
- reset_static_stack(tb);
+ reset_stack(stack);
dstack[dpos++] = DIR_END;
for (;;) {
if (!*this) { /* Failure */
@@ -2084,30 +2368,30 @@ static TreeDbTerm *linkout_tree(DbTableTree *tb, Eterm key) {
tstack[tpos++] = this;
state = delsub(this);
}
- erts_atomic_dec_nob(&tb->common.nitems);
+ erts_atomic_dec_nob(&tb->nitems);
break;
}
}
while (state && ( dir = dstack[--dpos] ) != DIR_END) {
this = tstack[--tpos];
if (dir == DIR_LEFT) {
- state = balance_left(this);
+ state = tree_balance_left(this);
} else {
- state = balance_right(this);
+ state = tree_balance_right(this);
}
}
return q;
}
-static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
- Eterm object)
+static TreeDbTerm *linkout_object_tree(DbTableCommon *tb, TreeDbTerm **root,
+ Eterm object, DbTableTree *stack)
{
TreeDbTerm **tstack[STACK_NEED];
int tpos = 0;
int dstack[STACK_NEED+1];
int dpos = 0;
int state = 0;
- TreeDbTerm **this = &tb->root;
+ TreeDbTerm **this = root;
Sint c;
int dir;
TreeDbTerm *q = NULL;
@@ -2122,7 +2406,7 @@ static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
key = GETKEY(tb, tuple_val(object));
- reset_static_stack(tb);
+ reset_static_stack(stack);
dstack[dpos++] = DIR_END;
for (;;) {
if (!*this) { /* Failure */
@@ -2136,7 +2420,7 @@ static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
tstack[tpos++] = this;
this = &((*this)->right);
} else { /* Equal key, found the only possible matching object*/
- if (!db_eq(&tb->common,object,&(*this)->dbterm)) {
+ if (!db_eq(tb,object,&(*this)->dbterm)) {
return NULL;
}
q = (*this);
@@ -2151,16 +2435,16 @@ static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
tstack[tpos++] = this;
state = delsub(this);
}
- erts_atomic_dec_nob(&tb->common.nitems);
+ erts_atomic_dec_nob(&tb->nitems);
break;
}
}
while (state && ( dir = dstack[--dpos] ) != DIR_END) {
this = tstack[--tpos];
if (dir == DIR_LEFT) {
- state = balance_left(this);
+ state = tree_balance_left(this);
} else {
- state = balance_right(this);
+ state = tree_balance_right(this);
}
}
return q;
@@ -2170,7 +2454,7 @@ static TreeDbTerm *linkout_object_tree(DbTableTree *tb,
** For the select functions, analyzes the pattern and determines which
** part of the tree should be searched. Also compiles the match program
*/
-static int analyze_pattern(DbTableTree *tb, Eterm pattern,
+static int analyze_pattern(DbTableCommon *tb, Eterm pattern,
extra_match_validator_t extra_validator, /* Optional callback */
struct mp_info *mpi)
{
@@ -2181,17 +2465,12 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
Eterm *ptpl;
int i;
int num_heads = 0;
- Eterm key;
- Eterm partly_bound;
- int res;
- Eterm least = 0;
- Eterm most = 0;
+ Eterm least = THE_NON_VALUE;
+ Eterm most = THE_NON_VALUE;
+ enum ms_key_boundness boundness;
- mpi->some_limitation = 1;
- mpi->got_partial = 0;
- mpi->something_can_match = 0;
+ mpi->key_boundness = MS_KEY_IMPOSSIBLE;
mpi->mp = NULL;
- mpi->save_term = NULL;
for (lst = pattern; is_list(lst); lst = CDR(list_val(lst)))
++num_heads;
@@ -2212,6 +2491,7 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
Eterm match;
Eterm guard;
Eterm body;
+ Eterm key;
ttpl = CAR(list_val(lst));
if (!is_tuple(ttpl)) {
@@ -2231,7 +2511,7 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
guards[i] = guard = ptpl[2];
bodies[i] = body = ptpl[3];
- if(extra_validator != NULL && !extra_validator(tb->common.keypos, match, guard, body)) {
+ if(extra_validator != NULL && !extra_validator(tb->keypos, match, guard, body)) {
if (buff != sbuff) {
erts_free(ERTS_ALC_T_DB_TMP, buff);
}
@@ -2243,30 +2523,29 @@ static int analyze_pattern(DbTableTree *tb, Eterm pattern,
}
++i;
- partly_bound = NIL;
- res = key_given(tb, tpl, &(mpi->save_term), &partly_bound);
- if ( res >= 0 ) { /* Can match something */
- key = 0;
- mpi->something_can_match = 1;
- if (res > 0) {
- key = GETKEY(tb,tuple_val(tpl));
- } else if (partly_bound != NIL) {
- mpi->got_partial = 1;
- key = partly_bound;
- } else {
- mpi->some_limitation = 0;
- }
- if (key != 0) {
- if (least == 0 ||
- partly_bound_can_match_lesser(key,least)) {
- least = key;
- }
- if (most == 0 ||
- partly_bound_can_match_greater(key,most)) {
- most = key;
- }
- }
- }
+ boundness = key_boundness(tb, tpl, &key);
+ switch (boundness)
+ {
+ case MS_KEY_BOUND:
+ case MS_KEY_PARTIALLY_BOUND:
+ if (is_non_value(least) || partly_bound_can_match_lesser(key,least)) {
+ least = key;
+ }
+ if (is_non_value(most) || partly_bound_can_match_greater(key,most)) {
+ most = key;
+ }
+ break;
+ case MS_KEY_IMPOSSIBLE:
+ case MS_KEY_UNBOUND:
+ break;
+ }
+ if (mpi->key_boundness > boundness)
+ mpi->key_boundness = boundness;
+ }
+
+ if (mpi->key_boundness == MS_KEY_BOUND && !CMP_EQ(least, most)) {
+ /* Several different bound keys */
+ mpi->key_boundness = MS_KEY_PARTIALLY_BOUND;
}
mpi->least = least;
mpi->most = most;
@@ -2308,7 +2587,7 @@ static SWord do_free_tree_continue(DbTableTree *tb, SWord reds)
PUSH_NODE(&tb->static_stack, root);
root = p;
} else {
- free_term(tb, root);
+ free_term((DbTable*)tb, root);
if (--reds < 0) {
return reds; /* Done enough for now */
}
@@ -2322,7 +2601,7 @@ static SWord do_free_tree_continue(DbTableTree *tb, SWord reds)
/*
* Deletion helpers
*/
-static int balance_left(TreeDbTerm **this)
+int tree_balance_left(TreeDbTerm **this)
{
TreeDbTerm *p, *p1, *p2;
int b1, b2, h = 1;
@@ -2367,7 +2646,7 @@ static int balance_left(TreeDbTerm **this)
return h;
}
-static int balance_right(TreeDbTerm **this)
+int tree_balance_right(TreeDbTerm **this)
{
TreeDbTerm *p, *p1, *p2;
int b1, b2, h = 1;
@@ -2439,7 +2718,7 @@ static int delsub(TreeDbTerm **this)
h = 1;
while (tpos && h) {
r = tstack[--tpos];
- h = balance_right(r);
+ h = tree_balance_right(r);
}
return h;
}
@@ -2448,11 +2727,29 @@ static int delsub(TreeDbTerm **this)
* Helper for db_slot
*/
-static TreeDbTerm *slot_search(Process *p, DbTableTree *tb, Sint slot)
+static TreeDbTerm *slot_search(Process *p, TreeDbTerm *root,
+ Sint slot, DbTable *tb,
+ DbTableTree *stack_container,
+ CATreeRootIterator *iter)
{
TreeDbTerm *this;
TreeDbTerm *tmp;
- DbTreeStack* stack = get_any_stack(tb);
+ TreeDbTerm *lastobj;
+ Eterm lastkey;
+ TreeDbTerm **pp;
+ DbTreeStack* stack;
+
+ if (iter) {
+ /* Find first non-empty tree */
+ while (!root) {
+ TreeDbTerm** pp = catree_find_next_root(iter, NULL);
+ if (!pp)
+ return NULL;
+ root = *pp;
+ }
+ }
+
+ stack = get_any_stack(tb,stack_container);
ASSERT(stack != NULL);
if (slot == 1) { /* Don't search from where we are if we are
@@ -2464,57 +2761,84 @@ static TreeDbTerm *slot_search(Process *p, DbTableTree *tb, Sint slot)
are not recorded */
stack->pos = 0;
}
- if (EMPTY_NODE(stack)) {
- this = tb->root;
- if (this == NULL)
- goto done;
- while (this->left != NULL){
- PUSH_NODE(stack, this);
- this = this->left;
- }
- PUSH_NODE(stack, this);
- stack->slot = 1;
- }
- this = TOP_NODE(stack);
- while (stack->slot != slot && this != NULL) {
- if (slot > stack->slot) {
- if (this->right != NULL) {
- this = this->right;
- while (this->left != NULL) {
- PUSH_NODE(stack, this);
- this = this->left;
- }
- PUSH_NODE(stack, this);
- } else {
- for (;;) {
- tmp = POP_NODE(stack);
- this = TOP_NODE(stack);
- if (this == NULL || this->left == tmp)
- break;
- }
- }
- ++(stack->slot);
- } else {
- if (this->left != NULL) {
- this = this->left;
- while (this->right != NULL) {
- PUSH_NODE(stack, this);
- this = this->right;
- }
- PUSH_NODE(stack, this);
- } else {
- for (;;) {
- tmp = POP_NODE(stack);
- this = TOP_NODE(stack);
- if (this == NULL || this->right == tmp)
- break;
- }
- }
- --(stack->slot);
- }
+ while (1) {
+ if (EMPTY_NODE(stack)) {
+ this = root;
+ if (this == NULL)
+ goto next_root;
+ while (this->left != NULL){
+ PUSH_NODE(stack, this);
+ this = this->left;
+ }
+ PUSH_NODE(stack, this);
+ stack->slot++;
+ }
+ this = TOP_NODE(stack);
+ while (stack->slot != slot) {
+ ASSERT(this);
+ lastobj = this;
+ if (slot > stack->slot) {
+ if (this->right != NULL) {
+ this = this->right;
+ while (this->left != NULL) {
+ PUSH_NODE(stack, this);
+ this = this->left;
+ }
+ PUSH_NODE(stack, this);
+ } else {
+ for (;;) {
+ tmp = POP_NODE(stack);
+ this = TOP_NODE(stack);
+ if (!this)
+ goto next_root;
+ if (this->left == tmp)
+ break;
+ }
+ }
+ ++(stack->slot);
+ } else {
+ if (this->left != NULL) {
+ this = this->left;
+ while (this->right != NULL) {
+ PUSH_NODE(stack, this);
+ this = this->right;
+ }
+ PUSH_NODE(stack, this);
+ } else {
+ for (;;) {
+ tmp = POP_NODE(stack);
+ this = TOP_NODE(stack);
+ if (!this)
+ goto next_root;
+ if (this->right == tmp)
+ break;
+ }
+ }
+ --(stack->slot);
+ }
+ }
+ /* Found slot */
+ ASSERT(this);
+ break;
+
+next_root:
+ if (!iter)
+ break; /* EOT */
+
+ ASSERT(slot > stack->slot);
+ if (lastobj) {
+ lastkey = GETKEY(tb, lastobj->dbterm.tpl);
+ lastobj = NULL;
+ }
+ pp = catree_find_next_root(iter, &lastkey);
+ if (!pp)
+ break; /* EOT */
+ root = *pp;
+ stack->pos = 0;
+ find_next(&tb->common, root, stack, lastkey);
}
-done:
- release_stack(tb,stack);
+
+ release_stack(tb,stack_container,stack);
return this;
}
@@ -2522,7 +2846,8 @@ done:
* Find next and previous in sort order
*/
-static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
+static TreeDbTerm *find_next(DbTableCommon *tb, TreeDbTerm *root,
+ DbTreeStack* stack, Eterm key) {
TreeDbTerm *this;
TreeDbTerm *tmp;
Sint c;
@@ -2534,7 +2859,7 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
}
}
if (EMPTY_NODE(stack)) { /* Have to rebuild the stack */
- if (( this = tb->root ) == NULL)
+ if (( this = root ) == NULL)
return NULL;
for (;;) {
PUSH_NODE(stack, this);
@@ -2547,7 +2872,7 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
this = this->right;
} else if (c < 0) {
if (this->left == NULL) /* Done */
- return this;
+ goto found_next;
else
this = this->left;
} else
@@ -2562,8 +2887,6 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
this = this->left;
PUSH_NODE(stack, this);
}
- if (stack->slot > 0)
- ++(stack->slot);
} else {
do {
tmp = POP_NODE(stack);
@@ -2572,13 +2895,17 @@ static TreeDbTerm *find_next(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
return NULL;
}
} while (this->right == tmp);
- if (stack->slot > 0)
- ++(stack->slot);
}
+
+found_next:
+ if (stack->slot > 0)
+ ++(stack->slot);
+
return this;
}
-static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
+static TreeDbTerm *find_prev(DbTableCommon *tb, TreeDbTerm *root,
+ DbTreeStack* stack, Eterm key) {
TreeDbTerm *this;
TreeDbTerm *tmp;
Sint c;
@@ -2590,7 +2917,7 @@ static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
}
}
if (EMPTY_NODE(stack)) { /* Have to rebuild the stack */
- if (( this = tb->root ) == NULL)
+ if (( this = root ) == NULL)
return NULL;
for (;;) {
PUSH_NODE(stack, this);
@@ -2603,7 +2930,7 @@ static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
this = this->left;
} else if (c > 0) {
if (this->right == NULL) /* Done */
- return this;
+ goto found_prev;
else
this = this->right;
} else
@@ -2618,8 +2945,6 @@ static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
this = this->right;
PUSH_NODE(stack, this);
}
- if (stack->slot > 0)
- --(stack->slot);
} else {
do {
tmp = POP_NODE(stack);
@@ -2628,74 +2953,92 @@ static TreeDbTerm *find_prev(DbTableTree *tb, DbTreeStack* stack, Eterm key) {
return NULL;
}
} while (this->left == tmp);
- if (stack->slot > 0)
- --(stack->slot);
}
+
+found_prev:
+ if (stack->slot > 0)
+ --(stack->slot);
+
return this;
}
-static TreeDbTerm *find_next_from_pb_key(DbTableTree *tb, DbTreeStack* stack,
- Eterm key)
+
+static TreeDbTerm *find_next_from_pb_key(DbTable *tbl, TreeDbTerm*** rootpp,
+ DbTreeStack* stack, Eterm key,
+ CATreeRootIterator* iter)
{
+ TreeDbTerm* root;
TreeDbTerm *this;
- TreeDbTerm *tmp;
+ Uint candidate = 0;
Sint c;
+ if (iter) {
+ *rootpp = catree_find_next_from_pb_key_root(key, iter);
+ ASSERT(*rootpp);
+ root = **rootpp;
+ }
+ else {
+ *rootpp = &tbl->tree.root;
+ root = tbl->tree.root;
+ }
+
/* spool the stack, we have to "re-search" */
stack->pos = stack->slot = 0;
- if (( this = tb->root ) == NULL)
+ if (( this = root ) == NULL)
return NULL;
for (;;) {
PUSH_NODE(stack, this);
- if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl))) >= 0) {
+ if (( c = cmp_partly_bound(key,GETKEY(tbl, this->dbterm.tpl))) >= 0) {
if (this->right == NULL) {
- do {
- tmp = POP_NODE(stack);
- if (( this = TOP_NODE(stack)) == NULL) {
- return NULL;
- }
- } while (this->right == tmp);
- return this;
- } else
- this = this->right;
+ stack->pos = candidate;
+ return TOP_NODE(stack);
+ }
+ this = this->right;
} else /*if (c < 0)*/ {
if (this->left == NULL) /* Done */
return this;
- else
- this = this->left;
+ candidate = stack->pos;
+ this = this->left;
}
}
}
-static TreeDbTerm *find_prev_from_pb_key(DbTableTree *tb, DbTreeStack* stack,
- Eterm key)
+static TreeDbTerm *find_prev_from_pb_key(DbTable *tbl, TreeDbTerm*** rootpp,
+ DbTreeStack* stack, Eterm key,
+ CATreeRootIterator* iter)
{
+ TreeDbTerm* root;
TreeDbTerm *this;
- TreeDbTerm *tmp;
+ Uint candidate = 0;
Sint c;
+ if (iter) {
+ *rootpp = catree_find_prev_from_pb_key_root(key, iter);
+ ASSERT(*rootpp);
+ root = **rootpp;
+ }
+ else {
+ *rootpp = &tbl->tree.root;
+ root = tbl->tree.root;
+ }
+
/* spool the stack, we have to "re-search" */
stack->pos = stack->slot = 0;
- if (( this = tb->root ) == NULL)
+ if (( this = root ) == NULL)
return NULL;
for (;;) {
PUSH_NODE(stack, this);
- if (( c = cmp_partly_bound(key,GETKEY(tb, this->dbterm.tpl))) <= 0) {
+ if (( c = cmp_partly_bound(key,GETKEY(tbl, this->dbterm.tpl))) <= 0) {
if (this->left == NULL) {
- do {
- tmp = POP_NODE(stack);
- if (( this = TOP_NODE(stack)) == NULL) {
- return NULL;
- }
- } while (this->left == tmp);
- return this;
- } else
- this = this->left;
- } else /*if (c < 0)*/ {
+ stack->pos = candidate;
+ return TOP_NODE(stack);
+ }
+ this = this->left;
+ } else /*if (c > 0)*/ {
if (this->right == NULL) /* Done */
return this;
- else
- this = this->right;
+ candidate = stack->pos;
+ this = this->right;
}
}
}
@@ -2704,16 +3047,17 @@ static TreeDbTerm *find_prev_from_pb_key(DbTableTree *tb, DbTreeStack* stack,
/*
* Just lookup a node
*/
-static TreeDbTerm *find_node(DbTableTree *tb, Eterm key)
+static TreeDbTerm *find_node(DbTableCommon *tb, TreeDbTerm *root,
+ Eterm key, DbTableTree *stack_container)
{
TreeDbTerm *this;
Sint res;
- DbTreeStack* stack = get_static_stack(tb);
+ DbTreeStack* stack = get_static_stack(stack_container);
if(!stack || EMPTY_NODE(stack)
|| !cmp_key_eq(tb, key, (this=TOP_NODE(stack)))) {
- this = tb->root;
+ this = root;
while (this != NULL && (res = cmp_key(tb,key,this)) != 0) {
if (res < 0)
this = this->left;
@@ -2722,7 +3066,7 @@ static TreeDbTerm *find_node(DbTableTree *tb, Eterm key)
}
}
if (stack) {
- release_stack(tb,stack);
+ release_stack((DbTable*)tb,stack_container,stack);
}
return this;
}
@@ -2730,12 +3074,12 @@ static TreeDbTerm *find_node(DbTableTree *tb, Eterm key)
/*
* Lookup a node and return the address of the node pointer in the tree
*/
-static TreeDbTerm **find_node2(DbTableTree *tb, Eterm key)
+static TreeDbTerm **find_node2(DbTableCommon *tb, TreeDbTerm **root, Eterm key)
{
TreeDbTerm **this;
Sint res;
- this = &tb->root;
+ this = root;
while ((*this) != NULL && (res = cmp_key(tb, key, *this)) != 0) {
if (res < 0)
this = &((*this)->left);
@@ -2752,7 +3096,8 @@ static TreeDbTerm **find_node2(DbTableTree *tb, Eterm key)
* Tries to reuse the existing stack for performance.
*/
-static TreeDbTerm **find_ptr(DbTableTree *tb, DbTreeStack *stack, TreeDbTerm *this) {
+static TreeDbTerm **find_ptr(DbTableCommon *tb, TreeDbTerm **root,
+ DbTreeStack *stack, TreeDbTerm *this) {
Eterm key = GETKEY(tb, this->dbterm.tpl);
TreeDbTerm *tmp;
TreeDbTerm *parent;
@@ -2765,7 +3110,7 @@ static TreeDbTerm **find_ptr(DbTableTree *tb, DbTreeStack *stack, TreeDbTerm *th
}
}
if (EMPTY_NODE(stack)) { /* Have to rebuild the stack */
- if (( tmp = tb->root ) == NULL)
+ if (( tmp = *root ) == NULL)
return NULL;
for (;;) {
PUSH_NODE(stack, tmp);
@@ -2791,7 +3136,7 @@ static TreeDbTerm **find_ptr(DbTableTree *tb, DbTreeStack *stack, TreeDbTerm *th
parent = TOPN_NODE(stack, 1);
if (parent == NULL)
- return ((this != tb->root) ? NULL : &(tb->root));
+ return ((this != *root) ? NULL : root);
if (parent->left == this)
return &(parent->left);
if (parent->right == this)
@@ -2799,12 +3144,11 @@ static TreeDbTerm **find_ptr(DbTableTree *tb, DbTreeStack *stack, TreeDbTerm *th
return NULL;
}
-static int
-db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
- DbUpdateHandle* handle)
+int db_lookup_dbterm_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root,
+ Eterm key, Eterm obj, DbUpdateHandle* handle,
+ DbTableTree *stack_container)
{
- DbTableTree *tb = &tbl->tree;
- TreeDbTerm **pp = find_node2(tb, key);
+ TreeDbTerm **pp = find_node2(&tbl->common, root, key);
int flags = 0;
if (pp == NULL) {
@@ -2815,18 +3159,19 @@ db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
int arity = arityval(*objp);
Eterm *htop, *hend;
- ASSERT(arity >= tb->common.keypos);
+ ASSERT(arity >= tbl->common.keypos);
htop = HAlloc(p, arity + 1);
hend = htop + arity + 1;
sys_memcpy(htop, objp, sizeof(Eterm) * (arity + 1));
- htop[tb->common.keypos] = key;
+ htop[tbl->common.keypos] = key;
obj = make_tuple(htop);
- if (db_put_tree(tbl, obj, 1) != DB_ERROR_NONE) {
+ if (db_put_tree_common(&tbl->common, root,
+ obj, 1, stack_container) != DB_ERROR_NONE) {
return 0;
}
- pp = find_node2(tb, key);
+ pp = find_node2(&tbl->common, root, key);
ASSERT(pp != NULL);
HRelease(p, hend, htop);
flags |= DB_NEW_OBJECT;
@@ -2841,21 +3186,28 @@ db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
return 1;
}
-static void
-db_finalize_dbterm_tree(int cret, DbUpdateHandle *handle)
+static int
+db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
+ DbUpdateHandle* handle)
{
- DbTable *tbl = handle->tb;
DbTableTree *tb = &tbl->tree;
+ return db_lookup_dbterm_tree_common(p, tbl, &tb->root, key, obj, handle, tb);
+}
+
+void db_finalize_dbterm_tree_common(int cret, DbUpdateHandle *handle,
+ DbTableTree *stack_container)
+{
+ DbTable *tbl = handle->tb;
TreeDbTerm *bp = (TreeDbTerm *) *handle->bp;
if (handle->flags & DB_NEW_OBJECT && cret != DB_ERROR_NONE) {
Eterm ret;
- db_erase_tree(tbl, GETKEY(tb, bp->dbterm.tpl), &ret);
+ db_erase_tree(tbl, GETKEY(&tbl->common, bp->dbterm.tpl), &ret);
} else if (handle->flags & DB_MUST_RESIZE) {
db_finalize_resize(handle, offsetof(TreeDbTerm,dbterm));
- reset_static_stack(tb);
+ reset_static_stack(stack_container);
- free_term(tb, bp);
+ free_term(tbl, bp);
}
#ifdef DEBUG
handle->dbterm = 0;
@@ -2863,156 +3215,207 @@ db_finalize_dbterm_tree(int cret, DbUpdateHandle *handle)
return;
}
+static void
+db_finalize_dbterm_tree(int cret, DbUpdateHandle *handle)
+{
+ DbTable *tbl = handle->tb;
+ DbTableTree *tb = &tbl->tree;
+ db_finalize_dbterm_tree_common(cret, handle, tb);
+}
+
/*
* Traverse the tree with a callback function, used by db_match_xxx
*/
-static void traverse_backwards(DbTableTree *tb,
+static void traverse_backwards(DbTableCommon *tb,
DbTreeStack* stack,
Eterm lastkey,
- int (*doit)(DbTableTree *,
- TreeDbTerm *,
- void *,
- int),
- void *context)
+ traverse_doit_funcT* doit,
+ struct select_common *context,
+ CATreeRootIterator* iter)
{
TreeDbTerm *this, *next;
+ TreeDbTerm** root = context->root;
if (lastkey == THE_NON_VALUE) {
- stack->pos = stack->slot = 0;
- if (( this = tb->root ) == NULL) {
- return;
- }
- while (this != NULL) {
- PUSH_NODE(stack, this);
- this = this->right;
- }
- this = TOP_NODE(stack);
- next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl));
- if (!((*doit)(tb, this, context, 0)))
- return;
+ if (iter) {
+ while (*root == NULL) {
+ root = catree_find_prev_root(iter, NULL);
+ if (!root)
+ return;
+ }
+ context->root = root;
+ }
+ stack->pos = stack->slot = 0;
+ next = *root;
+ while (next != NULL) {
+ PUSH_NODE(stack, next);
+ next = next->right;
+ }
+ next = TOP_NODE(stack);
} else {
- next = find_prev(tb, stack, lastkey);
+ next = find_prev(tb, *root, stack, lastkey);
}
- while ((this = next) != NULL) {
- next = find_prev(tb, stack, GETKEY(tb, this->dbterm.tpl));
- if (!((*doit)(tb, this, context, 0)))
- return;
+ while (1) {
+ while (next) {
+ this = next;
+ lastkey = GETKEY(tb, this->dbterm.tpl);
+ next = find_prev(tb, *root, stack, lastkey);
+ if (!((*doit)(tb, this, context, 0)))
+ return;
+ }
+
+ if (!iter)
+ return;
+ ASSERT(is_value(lastkey));
+ root = catree_find_prev_root(iter, &lastkey);
+ if (!root)
+ return;
+ context->root = root;
+ stack->pos = stack->slot = 0;
+ next = find_prev(tb, *root, stack, lastkey);
}
}
/*
* Traverse the tree with a callback function, used by db_match_xxx
*/
-static void traverse_forward(DbTableTree *tb,
+static void traverse_forward(DbTableCommon *tb,
DbTreeStack* stack,
Eterm lastkey,
- int (*doit)(DbTableTree *,
- TreeDbTerm *,
- void *,
- int),
- void *context)
+ traverse_doit_funcT* doit,
+ struct select_common *context,
+ CATreeRootIterator* iter)
{
TreeDbTerm *this, *next;
+ TreeDbTerm **root = context->root;
if (lastkey == THE_NON_VALUE) {
- stack->pos = stack->slot = 0;
- if (( this = tb->root ) == NULL) {
- return;
- }
- while (this != NULL) {
- PUSH_NODE(stack, this);
- this = this->left;
- }
- this = TOP_NODE(stack);
- next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl));
- if (!((*doit)(tb, this, context, 1)))
- return;
+ if (iter) {
+ while (*root == NULL) {
+ root = catree_find_next_root(iter, NULL);
+ if (!root)
+ return;
+ }
+ context->root = root;
+ }
+ stack->pos = stack->slot = 0;
+ next = *root;
+ while (next != NULL) {
+ PUSH_NODE(stack, next);
+ next = next->left;
+ }
+ next = TOP_NODE(stack);
} else {
- next = find_next(tb, stack, lastkey);
+ next = find_next(tb, *root, stack, lastkey);
}
- while ((this = next) != NULL) {
- next = find_next(tb, stack, GETKEY(tb, this->dbterm.tpl));
- if (!((*doit)(tb, this, context, 1)))
- return;
+ while (1) {
+ while (next) {
+ this = next;
+ lastkey = GETKEY(tb, this->dbterm.tpl);
+ next = find_next(tb, *root, stack, lastkey);
+ if (!((*doit)(tb, this, context, 1)))
+ return;
+ }
+
+ if (!iter)
+ return;
+ ASSERT(is_value(lastkey));
+ root = catree_find_next_root(iter, &lastkey);
+ if (!root)
+ return;
+ context->root = root;
+ stack->pos = stack->slot = 0;
+ next = find_next(tb, *root, stack, lastkey);
}
}
/*
* Traverse the tree with an update callback function, used by db_select_replace
*/
-static void traverse_update_backwards(DbTableTree *tb,
+static void traverse_update_backwards(DbTableCommon *tb,
DbTreeStack* stack,
Eterm lastkey,
- int (*doit)(DbTableTree*,
+ int (*doit)(DbTableCommon*,
TreeDbTerm**,
- void*,
+ struct select_common*,
int),
- void* context)
+ struct select_common* context,
+ CATreeRootIterator* iter)
{
int res;
TreeDbTerm *this, *next, **this_ptr;
+ TreeDbTerm** root = context->root;
if (lastkey == THE_NON_VALUE) {
- stack->pos = stack->slot = 0;
- if (( this = tb->root ) == NULL) {
- return;
+ if (iter) {
+ while (*root == NULL) {
+ root = catree_find_prev_root(iter, NULL);
+ if (!root)
+ return;
+ context->root = root;
+ }
}
- while (this != NULL) {
- PUSH_NODE(stack, this);
- this = this->right;
+ stack->pos = stack->slot = 0;
+ next = *root;
+ while (next) {
+ PUSH_NODE(stack, next);
+ next = next->right;
}
- this = TOP_NODE(stack);
- this_ptr = find_ptr(tb, stack, this);
- ASSERT(this_ptr != NULL);
- res = (*doit)(tb, this_ptr, context, 0);
- REPLACE_TOP_NODE(stack, *this_ptr);
- next = find_prev(tb, stack, GETKEY(tb, (*this_ptr)->dbterm.tpl));
- if (!res)
- return;
- } else {
- next = find_prev(tb, stack, lastkey);
+ next = TOP_NODE(stack);
}
+ else
+ next = find_prev(tb, *root, stack, lastkey);
+
+
+ while (1) {
+ while (next) {
+ this = next;
+ this_ptr = find_ptr(tb, root, stack, this);
+ ASSERT(this_ptr != NULL);
+ res = (*doit)(tb, this_ptr, context, 0);
+ this = *this_ptr;
+ REPLACE_TOP_NODE(stack, this);
+ if (!res)
+ return;
+ lastkey = GETKEY(tb, this->dbterm.tpl);
+ next = find_prev(tb, *root, stack, lastkey);
+ }
- while ((this = next) != NULL) {
- this_ptr = find_ptr(tb, stack, this);
- ASSERT(this_ptr != NULL);
- res = (*doit)(tb, this_ptr, context, 0);
- REPLACE_TOP_NODE(stack, *this_ptr);
- next = find_prev(tb, stack, GETKEY(tb, (*this_ptr)->dbterm.tpl));
- if (!res)
+ if (!iter)
+ return;
+ ASSERT(is_value(lastkey));
+ root = catree_find_prev_root(iter, &lastkey);
+ if (!root)
return;
+ context->root = root;
+ stack->pos = stack->slot = 0;
+ next = find_prev(tb, *root, stack, lastkey);
}
}
-/*
- * Returns 0 if not given 1 if given and -1 on no possible match
- * if key is given; *ret is set to point to the object concerned.
- */
-static int key_given(DbTableTree *tb, Eterm pattern, TreeDbTerm ***ret,
- Eterm *partly_bound)
+static enum ms_key_boundness key_boundness(DbTableCommon *tb,
+ Eterm pattern, Eterm *keyp)
{
- TreeDbTerm **this;
Eterm key;
- ASSERT(ret != NULL);
if (pattern == am_Underscore || db_is_variable(pattern) != -1)
- return 0;
- key = db_getkey(tb->common.keypos, pattern);
+ return MS_KEY_UNBOUND;
+ key = db_getkey(tb->keypos, pattern);
if (is_non_value(key))
- return -1; /* can't possibly match anything */
+ return MS_KEY_IMPOSSIBLE; /* can't possibly match anything */
if (!db_has_variable(key)) { /* Bound key */
- if (( this = find_node2(tb, key) ) == NULL) {
- return -1;
- }
- *ret = this;
- return 1;
- } else if (partly_bound != NULL && key != am_Underscore &&
- db_is_variable(key) < 0 && !db_has_map(key))
- *partly_bound = key;
+ *keyp = key;
+ return MS_KEY_BOUND;
+ } else if (key != am_Underscore &&
+ db_is_variable(key) < 0 && !db_has_map(key)) {
+
+ *keyp = key;
+ return MS_KEY_PARTIALLY_BOUND;
+ }
- return 0;
+ return MS_KEY_UNBOUND;
}
@@ -3080,7 +3483,8 @@ static Sint do_cmp_partly_bound(Eterm a, Eterm b, int *done)
}
}
-static Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key) {
+Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key)
+{
int done = 0;
Sint ret = do_cmp_partly_bound(partly_bound_key, bound_key, &done);
#ifdef HARDDEBUG
@@ -3126,7 +3530,7 @@ static int partly_bound_can_match_lesser(Eterm partly_bound_1,
if (ret)
erts_fprintf(stderr," can match lesser than ");
else
- erts_fprintf(stderr," can not match lesser than ");
+ erts_fprintf(stderr," cannot match lesser than ");
erts_fprintf(stderr,"%T\n",partly_bound_2);
#endif
return ret;
@@ -3144,7 +3548,7 @@ static int partly_bound_can_match_greater(Eterm partly_bound_1,
if (ret)
erts_fprintf(stderr," can match greater than ");
else
- erts_fprintf(stderr," can not match greater than ");
+ erts_fprintf(stderr," cannot match greater than ");
erts_fprintf(stderr,"%T\n",partly_bound_2);
#endif
return ret;
@@ -3296,7 +3700,8 @@ static int do_partly_bound_can_match_greater(Eterm a, Eterm b,
* Callback functions for the different match functions
*/
-static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr,
+static int doit_select(DbTableCommon *tb, TreeDbTerm *this,
+ struct select_common* ptr,
int forward)
{
struct select_context *sc = (struct select_context *) ptr;
@@ -3314,7 +3719,7 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0))) {
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, &hp, 2);
+ ret = db_match_dbterm(tb, sc->p,sc->mp, &this->dbterm, &hp, 2);
if (is_value(ret)) {
sc->accum = CONS(hp, ret, sc->accum);
}
@@ -3331,7 +3736,8 @@ static int doit_select(DbTableTree *tb, TreeDbTerm *this, void *ptr,
return 1;
}
-static int doit_select_count(DbTableTree *tb, TreeDbTerm *this, void *ptr,
+static int doit_select_count(DbTableCommon *tb, TreeDbTerm *this,
+ struct select_common* ptr,
int forward)
{
struct select_count_context *sc = (struct select_count_context *) ptr;
@@ -3345,7 +3751,7 @@ static int doit_select_count(DbTableTree *tb, TreeDbTerm *this, void *ptr,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0)) {
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, NULL, 0);
+ ret = db_match_dbterm(tb, sc->p, sc->mp, &this->dbterm, NULL, 0);
if (ret == am_true) {
++(sc->got);
}
@@ -3355,7 +3761,8 @@ static int doit_select_count(DbTableTree *tb, TreeDbTerm *this, void *ptr,
return 1;
}
-static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr,
+static int doit_select_chunk(DbTableCommon *tb, TreeDbTerm *this,
+ struct select_common* ptr,
int forward)
{
struct select_context *sc = (struct select_context *) ptr;
@@ -3374,7 +3781,7 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr,
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, &hp, 2);
+ ret = db_match_dbterm(tb, sc->p, sc->mp, &this->dbterm, &hp, 2);
if (is_value(ret)) {
++(sc->got);
sc->accum = CONS(hp, ret, sc->accum);
@@ -3393,7 +3800,8 @@ static int doit_select_chunk(DbTableTree *tb, TreeDbTerm *this, void *ptr,
}
-static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr,
+static int doit_select_delete(DbTableCommon *tb, TreeDbTerm *this,
+ struct select_common *ptr,
int forward)
{
struct select_delete_context *sc = (struct select_delete_context *) ptr;
@@ -3401,7 +3809,7 @@ static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr,
Eterm key;
if (sc->erase_lastterm)
- free_term(tb, sc->lastterm);
+ free_term((DbTable*)tb, sc->lastterm);
sc->erase_lastterm = 0;
sc->lastterm = this;
@@ -3409,10 +3817,10 @@ static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr,
cmp_partly_bound(sc->end_condition,
GETKEY_WITH_POS(sc->keypos, this->dbterm.tpl)) > 0)
return 0;
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &this->dbterm, NULL, 0);
+ ret = db_match_dbterm(tb, sc->p, sc->mp, &this->dbterm, NULL, 0);
if (ret == am_true) {
key = GETKEY(sc->tb, this->dbterm.tpl);
- linkout_tree(sc->tb, key);
+ linkout_tree(sc->tb, sc->common.root, key, sc->stack);
sc->erase_lastterm = 1;
++sc->accum;
}
@@ -3422,7 +3830,8 @@ static int doit_select_delete(DbTableTree *tb, TreeDbTerm *this, void *ptr,
return 1;
}
-static int doit_select_replace(DbTableTree *tb, TreeDbTerm **this, void *ptr,
+static int doit_select_replace(DbTableCommon *tb, TreeDbTerm **this,
+ struct select_common* ptr,
int forward)
{
struct select_replace_context *sc = (struct select_replace_context *) ptr;
@@ -3436,13 +3845,13 @@ static int doit_select_replace(DbTableTree *tb, TreeDbTerm **this, void *ptr,
GETKEY_WITH_POS(sc->keypos, (*this)->dbterm.tpl)) > 0)) {
return 0;
}
- ret = db_match_dbterm(&tb->common, sc->p, sc->mp, &(*this)->dbterm, NULL, 0);
+ ret = db_match_dbterm(tb, sc->p, sc->mp, &(*this)->dbterm, NULL, 0);
if (is_value(ret)) {
TreeDbTerm* new;
TreeDbTerm* old = *this;
#ifdef DEBUG
- Eterm key = db_getkey(tb->common.keypos, ret);
+ Eterm key = db_getkey(tb->keypos, ret);
ASSERT(is_value(key));
ASSERT(cmp_key(tb, key, old) == 0);
#endif
@@ -3452,7 +3861,7 @@ static int doit_select_replace(DbTableTree *tb, TreeDbTerm **this, void *ptr,
new->balance = old->balance;
sc->lastobj = new->dbterm.tpl;
*this = new;
- free_term(tb, old);
+ free_term((DbTable*)tb, old);
++(sc->replaced);
}
if (--(sc->max) <= 0) {
@@ -3462,7 +3871,7 @@ static int doit_select_replace(DbTableTree *tb, TreeDbTerm **this, void *ptr,
}
#ifdef TREE_DEBUG
-static void do_dump_tree2(DbTableTree* tb, int to, void *to_arg, int show,
+static void do_dump_tree2(DbTableCommon* tb, int to, void *to_arg, int show,
TreeDbTerm *t, int offset)
{
if (t == NULL)
@@ -3471,7 +3880,7 @@ static void do_dump_tree2(DbTableTree* tb, int to, void *to_arg, int show,
if (show) {
const char* prefix;
Eterm term;
- if (tb->common.compress) {
+ if (tb->compress) {
prefix = "key=";
term = GETKEY(tb, t->dbterm.tpl);
}
@@ -3526,7 +3935,7 @@ static void check_slot_pos(DbTableTree *tb)
"element position %d is really 0x%08X, when stack says "
"it's 0x%08X\n", tb->stack.slot, t,
tb->stack.array[tb->stack.pos - 1]);
- do_dump_tree2(tb, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
+ do_dump_tree2(&tb->common, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
}
}
@@ -3541,14 +3950,14 @@ static void check_saved_stack(DbTableTree *tb)
if (t != stack->array[0]) {
erts_fprintf(stderr,"tb->stack[0] is 0x%08X, should be 0x%08X\n",
stack->array[0], t);
- do_dump_tree2(tb, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
+ do_dump_tree2(&tb->common, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
return;
}
while (n < stack->pos) {
if (t == NULL) {
erts_fprintf(stderr, "NULL pointer in tree when stack not empty,"
" stack depth is %d\n", n);
- do_dump_tree2(tb, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
+ do_dump_tree2(&tb->common, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
return;
}
n++;
@@ -3562,7 +3971,7 @@ static void check_saved_stack(DbTableTree *tb)
"represent child pointer in tree!"
"(left == 0x%08X, right == 0x%08X\n",
n, tb->stack[n], t->left, t->right);
- do_dump_tree2(tb, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
+ do_dump_tree2(&tb->common, ERTS_PRINT_STDERR, NULL, 1, tb->root, 0);
return;
}
}
@@ -3581,7 +3990,7 @@ static int check_table_tree(DbTableTree* tb, TreeDbTerm *t)
erts_fprintf(stderr,"balance = %d, left = 0x%08X, right = 0x%08X\n",
t->balance, t->left, t->right);
erts_fprintf(stderr,"\nDump:\n---------------------------------\n");
- do_dump_tree2(tb, ERTS_PRINT_STDERR, NULL, 1, t, 0);
+ do_dump_tree2(&tb->common, ERTS_PRINT_STDERR, NULL, 1, t, 0);
erts_fprintf(stderr,"\n---------------------------------\n");
}
return ((rh > lh) ? rh : lh) + 1;
diff --git a/erts/emulator/beam/erl_db_tree_util.h b/erts/emulator/beam/erl_db_tree_util.h
new file mode 100644
index 0000000000..02df74678d
--- /dev/null
+++ b/erts/emulator/beam/erl_db_tree_util.h
@@ -0,0 +1,158 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-2016. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifndef _DB_TREE_UTIL_H
+#define _DB_TREE_UTIL_H
+
+/*
+** Internal functions and macros used by both the CA tree and the AVL tree
+*/
+
+/*
+** A stack of this size is enough for an AVL tree with more than
+** 0xFFFFFFFF elements. May be subject to change if
+** the datatype of the element counter is changed to a 64 bit integer.
+** The Maximal height of an AVL tree is calculated as:
+** h(n) <= 1.4404 * log(n + 2) - 0.328
+** Where n denotes the number of nodes, h(n) the height of the tree
+** with n nodes and log is the binary logarithm.
+*/
+
+#define STACK_NEED 50
+
+#define PUSH_NODE(Dtt, Tdt) \
+ ((Dtt)->array[(Dtt)->pos++] = Tdt)
+
+#define POP_NODE(Dtt) \
+ (((Dtt)->pos) ? \
+ (Dtt)->array[--((Dtt)->pos)] : NULL)
+
+#define TOP_NODE(Dtt) \
+ ((Dtt->pos) ? \
+ (Dtt)->array[(Dtt)->pos - 1] : NULL)
+
+#define EMPTY_NODE(Dtt) (TOP_NODE(Dtt) == NULL)
+
+static ERTS_INLINE void free_term(DbTable *tb, TreeDbTerm* p)
+{
+ db_free_term(tb, p, offsetof(TreeDbTerm, dbterm));
+}
+
+/*
+** Some macros for "direction stacks"
+*/
+#define DIR_LEFT 0
+#define DIR_RIGHT 1
+#define DIR_END 2
+
+static ERTS_INLINE Sint cmp_key(DbTableCommon* tb, Eterm key, TreeDbTerm* obj) {
+ return CMP(key, GETKEY(tb,obj->dbterm.tpl));
+}
+
+int tree_balance_left(TreeDbTerm **this);
+int tree_balance_right(TreeDbTerm **this);
+
+int db_first_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm *ret, DbTableTree *stack_container);
+int db_next_tree_common(Process *p, DbTable *tbl,
+ TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTreeStack* stack);
+int db_last_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm *ret, DbTableTree *stack_container);
+int db_prev_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTreeStack* stack);
+int db_put_tree_common(DbTableCommon *tb, TreeDbTerm **root, Eterm obj,
+ int key_clash_fail, DbTableTree *stack_container);
+int db_get_tree_common(Process *p, DbTableCommon *tb, TreeDbTerm *root, Eterm key,
+ Eterm *ret, DbTableTree *stack_container);
+int db_get_element_tree_common(Process *p, DbTableCommon *tb, TreeDbTerm *root, Eterm key,
+ int ndex, Eterm *ret, DbTableTree *stack_container);
+int db_member_tree_common(DbTableCommon *tb, TreeDbTerm *root, Eterm key, Eterm *ret,
+ DbTableTree *stack_container);
+int db_erase_tree_common(DbTable *tbl, TreeDbTerm **root, Eterm key, Eterm *ret,
+ DbTreeStack *stack /* NULL if no static stack */);
+int db_erase_object_tree_common(DbTable *tbl, TreeDbTerm **root, Eterm object,
+ Eterm *ret, DbTableTree *stack_container);
+int db_slot_tree_common(Process *p, DbTable *tbl, TreeDbTerm *root,
+ Eterm slot_term, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator*);
+int db_select_chunk_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, Sint chunk_size,
+ int reverse, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator*);
+int db_select_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, int reverse, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator*);
+int db_select_delete_tree_common(Process *p, DbTable *tbl,
+ Eterm tid, Eterm pattern,
+ Eterm *ret,
+ DbTreeStack* stack,
+ CATreeRootIterator* iter);
+int db_select_continue_tree_common(Process *p,
+ DbTableCommon *tb,
+ Eterm continuation,
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter);
+int db_select_delete_continue_tree_common(Process *p,
+ DbTable *tbl,
+ Eterm continuation,
+ Eterm *ret,
+ DbTreeStack* stack,
+ CATreeRootIterator* iter);
+int db_select_count_tree_common(Process *p, DbTable *tb,
+ Eterm tid, Eterm pattern, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter);
+int db_select_count_continue_tree_common(Process *p,
+ DbTable *tb,
+ Eterm continuation,
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter);
+int db_select_replace_tree_common(Process *p, DbTable*,
+ Eterm tid, Eterm pattern, Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter);
+int db_select_replace_continue_tree_common(Process *p,
+ DbTable*,
+ Eterm continuation,
+ Eterm *ret,
+ DbTableTree *stack_container,
+ CATreeRootIterator* iter);
+int db_take_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root,
+ Eterm key, Eterm *ret,
+ DbTreeStack *stack /* NULL if no static stack */);
+void db_print_tree_common(fmtfn_t to, void *to_arg,
+ int show, TreeDbTerm *root, DbTable *tbl);
+void db_foreach_offheap_tree_common(TreeDbTerm *root,
+ void (*func)(ErlOffHeap *, void *),
+ void * arg);
+int db_lookup_dbterm_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root,
+ Eterm key, Eterm obj, DbUpdateHandle* handle,
+ DbTableTree *stack_container);
+void db_finalize_dbterm_tree_common(int cret, DbUpdateHandle *handle,
+ DbTableTree *stack_container);
+Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key);
+
+#endif /* _DB_TREE_UTIL_H */
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index f1d47326b4..a78623f490 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -3118,9 +3118,7 @@ void* db_store_term_comp(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
Uint new_sz = offset + db_size_dbterm_comp(tb, obj);
byte* basep;
DbTerm* newp;
-#ifdef DEBUG
byte* top;
-#endif
ASSERT(tb->compress);
if (old != 0) {
@@ -3142,11 +3140,8 @@ void* db_store_term_comp(DbTableCommon *tb, DbTerm* old, Uint offset, Eterm obj)
}
newp->size = size_object(obj);
-#ifdef DEBUG
- top =
-#endif
- copy_to_comp(tb, obj, newp, new_sz);
- ASSERT(top <= basep + new_sz);
+ top = copy_to_comp(tb, obj, newp, new_sz);
+ ASSERT(top <= basep + new_sz); (void)top;
/* ToDo: Maybe realloc if ((basep+new_sz) - top) > WASTED_SPACE_LIMIT */
diff --git a/erts/emulator/beam/erl_db_util.h b/erts/emulator/beam/erl_db_util.h
index 6ec3b4f98f..e1af9210ea 100644
--- a/erts/emulator/beam/erl_db_util.h
+++ b/erts/emulator/beam/erl_db_util.h
@@ -89,7 +89,16 @@ typedef struct {
void** bp; /* {Hash|Tree}DbTerm** */
Uint new_size;
int flags;
- void* lck;
+ union {
+ struct {
+ erts_rwmtx_t* lck;
+ } hash;
+ struct {
+ struct DbTableCATreeNode* base_node;
+ struct DbTableCATreeNode* parent;
+ int current_level;
+ } catree;
+ } u;
} DbUpdateHandle;
@@ -274,23 +283,28 @@ typedef struct db_table_common {
} DbTableCommon;
/* These are status bit patterns */
-#define DB_PRIVATE (1 << 0)
-#define DB_PROTECTED (1 << 1)
-#define DB_PUBLIC (1 << 2)
-#define DB_DELETE (1 << 3) /* table is being deleted */
-#define DB_SET (1 << 4)
-#define DB_BAG (1 << 5)
-#define DB_DUPLICATE_BAG (1 << 6)
-#define DB_ORDERED_SET (1 << 7)
-#define DB_FINE_LOCKED (1 << 8) /* write_concurrency */
-#define DB_FREQ_READ (1 << 9) /* read_concurrency */
-#define DB_NAMED_TABLE (1 << 10)
-#define DB_BUSY (1 << 11)
+#define DB_PRIVATE (1 << 0)
+#define DB_PROTECTED (1 << 1)
+#define DB_PUBLIC (1 << 2)
+#define DB_DELETE (1 << 3) /* table is being deleted */
+#define DB_SET (1 << 4)
+#define DB_BAG (1 << 5)
+#define DB_DUPLICATE_BAG (1 << 6)
+#define DB_ORDERED_SET (1 << 7)
+#define DB_CA_ORDERED_SET (1 << 8)
+#define DB_FINE_LOCKED (1 << 9) /* write_concurrency */
+#define DB_FREQ_READ (1 << 10) /* read_concurrency */
+#define DB_NAMED_TABLE (1 << 11)
+#define DB_BUSY (1 << 12)
+
+#define DB_CATREE_FORCE_SPLIT (1 << 31) /* erts_debug */
#define IS_HASH_TABLE(Status) (!!((Status) & \
(DB_BAG | DB_SET | DB_DUPLICATE_BAG)))
#define IS_TREE_TABLE(Status) (!!((Status) & \
DB_ORDERED_SET))
+#define IS_CATREE_TABLE(Status) (!!((Status) & \
+ DB_CA_ORDERED_SET))
#define NFIXED(T) (erts_refc_read(&(T)->common.fix_count,0))
#define IS_FIXED(T) (NFIXED(T) != 0)
diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c
index a65dbbf42b..47dd115c82 100644
--- a/erts/emulator/beam/erl_gc.c
+++ b/erts/emulator/beam/erl_gc.c
@@ -1133,9 +1133,28 @@ erts_garbage_collect_literals(Process* p, Eterm* literals,
reds = (Sint64) garbage_collect(p, ERTS_INVALID_HFRAG_PTR, 0,
p->arg_reg, p->arity, fcalls,
ygen_usage);
+ if (ERTS_PROC_IS_EXITING(p)) {
+ return 0;
+ }
ASSERT(!(p->flags & (F_DIRTY_MAJOR_GC|F_DIRTY_MINOR_GC)));
+ if (MAX_HEAP_SIZE_GET(p)) {
+ Uint new_heap_size;
+ Uint old_heap_size;
+ Uint total_heap_size;
+
+ new_heap_size = HEAP_END(p) - HEAP_START(p);
+ old_heap_size = erts_next_heap_size(lit_size, 0);
+ total_heap_size = new_heap_size + old_heap_size;
+ if (MAX_HEAP_SIZE_GET(p) < total_heap_size &&
+ reached_max_heap_size(p, total_heap_size,
+ new_heap_size, old_heap_size)) {
+ erts_set_self_exiting(p, am_killed);
+ return 0;
+ }
+ }
+
/*
* Set GC state.
*/
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 57c6c10c7f..9ba3ae226e 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -128,7 +128,7 @@ const Eterm etp_hole_marker = 0;
static int modified_sched_thread_suggested_stack_size = 0;
-Eterm erts_init_process_id;
+Eterm erts_init_process_id = ERTS_INVALID_PID;
/*
* Note about VxWorks: All variables must be initialized by executable code,
@@ -163,7 +163,6 @@ int erts_initialized = 0;
* Configurable parameters.
*/
-Uint display_items; /* no of items to display in traces etc */
int H_MIN_SIZE; /* The minimum heap grain */
int BIN_VH_MIN_SIZE; /* The minimum binary virtual*/
int H_MAX_SIZE; /* The maximum heap size */
@@ -375,21 +374,19 @@ erl_init(int ncpu,
}
static Eterm
-erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** argv)
+erl_first_process_otp(char* mod_name, int argc, char** argv)
{
int i;
- Eterm start_mod;
Eterm args;
Eterm res;
Eterm* hp;
Process parent;
ErlSpawnOpts so;
- Eterm env;
-
- start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1);
- if (erts_find_function(start_mod, am_start, 2,
+ Eterm boot_mod;
+
+ if (erts_find_function(am_erl_init, am_start, 2,
erts_active_code_ix()) == NULL) {
- erts_exit(ERTS_ERROR_EXIT, "No function %s:start/2\n", modname);
+ erts_exit(ERTS_ERROR_EXIT, "No function erl_init:start/2\n");
}
/*
@@ -405,13 +402,13 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char**
args = CONS(hp, new_binary(&parent, (byte*)argv[i], len), args);
hp += 2;
}
- env = new_binary(&parent, code, size);
+ boot_mod = erts_atom_put((byte *) mod_name, sys_strlen(mod_name), ERTS_ATOM_ENC_LATIN1, 1);
args = CONS(hp, args, NIL);
hp += 2;
- args = CONS(hp, env, args);
+ args = CONS(hp, boot_mod, args);
so.flags = erts_default_spo_flags|SPO_SYSTEM_PROC;
- res = erl_create_process(&parent, start_mod, am_start, args, &so);
+ res = erl_create_process(&parent, am_erl_init, am_start, args, &so);
erts_proc_unlock(&parent, ERTS_PROC_LOCK_MAIN);
erts_cleanup_empty_process(&parent);
return res;
@@ -481,7 +478,6 @@ erts_preloaded(Process* p)
/* static variables that must not change (use same values at restart) */
static char* program;
static char* init = "init";
-static char* boot = "boot";
static int boot_argc;
static char** boot_argv;
@@ -535,9 +531,6 @@ void erts_usage(void)
int this_rel = this_rel_num();
erts_fprintf(stderr, "Usage: %s [flags] [ -- [init_args] ]\n", progname(program));
erts_fprintf(stderr, "The flags are:\n\n");
-
- /* erts_fprintf(stderr, "-# number set the number of items to be used in traces etc\n"); */
-
erts_fprintf(stderr, "-a size suggested stack size in kilo words for threads\n");
erts_fprintf(stderr, " in the async-thread pool, valid range is [%d-%d]\n",
ERTS_ASYNC_THREAD_MIN_STACK_SIZE,
@@ -545,13 +538,9 @@ void erts_usage(void)
erts_fprintf(stderr, "-A number set number of threads in async thread pool,\n");
erts_fprintf(stderr, " valid range is [0-%d]\n",
ERTS_MAX_NO_OF_ASYNC_THREADS);
-
erts_fprintf(stderr, "-B[c|d|i] c to have Ctrl-c interrupt the Erlang shell,\n");
erts_fprintf(stderr, " d (or no extra option) to disable the break\n");
erts_fprintf(stderr, " handler, i to ignore break signals\n");
-
- /* erts_fprintf(stderr, "-b func set the boot function (default boot)\n"); */
-
erts_fprintf(stderr, "-c bool enable or disable time correction\n");
erts_fprintf(stderr, "-C mode set time warp mode; valid modes are:\n");
erts_fprintf(stderr, " no_time_warp|single_time_warp|multi_time_warp\n");
@@ -570,7 +559,6 @@ void erts_usage(void)
erts_pd_initial_size);
erts_fprintf(stderr, "-hmqd val set default message queue data flag for processes,\n");
erts_fprintf(stderr, " valid values are: off_heap | on_heap\n");
-
erts_fprintf(stderr, "-IOp number set number of pollsets to be used to poll for I/O,\n");
erts_fprintf(stderr, " This value has to be equal or smaller than the\n");
erts_fprintf(stderr, " number of poll threads. If the current platform\n");
@@ -581,9 +569,7 @@ void erts_usage(void)
erts_fprintf(stderr, " number of poll threads.");
erts_fprintf(stderr, "-IOPt number set number of threads to be used to poll for I/O\n");
erts_fprintf(stderr, " as a percentage of the number of schedulers.");
-
- /* erts_fprintf(stderr, "-i module set the boot module (default init)\n"); */
-
+ erts_fprintf(stderr, "-i module set the boot module (default init)\n");
erts_fprintf(stderr, "-n[s|a|d] Control behavior of signals to ports\n");
erts_fprintf(stderr, " Note that this flag is deprecated!\n");
erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n");
@@ -598,7 +584,6 @@ void erts_usage(void)
erts_fprintf(stderr, "-R number set compatibility release number,\n");
erts_fprintf(stderr, " valid range [%d-%d]\n",
this_rel-2, this_rel);
-
erts_fprintf(stderr, "-r force ets memory block to be moved on realloc\n");
erts_fprintf(stderr, "-rg amount set reader groups limit\n");
erts_fprintf(stderr, "-sbt type set scheduler bind type, valid types are:\n");
@@ -669,9 +654,7 @@ void erts_usage(void)
erts_fprintf(stderr, "-T number set modified timing level, valid range is [0-%d]\n",
ERTS_MODIFIED_TIMING_LEVELS-1);
erts_fprintf(stderr, "-V print Erlang version\n");
-
erts_fprintf(stderr, "-v turn on chatty mode (GCs will be reported etc)\n");
-
erts_fprintf(stderr, "-W<i|w|e> set error logger warnings mapping,\n");
erts_fprintf(stderr, " see error_logger documentation for details\n");
erts_fprintf(stderr, "-zdbbl size set the distribution buffer busy limit in kilobytes\n");
@@ -762,7 +745,6 @@ early_init(int *argc, char **argv) /*
erts_sched_compact_load = 1;
erts_printf_eterm_func = erts_printf_term;
- display_items = 200;
erts_backtrace_depth = DEFAULT_BACKTRACE_SIZE;
erts_async_max_threads = ERTS_DEFAULT_NO_ASYNC_THREADS;
erts_async_thread_suggested_stack_size = ERTS_ASYNC_THREAD_MIN_STACK_SIZE;
@@ -1269,25 +1251,9 @@ erl_start(int argc, char **argv)
/*
* NOTE: -M flags are handled (and removed from argv) by
- * erts_alloc_init().
- *
- * The -d, -m, -S, -t, and -T flags was removed in
- * Erlang 5.3/OTP R9C.
- *
- * -S, and -T has been reused in Erlang 5.5/OTP R11B.
- *
- * -d has been reused in a patch R12B-4.
+ * erts_alloc_init().
*/
- case '#' :
- arg = get_arg(argv[i]+2, argv[i+1], &i);
- if ((display_items = atoi(arg)) == 0) {
- erts_fprintf(stderr, "bad display items%s\n", arg);
- erts_usage();
- }
- VERBOSE(DEBUG_SYSTEM,
- ("using display items %d\n",display_items));
- break;
case 'p':
if (!sys_strncmp(argv[i],"-pc",3)) {
int printable_chars = ERL_PRINTABLE_CHARACTERS_LATIN1;
@@ -1566,11 +1532,6 @@ erl_start(int argc, char **argv)
init = get_arg(argv[i]+2, argv[i+1], &i);
break;
- case 'b':
- /* define name of initial function */
- boot = get_arg(argv[i]+2, argv[i+1], &i);
- break;
-
case 'B':
if (argv[i][2] == 'i') /* +Bi */
ignore_break = 1;
@@ -2256,8 +2217,8 @@ erl_start(int argc, char **argv)
erts_initialized = 1;
- erts_init_process_id = erl_first_process_otp("otp_ring0", NULL, 0,
- boot_argc, boot_argv);
+ erts_init_process_id = erl_first_process_otp(init, boot_argc, boot_argv);
+ ASSERT(erts_init_process_id != ERTS_INVALID_PID);
{
/*
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index 463ae898a3..cfa63e7cd9 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -42,6 +42,7 @@
#include "erl_term.h"
#include "erl_threads.h"
#include "erl_atom_table.h"
+#include "erl_utils.h"
typedef struct {
char *name;
@@ -91,6 +92,8 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "db_tab", "address" },
{ "db_tab_fix", "address" },
{ "db_hash_slot", "address" },
+ { "erl_db_catree_base_node", NULL },
+ { "erl_db_catree_route_node", "index" },
{ "resource_monitors", "address" },
{ "driver_list", NULL },
{ "proc_msgq", "pid" },
@@ -191,6 +194,12 @@ struct lc_locked_lock_t_ {
unsigned int line;
erts_lock_flags_t flags;
erts_lock_options_t taken_options;
+ /*
+ * Pointer back to the lock instance if it exists or NULL for proc locks.
+ * If set, we use it to allow trylock of other lock instance
+ * but with identical lock order as an already locked lock.
+ */
+ erts_lc_lock_t *lck;
};
typedef struct {
@@ -404,6 +413,10 @@ new_locked_lock(lc_thread_t* thr,
ll->line = line;
ll->flags = lck->flags;
ll->taken_options = options;
+ if ((lck->flags & ERTS_LOCK_FLAGS_MASK_TYPE) == ERTS_LOCK_FLAGS_TYPE_PROCLOCK)
+ ll->lck = NULL;
+ else
+ ll->lck = lck;
return ll;
}
@@ -707,6 +720,14 @@ erts_lc_get_lock_order_id(char *name)
return (Sint16) -1;
}
+static int
+lc_is_term_order(Sint16 id)
+{
+ return erts_lock_order[id].internal_order != NULL
+ && sys_strcmp(erts_lock_order[id].internal_order, "term") == 0;
+}
+
+
static int compare_locked_by_id(lc_locked_lock_t *locked_lock, erts_lc_lock_t *comparand)
{
if(locked_lock->id < comparand->id) {
@@ -718,18 +739,23 @@ static int compare_locked_by_id(lc_locked_lock_t *locked_lock, erts_lc_lock_t *c
return 0;
}
-static int compare_locked_by_id_extra(lc_locked_lock_t *locked_lock, erts_lc_lock_t *comparand)
+static int compare_locked_by_id_extra(lc_locked_lock_t *ll, erts_lc_lock_t *comparand)
{
- int order = compare_locked_by_id(locked_lock, comparand);
+ int order = compare_locked_by_id(ll, comparand);
if(order) {
return order;
- } else if(locked_lock->extra < comparand->extra) {
+ }
+ if (ll->flags & ERTS_LOCK_FLAGS_PROPERTY_TERM_ORDER) {
+ ASSERT(!is_header(ll->extra) && !is_header(comparand->extra));
+ return CMP(ll->extra, comparand->extra);
+ }
+
+ if(ll->extra < comparand->extra) {
return -1;
- } else if(locked_lock->extra > comparand->extra) {
+ } else if(ll->extra > comparand->extra) {
return 1;
}
-
return 0;
}
@@ -968,7 +994,8 @@ erts_lc_trylock_force_busy_flg(erts_lc_lock_t *lck, erts_lock_options_t options)
return 0;
}
else {
- lc_locked_lock_t *tl_lck;
+ lc_locked_lock_t *ll;
+ int order;
ASSERT(thr->locked.last);
@@ -977,25 +1004,25 @@ erts_lc_trylock_force_busy_flg(erts_lc_lock_t *lck, erts_lock_options_t options)
type_order_violation("trylocking ", thr, lck);
#endif
- if (thr->locked.last->id < lck->id
- || (thr->locked.last->id == lck->id
- && thr->locked.last->extra < lck->extra))
- return 0;
+ ll = thr->locked.last;
+ order = compare_locked_by_id_extra(ll, lck);
+
+ if (order < 0)
+ return 0;
/*
- * Lock order violation
+ * TryLock order violation
*/
-
- /* Check that we are not trying to lock this lock twice */
- for (tl_lck = thr->locked.last; tl_lck; tl_lck = tl_lck->prev) {
- if (tl_lck->id < lck->id
- || (tl_lck->id == lck->id && tl_lck->extra <= lck->extra)) {
- if (tl_lck->id == lck->id && tl_lck->extra == lck->extra)
- lock_twice("Trylocking", thr, lck, options);
- break;
- }
- }
+ /* Check that we are not trying to lock this lock twice */
+ do {
+ if (order == 0 && (ll->lck == lck || !ll->lck))
+ lock_twice("Trylocking", thr, lck, options);
+ ll = ll->prev;
+ if (!ll)
+ break;
+ order = compare_locked_by_id_extra(ll, lck);
+ } while (order >= 0);
#ifndef ERTS_LC_ALLWAYS_FORCE_BUSY_TRYLOCK_ON_LOCK_ORDER_VIOLATION
/* We only force busy if a lock order violation would occur
@@ -1042,10 +1069,10 @@ void erts_lc_trylock_flg_x(int locked, erts_lc_lock_t *lck, erts_lock_options_t
#endif
for (tl_lck = thr->locked.last; tl_lck; tl_lck = tl_lck->prev) {
- if (tl_lck->id < lck->id
- || (tl_lck->id == lck->id && tl_lck->extra <= lck->extra)) {
- if (tl_lck->id == lck->id && tl_lck->extra == lck->extra)
- lock_twice("Trylocking", thr, lck, options);
+ int order = compare_locked_by_id_extra(tl_lck, lck);
+ if (order <= 0) {
+ if (order == 0 && (tl_lck->lck == lck || !tl_lck->lck))
+ lock_twice("Trylocking", thr, lck, options);
if (locked) {
ll->next = tl_lck->next;
ll->prev = tl_lck;
@@ -1087,10 +1114,10 @@ void erts_lc_require_lock_flg(erts_lc_lock_t *lck, erts_lock_options_t options,
for (l_lck2 = thr->required.last;
l_lck2;
l_lck2 = l_lck2->prev) {
- if (l_lck2->id < lck->id
- || (l_lck2->id == lck->id && l_lck2->extra < lck->extra))
+ int order = compare_locked_by_id_extra(l_lck2, lck);
+ if (order < 0)
break;
- else if (l_lck2->id == lck->id && l_lck2->extra == lck->extra)
+ if (order == 0)
require_twice(thr, lck);
}
if (!l_lck2) {
@@ -1148,6 +1175,7 @@ void erts_lc_lock_flg_x(erts_lc_lock_t *lck, erts_lock_options_t options,
{
lc_thread_t *thr;
lc_locked_lock_t *new_ll;
+ int order;
if (lck->inited != ERTS_LC_INITITALIZED)
uninitialized_lock();
@@ -1163,10 +1191,10 @@ void erts_lc_lock_flg_x(erts_lc_lock_t *lck, erts_lock_options_t options,
thr->locked.last = thr->locked.first = new_ll;
ASSERT(0 < lck->id && lck->id < ERTS_LOCK_ORDER_SIZE);
thr->matrix.m[lck->id][0] = 1;
+ return;
}
- else if (thr->locked.last->id < lck->id
- || (thr->locked.last->id == lck->id
- && thr->locked.last->extra < lck->extra)) {
+ order = compare_locked_by_id_extra(thr->locked.last, lck);
+ if (order < 0) {
lc_locked_lock_t* ll;
if (LOCK_IS_TYPE_ORDER_VIOLATION(lck->flags, thr->locked.last->flags)) {
type_order_violation("locking ", thr, lck);
@@ -1184,7 +1212,7 @@ void erts_lc_lock_flg_x(erts_lc_lock_t *lck, erts_lock_options_t options,
thr->locked.last->next = new_ll;
thr->locked.last = new_ll;
}
- else if (thr->locked.last->id == lck->id && thr->locked.last->extra == lck->extra)
+ else if (order == 0)
lock_twice("Locking", thr, lck, options);
else
lock_order_violation(thr, lck);
@@ -1296,7 +1324,6 @@ void
erts_lc_init_lock(erts_lc_lock_t *lck, char *name, erts_lock_flags_t flags)
{
lck->id = erts_lc_get_lock_order_id(name);
-
lck->extra = (UWord) &lck->extra;
ASSERT(is_not_immed(lck->extra));
lck->flags = flags;
@@ -1309,8 +1336,13 @@ erts_lc_init_lock_x(erts_lc_lock_t *lck, char *name, erts_lock_flags_t flags, Et
{
lck->id = erts_lc_get_lock_order_id(name);
lck->extra = extra;
- ASSERT(is_immed(lck->extra));
lck->flags = flags;
+ if (lc_is_term_order(lck->id)) {
+ lck->flags |= ERTS_LOCK_FLAGS_PROPERTY_TERM_ORDER;
+ ASSERT(!is_header(lck->extra));
+ }
+ else
+ ASSERT(is_immed(lck->extra));
lck->taken_options = 0;
lck->inited = ERTS_LC_INITITALIZED;
}
diff --git a/erts/emulator/beam/erl_lock_check.h b/erts/emulator/beam/erl_lock_check.h
index d10e32985a..b32f27d9f9 100644
--- a/erts/emulator/beam/erl_lock_check.h
+++ b/erts/emulator/beam/erl_lock_check.h
@@ -104,7 +104,7 @@ Eterm erts_lc_dump_graph(void);
#define erts_lc_lock(lck) erts_lc_lock_x(lck,__FILE__,__LINE__)
#define erts_lc_trylock(res,lck) erts_lc_trylock_x(res,lck,__FILE__,__LINE__)
-#define erts_lc_lock_flg(lck) erts_lc_lock_flg_x(lck,__FILE__,__LINE__)
-#define erts_lc_trylock_flg(res,lck) erts_lc_trylock_flg_x(res,lck,__FILE__,__LINE__)
+#define erts_lc_lock_flg(lck,flg) erts_lc_lock_flg_x(lck,flg,__FILE__,__LINE__)
+#define erts_lc_trylock_flg(res,lck,flg) erts_lc_trylock_flg_x(res,lck,flg,__FILE__,__LINE__)
#endif /* #ifndef ERTS_LOCK_CHECK_H__ */
diff --git a/erts/emulator/beam/erl_lock_count.h b/erts/emulator/beam/erl_lock_count.h
index 89d95a73cf..0d47b16e0b 100644
--- a/erts/emulator/beam/erl_lock_count.h
+++ b/erts/emulator/beam/erl_lock_count.h
@@ -532,7 +532,7 @@ ERTS_GLB_INLINE
void lcnt_dec_lock_state__(ethr_atomic_t *l_state) {
ethr_sint_t state = ethr_atomic_dec_read_acqb(l_state);
- /* We can not assume that state is >= -1 here; unlock and unacquire might
+ /* We cannot assume that state is >= -1 here; unlock and unacquire might
* bring it below -1 and race to increment it back. */
if(state < 0) {
diff --git a/erts/emulator/beam/erl_lock_flags.h b/erts/emulator/beam/erl_lock_flags.h
index d711f69456..2db133b598 100644
--- a/erts/emulator/beam/erl_lock_flags.h
+++ b/erts/emulator/beam/erl_lock_flags.h
@@ -28,15 +28,17 @@
/* Property/category are bitfields to simplify their use in masks. */
#define ERTS_LOCK_FLAGS_MASK_CATEGORY (0xFFC0)
-#define ERTS_LOCK_FLAGS_MASK_PROPERTY (0x0030)
+#define ERTS_LOCK_FLAGS_MASK_PROPERTY (0x0038)
/* Type is a plain number. */
-#define ERTS_LOCK_FLAGS_MASK_TYPE (0x000F)
+#define ERTS_LOCK_FLAGS_MASK_TYPE (0x0007)
#define ERTS_LOCK_FLAGS_TYPE_SPINLOCK (1)
#define ERTS_LOCK_FLAGS_TYPE_MUTEX (2)
#define ERTS_LOCK_FLAGS_TYPE_PROCLOCK (3)
+/* Lock checker use real term order instead of raw word compare */
+#define ERTS_LOCK_FLAGS_PROPERTY_TERM_ORDER (1 << 3)
/* "Static" guarantees that the lock will never be destroyed once created. */
#define ERTS_LOCK_FLAGS_PROPERTY_STATIC (1 << 4)
#define ERTS_LOCK_FLAGS_PROPERTY_READ_WRITE (1 << 5)
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index cba17d3e6a..3d6c9eb43f 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -1505,25 +1505,6 @@ int hashmap_key_hash_cmp(Eterm* ap, Eterm* bp)
return ap ? -1 : 1;
}
-/* maps:new/0 */
-
-BIF_RETTYPE maps_new_0(BIF_ALIST_0) {
- Eterm* hp;
- Eterm tup;
- flatmap_t *mp;
-
- hp = HAlloc(BIF_P, (MAP_HEADER_FLATMAP_SZ + 1));
- tup = make_tuple(hp);
- *hp++ = make_arityval(0);
-
- mp = (flatmap_t*)hp;
- mp->thing_word = MAP_HEADER_FLATMAP;
- mp->size = 0;
- mp->keys = tup;
-
- BIF_RET(make_flatmap(mp));
-}
-
/* maps:put/3 */
BIF_RETTYPE maps_put_3(BIF_ALIST_3) {
@@ -1707,11 +1688,16 @@ int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res)
return 0;
found_key:
- *hp++ = value;
- vs++;
- if (++i < n)
- sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
- *res = make_flatmap(shp);
+ if(*vs == value) {
+ HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp);
+ *res = map;
+ } else {
+ *hp++ = value;
+ vs++;
+ if (++i < n)
+ sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
+ *res = make_flatmap(shp);
+ }
return 1;
}
@@ -1767,9 +1753,7 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
if (is_immed(key)) {
for( i = 0; i < n; i ++) {
if (ks[i] == key) {
- *hp++ = value;
- vs++;
- c = 1;
+ goto found_key;
} else {
*hp++ = *vs++;
}
@@ -1777,18 +1761,13 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
} else {
for( i = 0; i < n; i ++) {
if (EQ(ks[i], key)) {
- *hp++ = value;
- vs++;
- c = 1;
+ goto found_key;
} else {
*hp++ = *vs++;
}
}
}
- if (c)
- return res;
-
/* the map will grow */
if (n >= MAP_SMALL_MAP_LIMIT) {
@@ -1843,6 +1822,18 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) {
*/
*shp = make_pos_bignum_header(0);
return res;
+
+found_key:
+ if(*vs == value) {
+ HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp);
+ return map;
+ } else {
+ *hp++ = value;
+ vs++;
+ if (++i < n)
+ sys_memcpy(hp, vs, (n - i)*sizeof(Eterm));
+ return res;
+ }
}
ASSERT(is_hashmap(map));
diff --git a/erts/emulator/beam/erl_message.c b/erts/emulator/beam/erl_message.c
index 507cc989d2..a3274d7443 100644
--- a/erts/emulator/beam/erl_message.c
+++ b/erts/emulator/beam/erl_message.c
@@ -409,6 +409,11 @@ ErtsMessage* prepend_pending_sig_maybe(Process* sender, Process* receiver,
*
* @brief Send one message from *NOT* a local process.
*
+ * seq_trace does not work with this type of messages
+ * to it is set to am_undefined which means that the
+ * receiving process will not remove the seq_trace token
+ * when it gets this message.
+ *
*/
void
erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks,
@@ -417,11 +422,19 @@ erts_queue_message(Process* receiver, ErtsProcLocks receiver_locks,
ASSERT(is_not_internal_pid(from));
ERL_MESSAGE_TERM(mp) = msg;
ERL_MESSAGE_FROM(mp) = from;
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
queue_messages(receiver, receiver_locks, mp, &mp->next, 1);
}
/**
* @brief Send one message from a local process.
+ *
+ * It is up to the caller of this function to set the
+ * correct seq_trace. The general rule of thumb is that
+ * it should be set to am_undefined if the message
+ * cannot be traced using seq_trace, if it can be
+ * traced it should be set to the trace token. It should
+ * very rarely be explicitly set to NIL!
*/
void
erts_queue_proc_message(Process* sender,
@@ -584,8 +597,7 @@ void
erts_send_message(Process* sender,
Process* receiver,
ErtsProcLocks *receiver_locks,
- Eterm message,
- unsigned flags)
+ Eterm message)
{
Uint msize;
ErtsMessage* mp;
@@ -619,7 +631,7 @@ erts_send_message(Process* sender,
receiver_state = erts_atomic32_read_nob(&receiver->state);
- if (SEQ_TRACE_TOKEN(sender) != NIL && !(flags & ERTS_SND_FLG_NO_SEQ_TRACE)) {
+ if (SEQ_TRACE_TOKEN(sender) != NIL) {
Eterm* hp;
Eterm stoken = SEQ_TRACE_TOKEN(sender);
Uint seq_trace_size = 0;
diff --git a/erts/emulator/beam/erl_message.h b/erts/emulator/beam/erl_message.h
index d120111634..b2550814fd 100644
--- a/erts/emulator/beam/erl_message.h
+++ b/erts/emulator/beam/erl_message.h
@@ -405,8 +405,6 @@ typedef struct erl_trace_message_queue__ {
#define SAVE_MESSAGE(p) \
(p)->sig_qs.save = &(*(p)->sig_qs.save)->next
-#define ERTS_SND_FLG_NO_SEQ_TRACE (((unsigned) 1) << 0)
-
#define ERTS_HEAP_FRAG_SIZE(DATA_WORDS) \
(sizeof(ErlHeapFragment) - sizeof(Eterm) + (DATA_WORDS)*sizeof(Eterm))
@@ -429,7 +427,7 @@ typedef struct erl_trace_message_queue__ {
do { \
(MP)->next = NULL; \
ERL_MESSAGE_TERM(MP) = THE_NON_VALUE; \
- ERL_MESSAGE_TOKEN(MP) = NIL; \
+ ERL_MESSAGE_TOKEN(MP) = THE_NON_VALUE; \
ERL_MESSAGE_FROM(MP) = NIL; \
ERL_MESSAGE_DT_UTAG_INIT(MP); \
MP->data.attached = NULL; \
@@ -446,7 +444,7 @@ void erts_queue_proc_message(Process* from,Process* to, ErtsProcLocks,ErtsMessag
void erts_queue_proc_messages(Process* from, Process* to, ErtsProcLocks,
ErtsMessage*, ErtsMessage**, Uint);
void erts_deliver_exit_message(Eterm, Process*, ErtsProcLocks *, Eterm, Eterm);
-void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm, unsigned);
+void erts_send_message(Process*, Process*, ErtsProcLocks*, Eterm);
void erts_link_mbuf_to_proc(Process *proc, ErlHeapFragment *bp);
Uint erts_msg_attached_data_size_aux(ErtsMessage *msg);
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 0fbf0eb03a..7339aa8874 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -453,8 +453,18 @@ static void full_flush_env(ErlNifEnv* env)
static void full_cache_env(ErlNifEnv* env)
{
- if (env->proc->static_flags & ERTS_STC_FLG_SHADOW_PROC)
+ if (env->proc->static_flags & ERTS_STC_FLG_SHADOW_PROC) {
erts_cache_dirty_shadow_proc(env->proc);
+ /*
+ * If shadow proc had heap fragments when flushed
+ * those have now been moved to the real proc.
+ * Ensure heap pointers do not point into a heap
+ * fragment on real proc...
+ */
+ ASSERT(!env->proc->mbuf);
+ env->hp_end = HEAP_LIMIT(env->proc);
+ env->hp = HEAP_TOP(env->proc);
+ }
cache_env(env);
}
@@ -744,8 +754,58 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
rp_locks = ERTS_PROC_LOCK_MAIN;
if (menv) {
+ Eterm token = c_p ? SEQ_TRACE_TOKEN(c_p) : am_undefined;
+ if (token != NIL && token != am_undefined) {
+ /* This code is copied from erts_send_message */
+ Eterm stoken = SEQ_TRACE_TOKEN(c_p);
+#ifdef USE_VM_PROBES
+ DTRACE_CHARBUF(sender_name, 64);
+ DTRACE_CHARBUF(receiver_name, 64);
+ Sint tok_label = 0;
+ Sint tok_lastcnt = 0;
+ Sint tok_serial = 0;
+ Eterm utag = NIL;
+ *sender_name = *receiver_name = '\0';
+ if (DTRACE_ENABLED(message_send)) {
+ erts_snprintf(sender_name, sizeof(DTRACE_CHARBUF_NAME(sender_name)),
+ "%T", c_p->common.id);
+ erts_snprintf(receiver_name, sizeof(DTRACE_CHARBUF_NAME(receiver_name)),
+ "%T", rp->common.id);
+ }
+#endif
+ if (have_seqtrace(stoken)) {
+ seq_trace_update_send(c_p);
+ seq_trace_output(stoken, msg, SEQ_TRACE_SEND,
+ rp->common.id, c_p);
+ }
+#ifdef USE_VM_PROBES
+ if (!(DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING)) {
+ stoken = NIL;
+ }
+#endif
+ token = enif_make_copy(msg_env, stoken);
+
+#ifdef USE_VM_PROBES
+ if (DT_UTAG_FLAGS(c_p) & DT_UTAG_SPREADING) {
+ if (is_immed(DT_UTAG(c_p)))
+ utag = DT_UTAG(c_p);
+ else
+ utag = enif_make_copy(msg_env, DT_UTAG(c_p));
+ }
+ if (DTRACE_ENABLED(message_send)) {
+ if (have_seqtrace(stoken)) {
+ tok_label = SEQ_TRACE_T_DTRACE_LABEL(stoken);
+ tok_lastcnt = signed_val(SEQ_TRACE_T_LASTCNT(stoken));
+ tok_serial = signed_val(SEQ_TRACE_T_SERIAL(stoken));
+ }
+ DTRACE6(message_send, sender_name, receiver_name,
+ size_object(msg), tok_label, tok_lastcnt, tok_serial);
+ }
+#endif
+ }
flush_env(msg_env);
mp = erts_alloc_message(0, NULL);
+ ERL_MESSAGE_TOKEN(mp) = token;
mp->data.heap_frag = menv->env.heap_frag;
ASSERT(mp->data.heap_frag == MBUF(&menv->phony_proc));
if (mp->data.heap_frag != NULL) {
@@ -783,6 +843,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
ohp = &bp->off_heap;
}
}
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
msg = copy_struct_litopt(msg, sz, &hp, ohp, &litarea);
}
@@ -826,6 +887,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid,
ERL_MESSAGE_TERM(mp) = msg;
ERL_MESSAGE_FROM(mp) = from;
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (!msgq) {
msgq = erts_alloc(ERTS_ALC_T_TRACE_MSG_QUEUE,
@@ -978,7 +1040,7 @@ ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
Eterm* hp;
/*
* No preserved sharing allowed as long as literals are also preserved.
- * Process independent environment can not be reached by purge.
+ * Process independent environment cannot be reached by purge.
*/
sz = size_object(src_term);
hp = alloc_heap(dst_env, sz);
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 1f147011a8..f4dc60941a 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -60,6 +60,10 @@ static int references_atoms_need_init = 1;
static ErtsMonotonicTime orig_node_tab_delete_delay;
static ErtsMonotonicTime node_tab_delete_delay;
+
+static void report_gc_active_dist_entry(Eterm sysname, enum dist_entry_state);
+
+
/* -- The distribution table ---------------------------------------------- */
#define ErtsBin2DistEntry(B) \
@@ -366,31 +370,43 @@ DistEntry *erts_find_dist_entry(Eterm sysname)
}
DistEntry *
-erts_dhandle_to_dist_entry(Eterm dhandle)
+erts_dhandle_to_dist_entry(Eterm dhandle, Uint32 *conn_id)
{
+ Eterm *tpl;
Binary *bin;
- if (!is_internal_magic_ref(dhandle))
+
+ if (!is_boxed(dhandle))
+ return NULL;
+ tpl = boxed_val(dhandle);
+ if (tpl[0] != make_arityval(2) || !is_small(tpl[1])
+ || !is_internal_magic_ref(tpl[2]))
return NULL;
- bin = erts_magic_ref2bin(dhandle);
+ *conn_id = unsigned_val(tpl[1]);
+ bin = erts_magic_ref2bin(tpl[2]);
if (ERTS_MAGIC_BIN_DESTRUCTOR(bin) != erts_dist_entry_destructor)
return NULL;
return ErtsBin2DistEntry(bin);
}
Eterm
-erts_build_dhandle(Eterm **hpp, ErlOffHeap* ohp, DistEntry *dep)
+erts_build_dhandle(Eterm **hpp, ErlOffHeap* ohp,
+ DistEntry *dep, Uint32 conn_id)
{
Binary *bin = ErtsDistEntry2Bin(dep);
+ Eterm mref, dhandle;
ASSERT(bin);
ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(bin) == erts_dist_entry_destructor);
- return erts_mk_magic_ref(hpp, ohp, bin);
+ mref = erts_mk_magic_ref(hpp, ohp, bin);
+ dhandle = TUPLE2(*hpp, make_small(conn_id), mref);
+ *hpp += 3;
+ return dhandle;
}
Eterm
-erts_make_dhandle(Process *c_p, DistEntry *dep)
+erts_make_dhandle(Process *c_p, DistEntry *dep, Uint32 conn_id)
{
- Eterm *hp = HAlloc(c_p, ERTS_MAGIC_REF_THING_SIZE);
- return erts_build_dhandle(&hp, &c_p->off_heap, dep);
+ Eterm *hp = HAlloc(c_p, ERTS_DHANDLE_SIZE);
+ return erts_build_dhandle(&hp, &c_p->off_heap, dep, conn_id);
}
static void start_timer_delete_dist_entry(void *vdep);
@@ -451,6 +467,19 @@ static void try_delete_dist_entry(DistEntry* dep)
{
erts_aint_t refc;
+ erts_de_rwlock(dep);
+ if (dep->state != ERTS_DE_STATE_IDLE && de_refc_read(dep,0) == 0) {
+ Eterm sysname = dep->sysname;
+ enum dist_entry_state state = dep->state;
+
+ if (dep->state != ERTS_DE_STATE_PENDING)
+ ERTS_INTERNAL_ERROR("Garbage collecting connected distribution entry");
+ erts_abort_connection_rwunlock(dep);
+ report_gc_active_dist_entry(sysname, state);
+ }
+ else
+ erts_de_rwunlock(dep);
+
erts_rwmtx_rwlock(&erts_dist_table_rwmtx);
/*
* Another thread might have looked up this dist entry after
@@ -477,6 +506,34 @@ static void try_delete_dist_entry(DistEntry* dep)
}
}
+static void report_gc_active_dist_entry(Eterm sysname,
+ enum dist_entry_state state)
+{
+ char *state_str;
+ erts_dsprintf_buf_t *dsbuf = erts_create_logger_dsbuf();
+ switch (state) {
+ case ERTS_DE_STATE_CONNECTED:
+ state_str = "connected";
+ break;
+ case ERTS_DE_STATE_PENDING:
+ state_str = "pending connect";
+ break;
+ case ERTS_DE_STATE_EXITING:
+ state_str = "exiting";
+ break;
+ case ERTS_DE_STATE_IDLE:
+ state_str = "idle";
+ break;
+ default:
+ state_str = "unknown";
+ break;
+ }
+ erts_dsprintf(dsbuf, "Garbage collecting distribution "
+ "entry for node %T in state: %s",
+ sysname, state_str);
+ erts_send_error_to_logger_nogl(dsbuf);
+}
+
int erts_dist_entry_destructor(Binary *bin)
{
DistEntry *dep = ErtsBin2DistEntry(bin);
@@ -582,7 +639,7 @@ erts_set_dist_entry_not_connected(DistEntry *dep)
if(dep->next)
dep->next->prev = dep->prev;
- dep->state = ERTS_DE_STATE_EXITING;
+ dep->state = ERTS_DE_STATE_IDLE;
dep->flags = 0;
dep->prev = NULL;
dep->cid = NIL;
@@ -1863,8 +1920,9 @@ setup_reference_table(void)
if (ohp)
insert_offheap(ohp, HEAP_REF, prt->common.id);
/* Insert controller */
- if (prt->dist_entry)
- insert_dist_entry(prt->dist_entry,
+ dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
+ if (dep)
+ insert_dist_entry(dep,
CTRL_REF,
prt->common.id,
0);
diff --git a/erts/emulator/beam/erl_node_tables.h b/erts/emulator/beam/erl_node_tables.h
index 9a792b10b1..c44f1f8991 100644
--- a/erts/emulator/beam/erl_node_tables.h
+++ b/erts/emulator/beam/erl_node_tables.h
@@ -214,9 +214,10 @@ int erts_lc_is_de_rwlocked(DistEntry *);
int erts_lc_is_de_rlocked(DistEntry *);
#endif
int erts_dist_entry_destructor(Binary *bin);
-DistEntry *erts_dhandle_to_dist_entry(Eterm dhandle);
-Eterm erts_build_dhandle(Eterm **hpp, ErlOffHeap*, DistEntry*);
-Eterm erts_make_dhandle(Process *c_p, DistEntry *dep);
+DistEntry *erts_dhandle_to_dist_entry(Eterm dhandle, Uint32* connection_id);
+#define ERTS_DHANDLE_SIZE (3+ERTS_MAGIC_REF_THING_SIZE)
+Eterm erts_build_dhandle(Eterm **hpp, ErlOffHeap*, DistEntry*, Uint32 conn_id);
+Eterm erts_make_dhandle(Process *c_p, DistEntry*, Uint32 conn_id);
ERTS_GLB_INLINE void erts_deref_node_entry(ErlNode *np);
ERTS_GLB_INLINE void erts_de_rlock(DistEntry *dep);
diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h
index 9b52b648e5..2be0a5bf74 100644
--- a/erts/emulator/beam/erl_port.h
+++ b/erts/emulator/beam/erl_port.h
@@ -112,8 +112,10 @@ typedef struct line_buf { /* Buffer used in line oriented I/O */
*/
#define ERTS_PRTSD_SCHED_ID 0
+#define ERTS_PRTSD_DIST_ENTRY 1
+#define ERTS_PRTSD_CONN_ID 2
-#define ERTS_PRTSD_SIZE 1
+#define ERTS_PRTSD_SIZE 3
typedef struct {
void *data[ERTS_PRTSD_SIZE];
@@ -154,7 +156,6 @@ struct _erl_drv_port {
Uint bytes_out; /* Number of bytes written */
ErlPortIOQueue ioq; /* driver accessible i/o queue */
- DistEntry *dist_entry; /* Dist entry used in DISTRIBUTION */
char *name; /* String used in the open */
erts_driver_t* drv_ptr;
UWord drv_data;
@@ -257,6 +258,8 @@ ERTS_GLB_INLINE void *
erts_prtsd_get(Port *prt, int ix)
{
ErtsPrtSD *psd = (ErtsPrtSD *) erts_atomic_read_nob(&prt->psd);
+
+ ASSERT((unsigned)ix < ERTS_PRTSD_SIZE);
if (!psd)
return NULL;
ERTS_THR_DATA_DEPENDENCY_READ_MEMORY_BARRIER;
@@ -272,6 +275,7 @@ erts_prtsd_set(Port *prt, int ix, void *data)
psd = (ErtsPrtSD *) erts_atomic_read_nob(&prt->psd);
+ ASSERT((unsigned)ix < ERTS_PRTSD_SIZE);
if (psd) {
#ifdef ETHR_ORDERED_READ_DEPEND
ETHR_MEMBAR(ETHR_LoadStore|ETHR_StoreStore);
@@ -459,7 +463,7 @@ erts_port_unlock(Port *prt)
ERTS_INVALID_PORT_OPT((PP), (ID), ERTS_PORT_SFLGS_INVALID_TRACER_LOOKUP)
#define ERTS_PORT_SCHED_ID(P, ID) \
- ((Uint) (UWord) erts_prtsd_set((P), ERTS_PSD_SCHED_ID, (void *) (UWord) (ID)))
+ ((Uint) (UWord) erts_prtsd_set((P), ERTS_PRTSD_SCHED_ID, (void *) (UWord) (ID)))
extern const Port erts_invalid_port;
#define ERTS_PORT_LOCK_BUSY ((Port *) &erts_invalid_port)
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index d6d22677e7..f343e984f7 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -52,8 +52,8 @@
#define ERTS_SIG_Q_OP_MAX 13
-#define ERTS_SIG_Q_OP_EXIT 0
-#define ERTS_SIG_Q_OP_EXIT_LINKED 1
+#define ERTS_SIG_Q_OP_EXIT 0 /* Exit signal due to bif call */
+#define ERTS_SIG_Q_OP_EXIT_LINKED 1 /* Exit signal due to link break*/
#define ERTS_SIG_Q_OP_MONITOR_DOWN 2
#define ERTS_SIG_Q_OP_MONITOR 3
#define ERTS_SIG_Q_OP_DEMONITOR 4
@@ -1167,10 +1167,7 @@ erts_proc_sig_send_persistent_monitor_msg(Uint16 type, Eterm key,
ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_PERSISTENT_MON_MSG,
type, 0);
ERL_MESSAGE_FROM(mp) = from;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (!proc_queue_signal(NULL, to, (ErtsSignal *) mp,
ERTS_SIG_Q_OP_PERSISTENT_MON_MSG)) {
@@ -1564,11 +1561,6 @@ erts_proc_sig_send_is_alive_request(Process *c_p, Eterm to, Eterm ref)
ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_IS_ALIVE,
ERTS_SIG_Q_TYPE_UNDEFINED,
0);
- ERL_MESSAGE_TOKEN(mp) = NIL;
- ERL_MESSAGE_FROM(mp) = am_system;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_IS_ALIVE))
(void) maybe_elevate_sig_handling_prio(c_p, to);
@@ -1672,11 +1664,6 @@ erts_proc_sig_send_sync_suspend(Process *c_p, Eterm to, Eterm tag, Eterm reply)
ERL_MESSAGE_TERM(mp) = ERTS_PROC_SIG_MAKE_TAG(ERTS_SIG_Q_OP_SYNC_SUSPEND,
ERTS_SIG_Q_TYPE_UNDEFINED,
0);
- ERL_MESSAGE_TOKEN(mp) = NIL;
- ERL_MESSAGE_FROM(mp) = am_system;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
if (proc_queue_signal(c_p, to, (ErtsSignal *) mp, ERTS_SIG_Q_OP_SYNC_SUSPEND))
(void) maybe_elevate_sig_handling_prio(c_p, to);
@@ -1790,7 +1777,7 @@ handle_rpc(Process *c_p, ErtsProcSigRPC *rpc, int cnt, int limit, int *yieldp)
msg = TUPLE2(hp, ref, res);
mp->hfrag.next = bp;
-
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, 0, mp, msg);
}
@@ -2155,10 +2142,7 @@ handle_exit_signal(Process *c_p, ErtsSigRecvTracing *tracing,
pid = STORE_NC(&hp, ohp, from);
ERL_MESSAGE_TERM(mp) = TUPLE3(hp, am_EXIT, pid, reason);
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
if (is_immed(pid))
ERL_MESSAGE_FROM(mp) = pid;
else {
@@ -2346,10 +2330,7 @@ convert_to_down_message(Process *c_p,
type, from, reason);
hp += 6;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
/* Replace original signal with the exit message... */
convert_to_msg(c_p, sig, mp, next_nm_sig);
@@ -2397,10 +2378,7 @@ convert_to_nodedown_messages(Process *c_p,
ERL_MESSAGE_TERM(mp) = TUPLE2(hp, am_nodedown, node);
ERL_MESSAGE_FROM(mp) = am_system;
- ERL_MESSAGE_TOKEN(mp) = NIL;
-#ifdef USE_VM_PROBES
- ERL_MESSAGE_DT_UTAG(mp) = NIL;
-#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
mp->next = nd_first;
nd_first = mp;
if (!nd_last)
@@ -2830,6 +2808,7 @@ handle_process_info(Process *c_p, ErtsSigRecvTracing *tracing,
if (is_alive)
erts_factory_trim_and_close(&hfact, &msg, 1);
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, locks, mp, msg);
if (!is_alive && locks)
@@ -2931,6 +2910,7 @@ sync_suspend_reply(Process *c_p, ErtsMessage *mp, erts_aint32_t state)
tp[2] = ssusp->async ? am_not_suspended : am_internal_error;
}
}
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, 0, mp, ssusp->message);
}
}
@@ -3146,8 +3126,8 @@ erts_proc_sig_handle_incoming(Process *c_p, erts_aint32_t *statep,
erts_monitor_tree_delete(&ERTS_P_MONITORS(c_p),
&mdp->origin);
omon = &mdp->origin;
+ remove_nm_sig(c_p, sig, next_nm_sig);
}
- remove_nm_sig(c_p, sig, next_nm_sig);
break;
default:
ERTS_INTERNAL_ERROR("invalid monitor type");
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 8784eb5a63..a21acb9a57 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -4022,9 +4022,7 @@ schedule_bound_processes(ErtsRunQueue *rq,
static ERTS_INLINE void
clear_proc_dirty_queue_bit(Process *p, ErtsRunQueue *rq, int prio_bit)
{
-#ifdef DEBUG
erts_aint32_t old;
-#endif
erts_aint32_t qb = prio_bit;
if (rq == ERTS_DIRTY_CPU_RUNQ)
qb <<= ERTS_PDSFLGS_IN_CPU_PRQ_MASK_OFFSET;
@@ -4032,13 +4030,8 @@ clear_proc_dirty_queue_bit(Process *p, ErtsRunQueue *rq, int prio_bit)
ASSERT(rq == ERTS_DIRTY_IO_RUNQ);
qb <<= ERTS_PDSFLGS_IN_IO_PRQ_MASK_OFFSET;
}
-#ifdef DEBUG
- old = (int)
-#else
- (void)
-#endif
- erts_atomic32_read_band_mb(&p->dirty_state, ~qb);
- ASSERT(old & qb);
+ old = (int) erts_atomic32_read_band_mb(&p->dirty_state, ~qb);
+ ASSERT(old & qb); (void)old;
}
@@ -7175,9 +7168,7 @@ msb_scheduler_type_switch(ErtsSchedType sched_type,
Uint32 nrml_prio, dcpu_prio, dio_prio;
ErtsSchedType exec_type;
ErtsRunQueue *exec_rq;
-#ifdef DEBUG
erts_aint32_t dbg_val;
-#endif
ASSERT(schdlr_sspnd.msb.ongoing);
@@ -7292,16 +7283,12 @@ msb_scheduler_type_switch(ErtsSchedType sched_type,
* Suspend this scheduler and wake up scheduler
* number one of another type...
*/
-#ifdef DEBUG
dbg_val =
-#else
- (void)
-#endif
erts_atomic32_read_bset_mb(&esdp->ssi->flags,
(ERTS_SSI_FLG_SUSPENDED
| ERTS_SSI_FLG_MSB_EXEC),
ERTS_SSI_FLG_SUSPENDED);
- ASSERT(dbg_val & ERTS_SSI_FLG_MSB_EXEC);
+ ASSERT(dbg_val & ERTS_SSI_FLG_MSB_EXEC); (void)dbg_val;
switch (exec_type) {
case ERTS_SCHED_NORMAL:
@@ -7319,11 +7306,7 @@ msb_scheduler_type_switch(ErtsSchedType sched_type,
break;
}
-#ifdef DEBUG
dbg_val =
-#else
- (void)
-#endif
erts_atomic32_read_bset_mb(&exec_rq->scheduler->ssi->flags,
(ERTS_SSI_FLG_SUSPENDED
| ERTS_SSI_FLG_MSB_EXEC),
@@ -8888,11 +8871,8 @@ erts_suspend(Process* c_p, ErtsProcLocks c_p_locks, Port *busy_port)
suspend = 1;
if (suspend) {
-#ifdef DEBUG
- int res =
-#endif
- suspend_process(c_p, c_p);
- ASSERT(res);
+ int res = suspend_process(c_p, c_p);
+ ASSERT(res); (void)res;
}
if (!(c_p_locks & ERTS_PROC_LOCK_STATUS))
@@ -9079,6 +9059,9 @@ unlock_lock_rq(int pre_free, void *vrq)
}
+static void trace_schedule_in(Process *p, erts_aint32_t state);
+static void trace_schedule_out(Process *p, erts_aint32_t state);
+
/*
* schedule() is called from BEAM (process_main()) or HiPE
* (hipe_mode_switch()) when the current process is to be
@@ -9184,22 +9167,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
state = erts_atomic32_read_nob(&p->state);
- if (IS_TRACED(p)) {
- if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE))
- erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
- if ((state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) == ERTS_PSFLG_EXITING) {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
- trace_sched(p, ERTS_PROC_LOCK_MAIN,
- ((state & ERTS_PSFLG_FREE)
- ? am_out_exited
- : am_out_exiting));
- }
- else {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
- ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
- trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
- }
- }
+ if (IS_TRACED(p))
+ trace_schedule_out(p, state);
erts_proc_lock(p, ERTS_PROC_LOCK_STATUS|ERTS_PROC_LOCK_TRACE);
@@ -9610,6 +9579,8 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
/* Migrate to dirty scheduler... */
sunlock_sched_out_proc:
erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
+ if (IS_TRACED(p))
+ trace_schedule_in(p, state);
goto sched_out_proc;
}
}
@@ -9643,29 +9614,14 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
erts_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
- /* Clear tracer if it has been removed */
- if (IS_TRACED(p) && erts_is_tracer_proc_enabled(
- p, ERTS_PROC_LOCK_MAIN, &p->common)) {
-
- if (state & ERTS_PSFLG_EXITING) {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
- trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in_exiting);
- }
- else {
- if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
- ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
- trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
- }
- if (IS_TRACED_FL(p, F_TRACE_CALLS)) {
- erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN);
- }
- }
+ if (IS_TRACED(p))
+ trace_schedule_in(p, state);
if (is_normal_sched) {
if (state & ERTS_PSFLG_RUNNING_SYS) {
if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) {
int local_only = (!!(p->flags & F_LOCAL_SIGS_ONLY)
- & !(state & ERTS_PSFLG_SUSPENDED));
+ & !(state & (ERTS_PSFLG_SUSPENDED|ERTS_PSFLGS_DIRTY_WORK)));
if (!local_only | !!(state & ERTS_PSFLG_SIG_Q)) {
int sig_reds;
/*
@@ -9823,6 +9779,53 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
}
+static void
+trace_schedule_in(Process *p, erts_aint32_t state)
+{
+ ASSERT(IS_TRACED(p));
+ ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(p) == ERTS_PROC_LOCK_MAIN);
+
+ /* Clear tracer if it has been removed */
+ if (erts_is_tracer_proc_enabled(p, ERTS_PROC_LOCK_MAIN, &p->common)) {
+
+ if (state & ERTS_PSFLG_EXITING) {
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in_exiting);
+ }
+ else {
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
+ ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_in);
+ }
+ if (IS_TRACED_FL(p, F_TRACE_CALLS))
+ erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN);
+ }
+
+}
+
+static void
+trace_schedule_out(Process *p, erts_aint32_t state)
+{
+ ASSERT(IS_TRACED(p));
+ ERTS_LC_ASSERT(erts_proc_lc_my_proc_locks(p) == ERTS_PROC_LOCK_MAIN);
+
+ if (IS_TRACED_FL(p, F_TRACE_CALLS) && !(state & ERTS_PSFLG_FREE))
+ erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
+
+ if ((state & (ERTS_PSFLG_FREE|ERTS_PSFLG_EXITING)) == ERTS_PSFLG_EXITING) {
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN,
+ ((state & ERTS_PSFLG_FREE)
+ ? am_out_exited
+ : am_out_exiting));
+ }
+ else {
+ if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED) ||
+ ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
+ trace_sched(p, ERTS_PROC_LOCK_MAIN, am_out);
+ }
+}
+
static int
notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st,
Eterm st_result, int normal_sched)
@@ -9874,6 +9877,7 @@ notify_sys_task_executed(Process *c_p, ErtsProcSysTask *st,
ASSERT(hp_start + hsz == hp);
#endif
+ ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_proc_message(c_p, rp, rp_locks, mp, msg);
if (c_p == rp)
@@ -12466,9 +12470,7 @@ erts_continue_exit_process(Process *p)
yield:
-#ifdef DEBUG
ASSERT(yield_allowed);
-#endif
ERTS_LC_ASSERT(curr_locks == erts_proc_lc_my_proc_locks(p));
ERTS_LC_ASSERT(ERTS_PROC_LOCK_MAIN & curr_locks);
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index 243db4c734..706530023b 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -963,12 +963,16 @@ dump_module_literals(fmtfn_t to, void *to_arg, ErtsLiteralArea* lit_area)
}
erts_putc(to, to_arg, '\n');
}
- } else if (is_export_header(w)) {
+ } else if (is_export_header(w) || is_fun_header(w)) {
dump_externally(to, to_arg, term);
erts_putc(to, to_arg, '\n');
}
size = 1 + header_arity(w);
switch (w & _HEADER_SUBTAG_MASK) {
+ case FUN_SUBTAG:
+ ASSERT(((ErlFunThing*)(htop))->num_free == 0);
+ size += 1;
+ break;
case MAP_SUBTAG:
if (is_flatmap_header(w)) {
size += 1 + flatmap_get_size(htop);
diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c
index d225916ac5..1d6869a7cd 100644
--- a/erts/emulator/beam/erl_unicode.c
+++ b/erts/emulator/beam/erl_unicode.c
@@ -1358,11 +1358,9 @@ Uint erts_atom_to_string_length(Eterm atom)
else {
byte* err_pos;
Uint num_chars;
-#ifdef DEBUG
int ares =
-#endif
erts_analyze_utf8(ap->name, ap->len, &err_pos, &num_chars, NULL);
- ASSERT(ares == ERTS_UTF8_OK);
+ ASSERT(ares == ERTS_UTF8_OK); (void)ares;
return num_chars;
}
diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c
index 904993ceb6..621ba108ba 100644
--- a/erts/emulator/beam/external.c
+++ b/erts/emulator/beam/external.c
@@ -671,30 +671,37 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
byte *ext,
Uint size,
DistEntry *dep,
- ErtsAtomCache *cache,
- Uint32 *connection_id)
+ Uint32 conn_id,
+ ErtsAtomCache *cache)
{
-#undef ERTS_EXT_FAIL
-#undef ERTS_EXT_HDR_FAIL
-#if 1
-#define ERTS_EXT_FAIL goto fail
-#define ERTS_EXT_HDR_FAIL goto bad_hdr
-#else
-#define ERTS_EXT_FAIL abort()
-#define ERTS_EXT_HDR_FAIL abort()
-#endif
+ register byte *ep;
+
+ edep->heap_size = -1;
+ edep->flags = 0;
+ edep->dep = dep;
+
+ ASSERT(dep);
+ erts_de_rlock(dep);
- register byte *ep = ext;
ASSERT(dep->flags & DFLAG_UTF8_ATOMS);
- edep->heap_size = -1;
- edep->ext_endp = ext+size;
+ if ((dep->state != ERTS_DE_STATE_CONNECTED &&
+ dep->state != ERTS_DE_STATE_PENDING)
+ || dep->connection_id != conn_id) {
+ erts_de_runlock(dep);
+ return ERTS_PREP_DIST_EXT_CLOSED;
+ }
- if (size < 2)
- ERTS_EXT_FAIL;
+ if (!(dep->flags & DFLAG_DIST_HDR_ATOM_CACHE)) {
+ /* Skip PASS_THROUGH */
+ ext++;
+ size--;
+ }
+ edep->ext_endp = ext + size;
+ ep = ext;
- if (!dep)
- ERTS_INTERNAL_ERROR("Invalid use");
+ if (size < 2)
+ goto fail;
if (ep[0] != VERSION_MAGIC) {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
@@ -703,28 +710,17 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
"channel %d\n",
dist_entry_channel_no(dep));
erts_send_error_to_logger_nogl(dsbufp);
- ERTS_EXT_FAIL;
+ goto fail;
}
- edep->flags = 0;
- edep->dep = dep;
-
- erts_de_rlock(dep);
-
- if (dep->state != ERTS_DE_STATE_CONNECTED &&
- dep->state != ERTS_DE_STATE_PENDING) {
- erts_de_runlock(dep);
- return ERTS_PREP_DIST_EXT_CLOSED;
- }
if (dep->flags & DFLAG_DIST_HDR_ATOM_CACHE)
edep->flags |= ERTS_DIST_EXT_DFLAG_HDR;
- *connection_id = dep->connection_id;
edep->connection_id = dep->connection_id;
if (ep[1] != DIST_HEADER) {
if (edep->flags & ERTS_DIST_EXT_DFLAG_HDR)
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
edep->attab.size = 0;
edep->extp = ext;
}
@@ -733,17 +729,17 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
int no_atoms;
if (!(edep->flags & ERTS_DIST_EXT_DFLAG_HDR))
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
#undef CHKSIZE
#define CHKSIZE(SZ) \
- do { if ((SZ) > edep->ext_endp - ep) ERTS_EXT_HDR_FAIL; } while(0)
+ do { if ((SZ) > edep->ext_endp - ep) goto bad_hdr; } while(0)
CHKSIZE(1+1+1);
ep += 2;
no_atoms = (int) get_int8(ep);
if (no_atoms < 0 || ERTS_ATOM_CACHE_SIZE < no_atoms)
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
ep++;
if (no_atoms) {
int long_atoms = 0;
@@ -821,18 +817,18 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
/* atom already cached */
cix += (int) get_int8(ep);
if (cix >= ERTS_ATOM_CACHE_SIZE)
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
ep++;
atom = cache->in_arr[cix];
if (!is_atom(atom))
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
edep->attab.atom[tix] = atom;
}
else {
/* new cached atom */
cix += (int) get_int8(ep);
if (cix >= ERTS_ATOM_CACHE_SIZE)
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
ep++;
if (long_atoms) {
CHKSIZE(2);
@@ -850,7 +846,7 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
ERTS_ATOM_ENC_UTF8,
0);
if (is_non_value(atom))
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
ep += len;
cache->in_arr[cix] = atom;
edep->attab.atom[tix] = atom;
@@ -870,12 +866,12 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
edep->extp = ep;
#ifdef ERTS_DEBUG_USE_DIST_SEP
if (*ep != VERSION_MAGIC)
- ERTS_EXT_HDR_FAIL;
+ goto bad_hdr;
#endif
}
#ifdef ERTS_DEBUG_USE_DIST_SEP
if (*ep != VERSION_MAGIC)
- ERTS_EXT_FAIL;
+ goto fail;
#endif
erts_de_runlock(dep);
@@ -883,8 +879,6 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
return ERTS_PREP_DIST_EXT_SUCCESS;
#undef CHKSIZE
-#undef ERTS_EXT_FAIL
-#undef ERTS_EXT_HDR_FAIL
bad_hdr: {
erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
@@ -901,7 +895,7 @@ erts_prepare_dist_ext(ErtsDistExternal *edep,
}
fail: {
erts_de_runlock(dep);
- erts_kill_dist_connection(dep, *connection_id);
+ erts_kill_dist_connection(dep, conn_id);
}
return ERTS_PREP_DIST_EXT_FAILED;
}
diff --git a/erts/emulator/beam/external.h b/erts/emulator/beam/external.h
index bbd9b4bad2..edac177cc6 100644
--- a/erts/emulator/beam/external.h
+++ b/erts/emulator/beam/external.h
@@ -182,7 +182,7 @@ void erts_destroy_dist_ext_copy(ErtsDistExternal *);
#define ERTS_PREP_DIST_EXT_CLOSED (1)
int erts_prepare_dist_ext(ErtsDistExternal *, byte *, Uint,
- DistEntry *, ErtsAtomCache *, Uint32 *);
+ DistEntry *, Uint32 conn_id, ErtsAtomCache *);
Sint erts_decode_dist_ext_size(ErtsDistExternal *);
Eterm erts_decode_dist_ext(ErtsHeapFactory* factory, ErtsDistExternal *);
diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h
index 2cf268162d..187d2635ea 100644
--- a/erts/emulator/beam/global.h
+++ b/erts/emulator/beam/global.h
@@ -292,7 +292,6 @@ union erl_off_heap_ptr {
/* controls warning mapping in error_logger */
extern Eterm node_cookie;
-extern Uint display_items; /* no of items to display in traces etc */
extern int erts_backtrace_depth;
extern erts_atomic32_t erts_max_gen_gcs;
@@ -1083,7 +1082,7 @@ extern int erts_do_net_exits(DistEntry*, Eterm);
extern int distribution_info(fmtfn_t, void *);
extern int is_node_name_atom(Eterm a);
-extern int erts_net_message(Port *, DistEntry *,
+extern int erts_net_message(Port *, DistEntry *, Uint32 conn_id,
byte *, ErlDrvSizeT, byte *, ErlDrvSizeT);
extern void init_dist(void);
diff --git a/erts/emulator/beam/instrs.tab b/erts/emulator/beam/instrs.tab
index 42c1168f85..da1dd3dc45 100644
--- a/erts/emulator/beam/instrs.tab
+++ b/erts/emulator/beam/instrs.tab
@@ -559,17 +559,19 @@ update_list(Hd, Dst) {
HTOP += 2;
}
-i_put_tuple := i_put_tuple.make.fill;
-
-i_put_tuple.make(Dst) {
- $Dst = make_tuple(HTOP);
-}
-
-i_put_tuple.fill(Arity) {
+put_tuple2(Dst, Arity) {
Eterm* hp = HTOP;
Eterm arity = $Arity;
+ /*
+ * If operands are not packed (in the 32-bit VM),
+ * is is not safe to use $Dst directly after I
+ * has been updated.
+ */
+ Eterm* dst_ptr = &($Dst);
+
//| -no_next
+ ASSERT(arity != 0);
*hp++ = make_arityval(arity);
I = $NEXT_INSTRUCTION;
do {
@@ -586,6 +588,7 @@ i_put_tuple.fill(Arity) {
break;
}
} while (--arity != 0);
+ *dst_ptr = make_tuple(HTOP);
HTOP = hp;
ASSERT(VALID_INSTR(* (Eterm *)I));
Goto(*I);
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 2446b3c074..5325480901 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -375,7 +375,6 @@ static Port *create_port(char *name,
prt->control_flags = 0;
prt->bytes_in = 0;
prt->bytes_out = 0;
- prt->dist_entry = NULL;
ERTS_PORT_INIT_CONNECTED(prt, pid);
prt->common.u.alive.reg = NULL;
ERTS_PTMR_INIT(prt);
@@ -3287,7 +3286,6 @@ static void deliver_read_message(Port* prt, erts_aint32_t state, Eterm to,
if (trace_send)
trace_port_send(prt, to, tuple, 1);
- ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
if (rp_locks)
erts_proc_unlock(rp, rp_locks);
@@ -3459,7 +3457,6 @@ deliver_vec_message(Port* prt, /* Port */
if (IS_TRACED_FL(prt, F_TRACE_SEND))
trace_port_send(prt, to, tuple, 1);
- ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
erts_proc_unlock(rp, rp_locks);
if (!scheduler)
@@ -3615,12 +3612,12 @@ terminate_port(Port *prt)
erts_cleanup_port_data(prt);
+ ASSERT(erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY) == NULL);
+
psd = (ErtsPrtSD *) erts_atomic_read_nob(&prt->psd);
if (psd)
erts_free(ERTS_ALC_T_PRTSD, psd);
- ASSERT(prt->dist_entry == NULL);
-
kill_port(prt);
/*
@@ -3761,10 +3758,12 @@ erts_deliver_port_exit(Port *prt, Eterm from, Eterm reason, int send_closed,
DRV_MONITOR_UNLOCK_PDL(prt);
}
- if ((state & ERTS_PORT_SFLG_DISTRIBUTION) && prt->dist_entry) {
- erts_do_net_exits(prt->dist_entry, modified_reason);
- erts_deref_dist_entry(prt->dist_entry);
- prt->dist_entry = NULL;
+ if (state & ERTS_PORT_SFLG_DISTRIBUTION) {
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
+ ASSERT(dep);
+ erts_do_net_exits(dep, modified_reason);
+ erts_deref_dist_entry(dep);
+ erts_prtsd_set(prt, ERTS_PRTSD_DIST_ENTRY, NULL);
erts_atomic32_read_band_relb(&prt->state,
~ERTS_PORT_SFLG_DISTRIBUTION);
}
@@ -5052,7 +5051,7 @@ set_busy_port(ErlDrvPort dprt, int on)
DTRACE1(port_not_busy, port_str);
}
#endif
- if (prt->dist_entry) {
+ if (erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY) != NULL) {
/*
* Processes suspended on distribution ports are
* normally queued on the dist entry.
@@ -5382,7 +5381,6 @@ void driver_report_exit(ErlDrvPort ix, int status)
if (IS_TRACED_FL(prt, F_TRACE_SEND))
trace_port_send(prt, pid, tuple, 1);
- ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_message(rp, rp_locks, mp, tuple, prt->common.id);
erts_proc_unlock(rp, rp_locks);
@@ -5988,8 +5986,6 @@ driver_deliver_term(Port *prt, Eterm to, ErlDrvTermData* data, int len)
from = prt->common.id;
}
- /* send message */
- ERL_MESSAGE_TOKEN(factory.message) = am_undefined;
erts_queue_message(rp, rp_locks, factory.message, mess, from);
}
else if (res == -2) {
@@ -6174,9 +6170,12 @@ int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
else
erts_atomic64_add_nob(&bytes_in, (erts_aint64_t) (hlen + len));
if (state & ERTS_PORT_SFLG_DISTRIBUTION) {
- erts_atomic64_inc_nob(&prt->dist_entry->in);
+ DistEntry* dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
+ Uint32 conn_id = (Uint32)(UWord) erts_prtsd_get(prt, ERTS_PRTSD_CONN_ID);
+ erts_atomic64_inc_nob(&dep->in);
return erts_net_message(prt,
- prt->dist_entry,
+ dep,
+ conn_id,
(byte*) hbuf, hlen,
(byte*) (bin->orig_bytes+offs), len);
}
@@ -6215,15 +6214,19 @@ int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen,
else
erts_atomic64_add_nob(&bytes_in, (erts_aint64_t) (hlen + len));
if (state & ERTS_PORT_SFLG_DISTRIBUTION) {
- erts_atomic64_inc_nob(&prt->dist_entry->in);
+ DistEntry *dep = (DistEntry*) erts_prtsd_get(prt, ERTS_PRTSD_DIST_ENTRY);
+ Uint32 conn_id = (Uint32)(UWord) erts_prtsd_get(prt, ERTS_PRTSD_CONN_ID);
+ erts_atomic64_inc_nob(&dep->in);
if (len == 0)
return erts_net_message(prt,
- prt->dist_entry,
+ dep,
+ conn_id,
NULL, 0,
(byte*) hbuf, hlen);
else
return erts_net_message(prt,
- prt->dist_entry,
+ dep,
+ conn_id,
(byte*) hbuf, hlen,
(byte*) buf, len);
}
diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab
index 88ede3bb60..349034e8ac 100644
--- a/erts/emulator/beam/ops.tab
+++ b/erts/emulator/beam/ops.tab
@@ -244,7 +244,7 @@ if_end
# Optimize for that case.
raise x==2 x==1 => i_raise
raise Trace=y Value=y => move Trace x=2 | move Value x=1 | i_raise
-raise Trace Value => move Trace x=3 | move Value x=1 | move x=3 x=2 | i_raise
+raise Trace Value => move Trace x | move Value x=1 | move x x=2 | i_raise
i_raise
@@ -483,9 +483,16 @@ is_eq f? s s
is_ne f? s s
#
-# Putting things.
+# Putting tuples.
+#
+# Code compiled with OTP 22 and later uses put_tuple2 to
+# to construct a tuple.
+#
+# Code compiled before OTP 22 uses put_tuple + one put instruction
+# per element. Translate to put_tuple2.
#
+i_put_tuple/2
put_tuple Arity Dst => i_put_tuple Dst u
i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \
@@ -495,11 +502,13 @@ i_put_tuple Dst Arity Puts=* | put S1 | put S2 | \
i_put_tuple Dst Arity Puts=* | put S => \
tuple_append_put(Arity, Dst, Puts, S)
-i_put_tuple/2
+i_put_tuple Dst Arity Puts=* => put_tuple2 Dst Arity Puts
-i_put_tuple xy I
+put_tuple2 xy I
#
+# Putting lists.
+#
# The instruction "put_list Const [] Dst" were generated in rare
# circumstances up to and including OTP 18. Starting with OTP 19,
# AFAIK, it should never be generated.
@@ -1080,67 +1089,73 @@ func_info M F A => i_func_info u M F A
%warm
bs_start_match2 Fail=f ica X Y D => jump Fail
bs_start_match2 Fail Bin X Y D => i_bs_start_match2 Bin Fail X Y D
-i_bs_start_match2 xy f t t x
+i_bs_start_match2 xy f t t d
bs_save2 Reg Index => gen_bs_save(Reg, Index)
-i_bs_save2 x t
+i_bs_save2 xy t
bs_restore2 Reg Index => gen_bs_restore(Reg, Index)
-i_bs_restore2 x t
+i_bs_restore2 xy t
# Matching integers
bs_match_string Fail Ms Bits Val => i_bs_match_string Ms Fail Bits Val
-i_bs_match_string x f W W
+i_bs_match_string xy f W W
# Fetching integers from binaries.
-bs_get_integer2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
+bs_get_integer2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_integer2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-i_bs_get_integer_small_imm x W f? t x
-i_bs_get_integer_imm x W t f? t x
-i_bs_get_integer f? t t x s x
-i_bs_get_integer_8 x f? x
-i_bs_get_integer_16 x f? x
+i_bs_get_integer_small_imm Ms Bits Fail Flags Y=y => \
+ i_bs_get_integer_small_imm Ms Bits Fail Flags x | move x Y
+
+i_bs_get_integer_imm Ms Bits Live Fail Flags Y=y => \
+ i_bs_get_integer_imm Ms Bits Live Fail Flags x | move x Y
+
+i_bs_get_integer_small_imm xy W f? t x
+i_bs_get_integer_imm xy W t f? t x
+i_bs_get_integer f? t t xy s d
+i_bs_get_integer_8 xy f? d
+i_bs_get_integer_16 xy f? d
%if ARCH_64
-i_bs_get_integer_32 x f? x
+i_bs_get_integer_32 xy f? d
%endif
# Fetching binaries from binaries.
-bs_get_binary2 Fail=f Ms=x Live=u Sz=sq Unit=u Flags=u Dst=d => \
+bs_get_binary2 Fail=f Ms=xy Live=u Sz=sq Unit=u Flags=u Dst=d => \
gen_get_binary2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
-i_bs_get_binary_imm2 f? x t W t x
-i_bs_get_binary2 f x t? s t x
-i_bs_get_binary_all2 f? x t t x
-i_bs_get_binary_all_reuse x f? t
+i_bs_get_binary_imm2 f? xy t W t d
+i_bs_get_binary2 f xy t? s t d
+i_bs_get_binary_all2 f? xy t t d
+i_bs_get_binary_all_reuse xy f? t
# Fetching float from binaries.
-bs_get_float2 Fail=f Ms=x Live=u Sz=s Unit=u Flags=u Dst=d => \
+bs_get_float2 Fail=f Ms=xy Live=u Sz=s Unit=u Flags=u Dst=d => \
gen_get_float2(Fail, Ms, Live, Sz, Unit, Flags, Dst)
bs_get_float2 Fail=f Ms=x Live=u Sz=q Unit=u Flags=u Dst=d => jump Fail
-i_bs_get_float2 f? x t s t x
+i_bs_get_float2 f? xy t s t d
# Miscellanous
-bs_skip_bits2 Fail=f Ms=x Sz=sq Unit=u Flags=u => \
+bs_skip_bits2 Fail=f Ms=xy Sz=sq Unit=u Flags=u => \
gen_skip_bits2(Fail, Ms, Sz, Unit, Flags)
-i_bs_skip_bits_imm2 f? x W
-i_bs_skip_bits2 f? x xy t
-i_bs_skip_bits_all2 f? x t
+i_bs_skip_bits_imm2 f? xy W
+i_bs_skip_bits2 f? xy xy t
+i_bs_skip_bits_all2 f? xy t
-bs_test_tail2 Fail=f Ms=x Bits=u==0 => bs_test_zero_tail2 Fail Ms
-bs_test_tail2 Fail=f Ms=x Bits=u => bs_test_tail_imm2 Fail Ms Bits
-bs_test_zero_tail2 f? x
-bs_test_tail_imm2 f? x W
+bs_test_tail2 Fail=f Ms=xy Bits=u==0 => bs_test_zero_tail2 Fail Ms
+bs_test_tail2 Fail=f Ms=xy Bits=u => bs_test_tail_imm2 Fail Ms Bits
+bs_test_zero_tail2 f? xy
+bs_test_tail_imm2 f? xy W
bs_test_unit F Ms Unit=u==8 => bs_test_unit8 F Ms
-bs_test_unit f? x t
-bs_test_unit8 f? x
+bs_test_unit f? xy t
+bs_test_unit8 f? xy
# An y register operand for bs_context_to_binary is rare,
# but can happen because of inlining.
@@ -1152,23 +1167,55 @@ bs_context_to_binary Y=y => move Y x | bs_context_to_binary x
bs_context_to_binary x
+# Gets a bitstring from the tail of a context.
+bs_get_tail xy d t
+
+# New bs_start_match variant for contexts with external position storage.
+#
+# bs_get/set_position is used to save positions into registers instead of
+# "slots" in the context itself, which lets us continue matching even after
+# we've passed it off to another function.
+
+%if ARCH_64
+bs_start_match3 Fail Bin Live Ctx | bs_get_position Ctx Pos=x Ignored => \
+ i_bs_start_match3_gp Bin Live Fail Ctx Pos
+i_bs_start_match3_gp xy t f d x
+%endif
+
+bs_start_match3 Fail=f ica Live Dst => jump Fail
+bs_start_match3 Fail Bin Live Dst => i_bs_start_match3 Bin Live Fail Dst
+
+i_bs_start_match3 xy t f d
+
+# Match context position instructions. 64-bit assumes that all positions can
+# fit into an unsigned small.
+
+%if ARCH_64
+ bs_get_position Src Dst Live => i_bs_get_position Src Dst
+ i_bs_get_position xy xy
+ bs_set_position xy xy
+%else
+ bs_get_position xy d t?
+ bs_set_position xy xy
+%endif
+
#
# Utf8/utf16/utf32 support. (R12B-5)
#
-bs_get_utf8 Fail=f Ms=x u u Dst=d => i_bs_get_utf8 Ms Fail Dst
-i_bs_get_utf8 x f? x
+bs_get_utf8 Fail=f Ms=xy u u Dst=d => i_bs_get_utf8 Ms Fail Dst
+i_bs_get_utf8 xy f? d
-bs_skip_utf8 Fail=f Ms=x u u => i_bs_get_utf8 Ms Fail x
+bs_skip_utf8 Fail=f Ms=xy u u => i_bs_get_utf8 Ms Fail x
-bs_get_utf16 Fail=f Ms=x u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
-bs_skip_utf16 Fail=f Ms=x u Flags=u => i_bs_get_utf16 Ms Fail Flags x
+bs_get_utf16 Fail=f Ms=xy u Flags=u Dst=d => i_bs_get_utf16 Ms Fail Flags Dst
+bs_skip_utf16 Fail=f Ms=xy u Flags=u => i_bs_get_utf16 Ms Fail Flags x
-i_bs_get_utf16 x f? t x
+i_bs_get_utf16 xy f? t d
-bs_get_utf32 Fail=f Ms=x Live=u Flags=u Dst=d => \
+bs_get_utf32 Fail=f Ms=xy Live=u Flags=u Dst=d => \
bs_get_integer2 Fail Ms Live i=32 u=1 Flags Dst | \
i_bs_validate_unicode_retract Fail Dst Ms
-bs_skip_utf32 Fail=f Ms=x Live=u Flags=u => \
+bs_skip_utf32 Fail=f Ms=xy Live=u Flags=u => \
bs_get_integer2 Fail Ms Live i=32 u=1 Flags x | \
i_bs_validate_unicode_retract Fail x Ms
@@ -1182,6 +1229,9 @@ i_bs_validate_unicode_retract j s S
bs_init2 Fail Sz Words Regs Flags Dst | binary_too_big(Sz) => system_limit Fail
+bs_init2 Fail Sz Words Regs Flags Dst=y => \
+ bs_init2 Fail Sz Words Regs Flags x | move x Dst
+
bs_init2 Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init Sz Regs Dst
bs_init2 Fail Sz=u Words Regs Flags Dst => \
@@ -1202,6 +1252,8 @@ i_bs_init_heap W I t? x
bs_init_bits Fail Sz=o Words Regs Flags Dst => system_limit Fail
+bs_init_bits Fail Sz Words Regs Flags Dst=y => \
+ bs_init_bits Fail Sz Words Regs Flags x | move x Dst
bs_init_bits Fail Sz=u Words=u==0 Regs Flags Dst => i_bs_init_bits Sz Regs Dst
bs_init_bits Fail Sz=u Words Regs Flags Dst => i_bs_init_bits_heap Sz Words Regs Dst
@@ -1230,7 +1282,7 @@ bs_private_append Fail Size Unit Bin Flags Dst => \
bs_init_writable
-i_bs_append j? I t? t s x
+i_bs_append j? I t? t s xy
i_bs_private_append j? t s S x
#
@@ -1421,16 +1473,13 @@ get_map_elements Fail Src Size Rest=* | map_key_sort(Size, Rest) => \
i_get_map_elements f? s I
-i_get_map_element Fail Src=xy Key=y Dst => \
- move Key x | i_get_map_element Fail Src x Dst
-
i_get_map_element_hash Fail Src=c Key Hash Dst => \
move Src x | i_get_map_element_hash Fail x Key Hash Dst
i_get_map_element_hash f? xy c I xy
i_get_map_element Fail Src=c Key Dst => \
move Src x | i_get_map_element Fail x Key Dst
-i_get_map_element f? xy x xy
+i_get_map_element f? xy xy xy
#
# Convert the plus operations to a generic plus instruction.
diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c
index 19b1312ee3..996757ef43 100644
--- a/erts/emulator/beam/utils.c
+++ b/erts/emulator/beam/utils.c
@@ -1569,7 +1569,7 @@ make_hash2(Eterm term)
* MUST BE USED AS INPUT FOR THE HASH. Two different terms must always have a
* chance of hashing different when salted: hash([Salt|A]) vs hash([Salt|B]).
*
- * This is why we can not use cached hash values for atoms for example.
+ * This is why we cannot use cached hash values for atoms for example.
*
*/
@@ -3122,7 +3122,7 @@ tailrecur_ne:
ASSERT(alen == blen);
for (i = (Sint) alen - 1; i >= 0; i--)
if (anum[i] != bnum[i])
- RETURN_NEQ((Sint32) (anum[i] - bnum[i]));
+ RETURN_NEQ(anum[i] < bnum[i] ? -1 : 1);
goto pop_next;
case (_TAG_HEADER_EXTERNAL_REF >> _TAG_PRIMARY_SIZE):
if (is_internal_ref(b)) {
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 5e9afdc5ca..dbe0201caf 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -624,6 +624,26 @@ static size_t my_strnlen(const char *s, size_t maxlen)
# define VALGRIND_MAKE_MEM_DEFINED(ptr,size)
#endif
+#ifndef __WIN32__
+/* Calculate CMSG_NXTHDR without having a struct msghdr*.
+ * CMSG_LEN only caters for alignment for start of data.
+ * To get how much to advance we need to use CMSG_SPACE
+ * on the payload length. To get the payload length we
+ * take the calculated cmsg->cmsg_len and subtract the
+ * header length. To get the header length we use
+ * the pointer difference from the cmsg start pointer
+ * to the CMSG_DATA(cmsg) pointer.
+ */
+#define LEN_CMSG_DATA(cmsg) \
+ ((cmsg)->cmsg_len - ((char*)CMSG_DATA(cmsg) - (char*)(cmsg)))
+#define NXT_CMSG_HDR(cmsg) \
+ ((struct cmsghdr*)(((char*)(cmsg)) + CMSG_SPACE(LEN_CMSG_DATA(cmsg))))
+#endif
+
+#if !defined(IPV6_PKTOPTIONS) && defined(IPV6_2292PKTOPTIONS)
+#define IPV6_PKTOPTIONS IPV6_2292PKTOPTIONS
+#endif
+
/*
Magic errno value used locally for return of {error, system_limit}
- the emulator definition of SYSTEM_LIMIT is not available here.
@@ -787,6 +807,12 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */
#define INET_OPT_TCLASS 41 /* IPv6 transport class */
#define INET_OPT_BIND_TO_DEVICE 42 /* get/set network device the socket is bound to */
+#define INET_OPT_RECVTOS 43 /* IP_RECVTOS ancillary data */
+#define INET_OPT_RECVTCLASS 44 /* IPV6_RECVTCLASS ancillary data */
+#define INET_OPT_PKTOPTIONS 45 /* IP(V6)_PKTOPTIONS get ancillary data */
+#define INET_OPT_TTL 46 /* IP_TTL */
+#define INET_OPT_RECVTTL 47 /* IP_RECVTTL ancillary data */
+#define TCP_OPT_NOPUSH 48 /* super-Nagle, aka TCP_CORK */
/* SCTP options: a separate range, from 100: */
#define SCTP_OPT_RTOINFO 100
#define SCTP_OPT_ASSOCINFO 101
@@ -862,6 +888,11 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#define SCTP_FLAG_SACDELAY_ENABLE (32 /* am_sackdelay_enable */)
#define SCTP_FLAG_SACDELAY_DISABLE (64 /* am_sackdelay_disable */)
+/* Flags for recv_cmsgflags */
+#define INET_CMSG_RECVTOS (1 << 0) /* am_recvtos, am_tos */
+#define INET_CMSG_RECVTCLASS (1 << 1) /* am_recvtclass, am_tclass */
+#define INET_CMSG_RECVTTL (1 << 2) /* am_recvttl, am_ttl */
+
/*
** End of interface constants.
**--------------------------------------------------------------------------*/
@@ -916,10 +947,21 @@ static size_t my_strnlen(const char *s, size_t maxlen)
#ifdef HAVE_SCTP
#define PACKET_ERL_DRV_TERM_DATA_LEN 512
#else
+#ifndef __WIN32__
+/* Assume we have recvmsg() and might need room for ancillary data */
+#define PACKET_ERL_DRV_TERM_DATA_LEN 64
+#else
#define PACKET_ERL_DRV_TERM_DATA_LEN 32
#endif
+#endif
+#if defined(TCP_CORK)
+#define INET_TCP_NOPUSH TCP_CORK
+#elif defined(TCP_NOPUSH) && !defined(__DARWIN__)
+#define INET_TCP_NOPUSH TCP_NOPUSH
+#endif
+
#define BIN_REALLOC_MARGIN(x) ((x)/4) /* 25% */
/* The general purpose sockaddr */
@@ -1084,6 +1126,7 @@ typedef struct {
char *netns; /* Socket network namespace name
as full file path */
#endif
+ int recv_cmsgflags; /* Which ancillary data to expect */
} inet_descriptor;
@@ -1336,6 +1379,11 @@ static ErlDrvTermData am_udp_error;
#ifdef HAVE_SYS_UN_H
static ErlDrvTermData am_local;
#endif
+#ifndef __WIN32__
+static ErlDrvTermData am_tos;
+static ErlDrvTermData am_tclass;
+static ErlDrvTermData am_ttl;
+#endif
#ifdef HAVE_SCTP
static ErlDrvTermData am_sctp;
static ErlDrvTermData am_sctp_passive;
@@ -1356,8 +1404,9 @@ static ErlDrvTermData am_sndbuf;
static ErlDrvTermData am_reuseaddr;
static ErlDrvTermData am_dontroute;
static ErlDrvTermData am_priority;
-static ErlDrvTermData am_tos;
-static ErlDrvTermData am_tclass;
+static ErlDrvTermData am_recvtos;
+static ErlDrvTermData am_recvtclass;
+static ErlDrvTermData am_recvttl;
static ErlDrvTermData am_ipv6_v6only;
static ErlDrvTermData am_netns;
static ErlDrvTermData am_bind_to_device;
@@ -1548,8 +1597,10 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
# define ASSOC_ID_LEN 4
# define LOAD_ASSOC_ID LOAD_UINT
# define LOAD_ASSOC_ID_CNT LOAD_UINT_CNT
-# define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */
+#else
+# define IS_SCTP(desc) 0
#endif
+# define ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */
#ifdef HAVE_UDP
static int load_address(ErlDrvTermData* spec, int i, char* buf)
@@ -1785,6 +1836,7 @@ static void release_buffer(ErlDrvBinary* buf)
#ifdef HAVE_UDP
static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz)
{
+ DEBUGF(("realloc_buffer: %ld -> %ld\r\n", (buf==NULL) ? 0 : buf->orig_size, newsz));
return driver_realloc_binary(buf, newsz);
}
#endif
@@ -2749,6 +2801,66 @@ static int inet_async_data(inet_descriptor* desc, const char* buf, int len)
}
}
+#ifndef __WIN32__
+static int load_cmsg_int(ErlDrvTermData *spec, int i,
+ struct cmsghdr *cmsg) {
+ union u {
+ byte uint8;
+ Uint16 uint16;
+ Uint32 uint32;
+ Uint64 uint64;
+ } *p;
+ p = (union u*) CMSG_DATA(cmsg);
+ switch (LEN_CMSG_DATA(cmsg) * CHAR_BIT) {
+ case 8:
+ return LOAD_INT(spec, i, p->uint8);
+ case 16:
+ return LOAD_INT(spec, i, p->uint16);
+
+ case 32:
+ return LOAD_INT(spec, i, p->uint32);
+
+ case 64:
+ return LOAD_INT(spec, i, p->uint64);
+ }
+ return LOAD_INT(spec, i, 0);
+}
+
+static int parse_ancillary_data_item(ErlDrvTermData *spec, int i,
+ struct cmsghdr *cmsg, int *n) {
+#define LOAD_CMSG_INT(proto, type, am) \
+ if (cmsg->cmsg_level == (proto) && \
+ cmsg->cmsg_type == (type)) { \
+ i = LOAD_ATOM(spec, i, (am)); \
+ i = load_cmsg_int(spec, i, cmsg); \
+ i = LOAD_TUPLE(spec, i, 2); \
+ (*n)++; \
+ return i; \
+ }
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ LOAD_CMSG_INT(IPPROTO_IP, IP_TOS, am_tos);
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
+ LOAD_CMSG_INT(IPPROTO_IPV6, IPV6_TCLASS, am_tclass);
+#endif
+#if defined(IPPROTO_IP) && defined(IP_TTL)
+ LOAD_CMSG_INT(IPPROTO_IP, IP_TTL, am_ttl);
+#endif
+ /* BSD uses the RECV* names in CMSG fields */
+#if defined(IPPROTO_IP) && defined(IP_RECVTOS)
+ LOAD_CMSG_INT(IPPROTO_IP, IP_RECVTOS, am_tos);
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_RECVTCLASS)
+ LOAD_CMSG_INT(IPPROTO_IPV6, IPV6_RECVTCLASS, am_tclass);
+#endif
+#if defined(IPPROTO_IP) && defined(IP_RECVTTL)
+ LOAD_CMSG_INT(IPPROTO_IP, IP_RECVTTL, am_ttl);
+#endif
+#undef LOAD_CMSG_INT
+ return i;
+}
+#endif /* #ifndef __WIN32__ */
+
#ifdef HAVE_SCTP
/*
** SCTP-related atoms:
@@ -2880,11 +2992,18 @@ static int sctp_parse_ancillary_data
for (cmsg = frst_msg; cmsg != NULL; cmsg = CMSG_NXTHDR(mptr,cmsg))
{
struct sctp_sndrcvinfo * sri;
-
+#ifndef __WIN32
+ int old_s;
+
+ /* Parse ancillary data common to UDP */
+ old_s = s;
+ i = parse_ancillary_data_item(spec, i, cmsg, &s);
+ if (s > old_s) continue;
/* Skip other possible ancillary data, e.g. from IPv6: */
if (cmsg->cmsg_level != IPPROTO_SCTP ||
cmsg->cmsg_type != SCTP_SNDRCV)
continue;
+#endif
if (((char*)cmsg + cmsg->cmsg_len) - (char*)frst_msg >
mptr->msg_controllen)
@@ -3224,6 +3343,23 @@ static int sctp_parse_async_event
}
#endif /* HAVE_SCTP */
+#ifndef __WIN32__
+static int udp_parse_ancillary_data(ErlDrvTermData *spec, int i,
+ struct msghdr *mptr) {
+ struct cmsghdr *cmsg;
+ int n;
+
+ n = 0;
+ for (cmsg = CMSG_FIRSTHDR(mptr);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(mptr, cmsg)) {
+ i = parse_ancillary_data_item(spec, i, cmsg, &n);
+ }
+ i = LOAD_NIL(spec, i);
+ return LOAD_LIST(spec, i, n+1);
+}
+#endif /* ifndef __WIN32__ */
+
/*
** passive mode reply:
** for UDP:
@@ -3246,7 +3382,7 @@ static int sctp_parse_async_event
static int
inet_async_binary_data
(inet_descriptor* desc, unsigned int phsz,
- ErlDrvBinary * bin, int offs, int len, void * extra)
+ ErlDrvBinary * bin, int offs, int len, void *mp)
{
unsigned int hsz = desc->hsz + phsz;
ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
@@ -3279,9 +3415,10 @@ inet_async_binary_data
if (IS_SCTP(desc))
{ /* For SCTP we always have desc->hsz==0 (i.e., no application-level
headers are used), so hsz==phsz (see above): */
- struct msghdr* mptr;
int sz;
-
+ struct msghdr *mptr;
+
+ mptr = mp;
ASSERT (hsz == phsz && hsz != 0);
sz = len - hsz; /* Size of the msg data proper, w/o the addr */
@@ -3289,7 +3426,6 @@ inet_async_binary_data
i = LOAD_STRING(spec, i, bin->orig_bytes+offs, hsz);
/* Put in the list (possibly empty) of Ancillary Data: */
- mptr = (struct msghdr *) extra;
i = sctp_parse_ancillary_data (spec, i, mptr);
/* Then: Data or Event (Notification)? */
@@ -3318,20 +3454,32 @@ inet_async_binary_data
}
else
#endif /* HAVE_SCTP */
- /* Generic case. Both Addr and Data (or a single list of them together) are
- returned: */
+ {
+ /* Generic case. Both Addr and Data
+ * (or a single list of them together) are returned: */
- if ((desc->mode == INET_MODE_LIST) || (hsz > len)) {
- /* INET_MODE_LIST => [H1,H2,...Hn] */
- i = LOAD_STRING(spec, i, bin->orig_bytes+offs, len);
- }
- else {
- /* INET_MODE_BINARY => [H1,H2,...HSz | Binary] or [Binary]: */
- int sz = len - hsz;
- i = LOAD_BINARY(spec, i, bin, offs+hsz, sz);
- if (hsz > 0)
- i = LOAD_STRING_CONS(spec, i, bin->orig_bytes+offs, hsz);
+ if ((desc->mode == INET_MODE_LIST) || (hsz > len)) {
+ /* INET_MODE_LIST => [H1,H2,...Hn] */
+ i = LOAD_STRING(spec, i, bin->orig_bytes+offs, len);
+ }
+ else {
+ /* INET_MODE_BINARY => [H1,H2,...HSz | Binary] or [Binary]: */
+ int sz = len - hsz;
+ i = LOAD_BINARY(spec, i, bin, offs+hsz, sz);
+ if (hsz > 0)
+ i = LOAD_STRING_CONS(spec, i, bin->orig_bytes+offs, hsz);
+ }
+
+#ifndef __WIN32__
+ if (mp) {
+ /* We got ancillary data from an UDP recvmsg.
+ * Insert an additional tuple level {[F|AddrData],AncData} */
+ i = udp_parse_ancillary_data(spec, i, (struct msghdr*)mp);
+ i = LOAD_TUPLE(spec, i, 2);
+ }
+#endif
}
+
/* Close up the {ok, ...} or {error, ...} tuple: */
i = LOAD_TUPLE(spec, i, 2);
@@ -3463,8 +3611,9 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
** [AddrLen, H2,...,HSz] are msg headers for UDP AF_UNIX only
** Data : List() | Binary()
*/
-static int packet_binary_message
- (inet_descriptor* desc, ErlDrvBinary* bin, int offs, int len, void* extra)
+static int packet_binary_message(inet_descriptor* desc,
+ ErlDrvBinary* bin, int offs, int len,
+ void *mp)
{
unsigned int hsz = desc->hsz;
ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
@@ -3489,8 +3638,14 @@ static int packet_binary_message
# ifdef HAVE_SCTP
if (!IS_SCTP(desc))
- {
# endif
+ {
+#ifndef __WIN32__
+ if (mp) i = udp_parse_ancillary_data(spec, i, (struct msghdr*)mp);
+#endif
+ /* We got ancillary data from an UDP recvmsg.
+ * Insert an additional tuple level {AncData,[F|AddrData]}
+ */
if ((desc->mode == INET_MODE_LIST) || (hsz > len))
/* INET_MODE_LIST, or only headers => [H1,H2,...Hn] */
i = LOAD_STRING(spec, i, bin->orig_bytes+offs, len);
@@ -3502,16 +3657,24 @@ static int packet_binary_message
if (hsz > 0)
i = LOAD_STRING_CONS(spec, i, bin->orig_bytes+offs, hsz);
}
-# ifdef HAVE_SCTP
+ /* Close up the outer 5-or-6-tuple */
+#ifndef __WIN32__
+ if (mp) i = LOAD_TUPLE(spec, i, 6);
+ else
+#endif
+ i = LOAD_TUPLE(spec, i, 5);
}
+# ifdef HAVE_SCTP
else
- { /* For SCTP we always have desc->hsz==0 (i.e., no application-level
+ {
+ struct msghdr *mptr;
+
+ mptr = mp;
+ /* For SCTP we always have desc->hsz==0 (i.e., no application-level
headers are used): */
- struct msghdr* mptr;
ASSERT(hsz == 0);
/* Put in the list (possibly empty) of Ancillary Data: */
- mptr = (struct msghdr *) extra;
i = sctp_parse_ancillary_data (spec, i, mptr);
/* Then: Data or Event (Notification)? */
@@ -3537,11 +3700,11 @@ static int packet_binary_message
/* Close up the {[AncilData], Event_OR_Data} tuple: */
i = LOAD_TUPLE (spec, i, 2);
+ /* Close up the outer 5-tuple: */
+ i = LOAD_TUPLE(spec, i, 5);
}
# endif /* HAVE_SCTP */
- /* Close up the outer 5-tuple: */
- i = LOAD_TUPLE(spec, i, 5);
ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN);
return erl_drv_output_term(desc->dport, spec, i);
}
@@ -3675,19 +3838,19 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len
static int
packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz,
ErlDrvBinary * bin, int offs, int len,
- void * extra)
+ void *mp)
{
int code;
if (desc->active == INET_PASSIVE)
/* "inet" is actually for both UDP and SCTP, as well as TCP! */
- return inet_async_binary_data(desc, hsz, bin, offs, len, extra);
+ return inet_async_binary_data(desc, hsz, bin, offs, len, mp);
else
{ /* INET_ACTIVE or INET_ONCE: */
if (desc->deliver == INET_DELIVER_PORT)
code = inet_port_binary_data(desc, bin, offs, len);
else
- code = packet_binary_message(desc, bin, offs, len, extra);
+ code = packet_binary_message(desc, bin, offs, len, mp);
if (code < 0)
return code;
INET_CHECK_ACTIVE_TO_PASSIVE(desc);
@@ -3754,8 +3917,9 @@ static void inet_init_sctp(void) {
INIT_ATOM(reuseaddr);
INIT_ATOM(dontroute);
INIT_ATOM(priority);
- INIT_ATOM(tos);
- INIT_ATOM(tclass);
+ INIT_ATOM(recvtos);
+ INIT_ATOM(recvtclass);
+ INIT_ATOM(recvttl);
INIT_ATOM(ipv6_v6only);
INIT_ATOM(netns);
INIT_ATOM(bind_to_device);
@@ -3898,6 +4062,11 @@ static int inet_init()
#endif
INIT_ATOM(empty_out_q);
INIT_ATOM(ssl_tls);
+#ifndef __WIN32__
+ INIT_ATOM(tos);
+ INIT_ATOM(tclass);
+ INIT_ATOM(ttl);
+#endif
INIT_ATOM(http_eoh);
INIT_ATOM(http_header);
@@ -4390,7 +4559,7 @@ static void desc_close_read(inet_descriptor* desc)
{
if (desc->s != INVALID_SOCKET) {
#ifdef __WIN32__
- /* This call can not be right???
+ /* This call cannot be right???
* We want to turn off read events but keep any write events.
* But on windows driver_select(...,READ,1) is only used as a
* way to hook into the pollset. sock_select is used to control
@@ -5016,6 +5185,71 @@ static int hwaddr_libdlpi_lookup(const char *ifnm,
}
#endif
+#ifdef HAVE_GETIFADDRS
+/* Returns 0 for success and errno() for failure */
+static int call_getifaddrs(inet_descriptor* desc_p, struct ifaddrs **ifa_pp)
+{
+ int result, save_errno;
+#ifdef HAVE_SETNS
+ int current_ns;
+
+ current_ns = 0;
+ if (desc_p->netns != NULL) {
+ int new_ns;
+ /* Temporarily change network namespace for this thread
+ * over the getifaddrs() call
+ */
+ current_ns = open("/proc/self/ns/net", O_RDONLY);
+ if (current_ns == INVALID_SOCKET)
+ return sock_errno();
+ new_ns = open(desc_p->netns, O_RDONLY);
+ if (new_ns == INVALID_SOCKET) {
+ save_errno = sock_errno();
+ while (close(current_ns) == INVALID_SOCKET &&
+ sock_errno() == EINTR);
+ return save_errno;
+ }
+ if (setns(new_ns, CLONE_NEWNET) != 0) {
+ save_errno = sock_errno();
+ while (close(new_ns) == INVALID_SOCKET &&
+ sock_errno() == EINTR);
+ while (close(current_ns) == INVALID_SOCKET &&
+ sock_errno() == EINTR);
+ return save_errno;
+ }
+ else {
+ while (close(new_ns) == INVALID_SOCKET &&
+ sock_errno() == EINTR);
+ }
+ }
+#endif
+ save_errno = 0;
+ result = getifaddrs(ifa_pp);
+ if (result < 0)
+ save_errno = sock_errno();
+#ifdef HAVE_SETNS
+ if (desc_p->netns != NULL) {
+ /* Restore network namespace */
+ if (setns(current_ns, CLONE_NEWNET) != 0) {
+ /* XXX Failed to restore network namespace.
+ * What to do? Tidy up and return an error...
+ * Note that the thread now might still be in the set namespace.
+ * Can this even happen? Should the emulator be aborted?
+ */
+ if (result >= 0) {
+ /* We got a result but have to waste it */
+ save_errno = sock_errno();
+ freeifaddrs(*ifa_pp);
+ }
+ }
+ while (close(current_ns) == INVALID_SOCKET &&
+ sock_errno() == EINTR);
+ }
+#endif
+ return save_errno;
+}
+#endif /* #ifdef HAVE_GETIFADDRS */
+
/* FIXME: temporary hack */
#ifndef IFHWADDRLEN
#define IFHWADDRLEN 6
@@ -5093,8 +5327,8 @@ static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc,
struct sockaddr_dl *sdlp;
int found = 0;
- if (getifaddrs(&ifa) == -1)
- goto error;
+ if (call_getifaddrs(desc, &ifa) != 0)
+ goto error;
for (ifp = ifa; ifp; ifp = ifp->ifa_next) {
if ((ifp->ifa_addr->sa_family == AF_LINK) &&
@@ -5116,8 +5350,8 @@ static ErlDrvSSizeT inet_ctl_ifget(inet_descriptor* desc,
sys_memcpy(sptr,
sdlp->sdl_data + sdlp->sdl_nlen,
sdlp->sdl_alen);
- freeifaddrs(ifa);
sptr += sdlp->sdl_alen;
+ freeifaddrs(ifa);
#endif
break;
}
@@ -5812,6 +6046,7 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
ErlDrvSizeT buf_size;
char *buf_p;
char *buf_alloc_p;
+ int save_errno;
buf_size = GETIFADDRS_BUFSZ;
buf_alloc_p = ALLOC(GETIFADDRS_BUFSZ);
@@ -5846,9 +6081,9 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
} \
} while (0)
- if (getifaddrs(&ifa_p) < 0) {
- return ctl_error(sock_errno(), rbuf_pp, rsize);
- }
+ if ((save_errno = call_getifaddrs(desc_p, &ifa_p)) != 0)
+ return ctl_error(save_errno, rbuf_pp, rsize);
+
ifa_free_p = ifa_p;
*buf_p++ = INET_REP_OK;
for (; ifa_p; ifa_p = ifa_p->ifa_next) {
@@ -5930,7 +6165,8 @@ static ErlDrvSSizeT inet_ctl_getifaddrs(inet_descriptor* desc_p,
but ditto for the other worked and that was actually the requested
option, failure was still reported to erlang. */
-#if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY)
+#if defined(IP_TOS) && defined(IPPROTO_IP) \
+ && defined(SO_PRIORITY) && !defined(__WIN32__)
static int setopt_prio_tos_trick
(int fd, int proto, int type, char* arg_ptr, int arg_sz, int propagate)
{
@@ -5952,14 +6188,14 @@ static int setopt_prio_tos_trick
res_prio = sock_getopt(fd, SOL_SOCKET, SO_PRIORITY,
(char *) &tmp_ival_prio, &tmp_arg_sz_prio);
- res_tos = sock_getopt(fd, SOL_IP, IP_TOS,
+ res_tos = sock_getopt(fd, IPPROTO_IP, IP_TOS,
(char *) &tmp_ival_tos, &tmp_arg_sz_tos);
res = sock_setopt(fd, proto, type, arg_ptr, arg_sz);
if (res == 0) {
if (type != SO_PRIORITY) {
if (type != IP_TOS && res_tos == 0) {
res_tos = sock_setopt(fd,
- SOL_IP,
+ IPPROTO_IP,
IP_TOS,
(char *) &tmp_ival_tos,
tmp_arg_sz_tos);
@@ -6003,7 +6239,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
int proto;
int opt;
struct linger li_val;
-#ifdef HAVE_MULTICAST_SUPPORT
+#if defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP)
struct ip_mreq mreq_val;
#endif
int ival;
@@ -6026,6 +6262,8 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
/* XXX { int i; for(i=0;i<len;++i) fprintf(stderr,"0x%02X, ", (unsigned) ptr[i]); fprintf(stderr,"\r\n");} */
while(len >= 5) {
+ int recv_cmsgflags;
+
opt = *ptr++;
ival = get_int32(ptr);
ptr += 4;
@@ -6034,6 +6272,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
arg_sz = sizeof(ival);
proto = SOL_SOCKET;
propagate = 0;
+ recv_cmsgflags = desc->recv_cmsgflags;
switch(opt) {
case INET_LOPT_HEADER:
@@ -6284,28 +6523,80 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
(long)desc->port, desc->s, ival));
break;
#else
+ /* inet_fill_opts always returns a value for this option,
+ * so we need to ignore it if not implemented */
continue;
#endif
case INET_OPT_TOS:
-#if defined(IP_TOS) && defined(SOL_IP)
- proto = SOL_IP;
+#if defined(IP_TOS) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
type = IP_TOS;
propagate = 1;
DEBUGF(("inet_set_opts(%ld): s=%d, IP_TOS=%d\r\n",
(long)desc->port, desc->s, ival));
break;
#else
+ /* inet_fill_opts always returns a value for this option,
+ * so we need to ignore it if not implemented. */
continue;
#endif
-#if defined(IPV6_TCLASS) && defined(SOL_IPV6)
+#if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
case INET_OPT_TCLASS:
- proto = SOL_IPV6;
+ proto = IPPROTO_IPV6;
type = IPV6_TCLASS;
propagate = 1;
DEBUGF(("inet_set_opts(%ld): s=%d, IPV6_TCLASS=%d\r\n",
(long)desc->port, desc->s, ival));
break;
#endif
+#if defined(IP_TTL) && defined(IPPROTO_IP)
+ case INET_OPT_TTL:
+ proto = IPPROTO_IP;
+ type = IP_TTL;
+ propagate = 1;
+ DEBUGF(("inet_set_opts(%ld): s=%d, IP_TTL=%d\r\n",
+ (long)desc->port, desc->s, ival));
+ break;
+#endif
+#if defined(IP_RECVTOS) && defined(IPPROTO_IP)
+ case INET_OPT_RECVTOS:
+ proto = IPPROTO_IP;
+ type = IP_RECVTOS;
+ propagate = 1;
+ recv_cmsgflags =
+ ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTOS) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTOS);
+ DEBUGF(("inet_set_opts(%ld): s=%d, IP_RECVTOS=%d\r\n",
+ (long)desc->port, desc->s, ival));
+ break;
+#endif
+#if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6)
+ case INET_OPT_RECVTCLASS:
+ proto = IPPROTO_IPV6;
+ type = IPV6_RECVTCLASS;
+ propagate = 1;
+ recv_cmsgflags =
+ ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTCLASS) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTCLASS);
+ DEBUGF(("inet_set_opts(%ld): s=%d, IPV6_RECVTCLASS=%d\r\n",
+ (long)desc->port, desc->s, ival));
+ break;
+#endif
+#if defined(IP_RECVTTL) && defined(IPPROTO_IP)
+ case INET_OPT_RECVTTL:
+ proto = IPPROTO_IP;
+ type = IP_RECVTTL;
+ propagate = 1;
+ recv_cmsgflags =
+ ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTTL) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTTL);
+ DEBUGF(("inet_set_opts(%ld): s=%d, IP_RECVTTL=%d\r\n",
+ (long)desc->port, desc->s, ival));
+ break;
+#endif
case TCP_OPT_NODELAY:
proto = IPPROTO_TCP;
@@ -6314,7 +6605,20 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
(long)desc->port, desc->s, ival));
break;
-#ifdef HAVE_MULTICAST_SUPPORT
+ case TCP_OPT_NOPUSH:
+#if defined(INET_TCP_NOPUSH)
+ proto = IPPROTO_TCP;
+ type = INET_TCP_NOPUSH;
+ DEBUGF(("inet_set_opts(%ld): s=%d, t=%d TCP_NOPUSH=%d\r\n",
+ (long)desc->port, desc->s, type, ival));
+ break;
+#else
+ /* inet_fill_opts always returns a value for this option,
+ * so we need to ignore it if not implemented, just in case */
+ continue;
+#endif
+
+#if defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP)
case UDP_OPT_MULTICAST_TTL:
proto = IPPROTO_IP;
@@ -6360,10 +6664,10 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
arg_sz = sizeof(mreq_val);
break;
-#endif /* HAVE_MULTICAST_SUPPORT */
+#endif /* defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP) */
case INET_OPT_IPV6_V6ONLY:
-#if HAVE_DECL_IPV6_V6ONLY
+#if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6)
proto = IPPROTO_IPV6;
type = IPV6_V6ONLY;
propagate = 1;
@@ -6423,11 +6727,13 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
default:
return -1;
}
-#if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY)
+#if defined(IP_TOS) && defined(IPPROTO_IP) \
+ && defined(SO_PRIORITY) && !defined(__WIN32__)
res = setopt_prio_tos_trick (desc->s, proto, type, arg_ptr, arg_sz, propagate);
#else
res = sock_setopt (desc->s, proto, type, arg_ptr, arg_sz);
#endif
+ if (res == 0) desc->recv_cmsgflags = recv_cmsgflags;
if (propagate && res != 0) {
return -1;
}
@@ -6435,7 +6741,12 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len)
(long)desc->port, desc->s, res));
if (type == SO_RCVBUF) {
/* make sure we have desc->bufsz >= SO_RCVBUF */
- if (ival > desc->bufsz)
+ if (ival > (1 << 16) && desc->stype == SOCK_DGRAM && !IS_SCTP(desc))
+ /* For UDP we don't want to automatically
+ set the buffer size to be larger than
+ the theoretical max MTU */
+ desc->bufsz = 1 << 16;
+ else if (ival > desc->bufsz)
desc->bufsz = ival;
}
}
@@ -6564,10 +6875,14 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
while (curr < ptr + len)
{
+ int recv_cmsgflags;
/* Get the Erlang-encoded option type -- always 1 byte: */
- int eopt = *curr;
+ int eopt;
+
+ eopt = *curr;
curr++;
+ recv_cmsgflags = desc->recv_cmsgflags;
/* Get the option value. XXX: The condition (curr < ptr + len)
does not preclude us from reading from beyond the buffer end,
if the Erlang part of the driver specifies its input wrongly!
@@ -6748,28 +7063,32 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
break;
}
# else
- continue; /* Option not supported -- ignore it */
+ /* inet_fill_opts always returns a value for this option,
+ * so we need to ignore it if not implemented, just in case */
+ continue;
# endif
case INET_OPT_TOS:
-# if defined(IP_TOS) && defined(SOL_IP)
+# if defined(IP_TOS) && defined(IPPROTO_IP)
{
arg.ival= get_int32 (curr); curr += 4;
- proto = SOL_IP;
+ proto = IPPROTO_IP;
type = IP_TOS;
arg_ptr = (char*) (&arg.ival);
arg_sz = sizeof ( arg.ival);
break;
}
# else
- continue; /* Option not supported -- ignore it */
+ /* inet_fill_opts always returns a value for this option,
+ * so we need to ignore it if not implemented, just in case */
+ continue;
# endif
-# if defined(IPV6_TCLASS) && defined(SOL_IPV6)
+# if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
case INET_OPT_TCLASS:
{
arg.ival= get_int32 (curr); curr += 4;
- proto = SOL_IPV6;
+ proto = IPPROTO_IPV6;
type = IPV6_TCLASS;
arg_ptr = (char*) (&arg.ival);
arg_sz = sizeof ( arg.ival);
@@ -6777,9 +7096,69 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
}
# endif
+# if defined(IP_TTL) && defined(IPPROTO_IP)
+ case INET_OPT_TTL:
+ {
+ arg.ival= get_int32 (curr); curr += 4;
+ proto = IPPROTO_IP;
+ type = IP_TTL;
+ arg_ptr = (char*) (&arg.ival);
+ arg_sz = sizeof ( arg.ival);
+ break;
+ }
+# endif
+
+# if defined(IP_RECVTOS) && defined(IPPROTO_IP)
+ case INET_OPT_RECVTOS:
+ {
+ arg.ival= get_int32 (curr); curr += 4;
+ proto = IPPROTO_IP;
+ type = IP_RECVTOS;
+ arg_ptr = (char*) (&arg.ival);
+ arg_sz = sizeof ( arg.ival);
+ recv_cmsgflags =
+ arg.ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTOS) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTOS);
+ break;
+ }
+# endif
+
+# if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6)
+ case INET_OPT_RECVTCLASS:
+ {
+ arg.ival= get_int32 (curr); curr += 4;
+ proto = IPPROTO_IPV6;
+ type = IPV6_RECVTCLASS;
+ arg_ptr = (char*) (&arg.ival);
+ arg_sz = sizeof ( arg.ival);
+ recv_cmsgflags =
+ arg.ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTCLASS) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTCLASS);
+ break;
+ }
+# endif
+
+# if defined(IP_RECVTTL) && defined(IPPROTO_IP)
+ case INET_OPT_RECVTTL:
+ {
+ arg.ival= get_int32 (curr); curr += 4;
+ proto = IPPROTO_IP;
+ type = IP_RECVTTL;
+ arg_ptr = (char*) (&arg.ival);
+ arg_sz = sizeof ( arg.ival);
+ recv_cmsgflags =
+ arg.ival ?
+ (desc->recv_cmsgflags | INET_CMSG_RECVTTL) :
+ (desc->recv_cmsgflags & ~INET_CMSG_RECVTTL);
+ break;
+ }
+# endif
+
case INET_OPT_IPV6_V6ONLY:
-# if HAVE_DECL_IPV6_V6ONLY
+# if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6)
{
arg.ival= get_int32 (curr); curr += 4;
proto = IPPROTO_IPV6;
@@ -7029,13 +7408,15 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
*/
return -1;
}
-#if defined(IP_TOS) && defined(SOL_IP) && defined(SO_PRIORITY)
+#if defined(IP_TOS) && defined(IPPROTO_IP) \
+ && defined(SO_PRIORITY) && !defined(__WIN32__)
res = setopt_prio_tos_trick (desc->s, proto, type, arg_ptr, arg_sz, 1);
#else
res = sock_setopt (desc->s, proto, type, arg_ptr, arg_sz);
#endif
/* The return values of "sock_setopt" can only be 0 or -1: */
ASSERT(res == 0 || res == -1);
+ if (res == 0) desc->recv_cmsgflags = recv_cmsgflags;
if (res == -1)
{ /* Got an error, DO NOT continue with other options. However, on
Solaris 10, we DO allow SO_SNDBUF and SO_RCVBUF to fail, assu-
@@ -7056,6 +7437,35 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len)
}
#endif /* HAVE_SCTP */
+#ifndef __WIN32__
+static void put_cmsg_int32(struct cmsghdr *cmsg, char *ptr) {
+ union u {
+ byte uint8;
+ Uint16 uint16;
+ Uint32 uint32;
+ Uint64 uint64;
+ } *p;
+ p = (union u*) CMSG_DATA(cmsg);
+ switch (LEN_CMSG_DATA(cmsg) * CHAR_BIT) {
+ case 8:
+ put_int32((Uint32) p->uint8, ptr);
+ break;
+ case 16:
+ put_int32((Uint32) p->uint16, ptr);
+ break;
+ case 32:
+ put_int32(p->uint32, ptr);
+ break;
+ case 64:
+ put_int32((Uint32) p->uint64, ptr);
+ break;
+ default:
+ put_int32(0, ptr);
+ }
+ return;
+}
+#endif
+
/* load all option values into the buf and reply
** return total length of reply filled into ptr
** ptr should point to a buffer with 9*len +1 to be safe!!
@@ -7290,8 +7700,8 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
continue;
#endif
case INET_OPT_TOS:
-#if defined(IP_TOS) && defined(SOL_IP)
- proto = SOL_IP;
+#if defined(IP_TOS) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
type = IP_TOS;
break;
#else
@@ -7300,14 +7710,50 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
continue;
#endif
case INET_OPT_TCLASS:
-#if defined(IPV6_TCLASS) && defined(SOL_IPV6)
- proto = SOL_IPV6;
+#if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
+ proto = IPPROTO_IPV6;
type = IPV6_TCLASS;
break;
#else
TRUNCATE_TO(0,ptr);
continue;
#endif
+ case INET_OPT_TTL:
+#if defined(IP_TTL) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_TTL;
+ break;
+#else
+ TRUNCATE_TO(0,ptr);
+ continue;
+#endif
+ case INET_OPT_RECVTOS:
+#if defined(IP_RECVTOS) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_RECVTOS;
+ break;
+#else
+ TRUNCATE_TO(0,ptr);
+ continue;
+#endif
+ case INET_OPT_RECVTCLASS:
+#if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6)
+ proto = IPPROTO_IPV6;
+ type = IPV6_RECVTCLASS;
+ break;
+#else
+ TRUNCATE_TO(0,ptr);
+ continue;
+#endif
+ case INET_OPT_RECVTTL:
+#if defined(IP_RECVTTL) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_RECVTTL;
+ break;
+#else
+ TRUNCATE_TO(0,ptr);
+ continue;
+#endif
case INET_OPT_REUSEADDR:
type = SO_REUSEADDR;
break;
@@ -7333,8 +7779,18 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
proto = IPPROTO_TCP;
type = TCP_NODELAY;
break;
+ case TCP_OPT_NOPUSH:
+#if defined(INET_TCP_NOPUSH)
+ proto = IPPROTO_TCP;
+ type = INET_TCP_NOPUSH;
+ break;
+#else
+ *ptr++ = opt;
+ put_int32(0, ptr);
+ continue;
+#endif
-#ifdef HAVE_MULTICAST_SUPPORT
+#if defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP)
case UDP_OPT_MULTICAST_TTL:
proto = IPPROTO_IP;
type = IP_MULTICAST_TTL;
@@ -7353,10 +7809,10 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
arg_ptr = (char*) &li_val;
type = SO_LINGER;
break;
-#endif /* HAVE_MULTICAST_SUPPORT */
+#endif /* defined(HAVE_MULTICAST_SUPPORT) && defined(IPPROTO_IP) */
case INET_OPT_IPV6_V6ONLY:
-#if HAVE_DECL_IPV6_V6ONLY
+#if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6)
proto = IPPROTO_IPV6;
type = IPV6_V6ONLY;
break;
@@ -7434,6 +7890,93 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
continue;
#endif
+#ifndef __WIN32__
+ /* Winsock does not have struct cmsghdr */
+ case INET_OPT_PKTOPTIONS: {
+ struct cmsghdr *cmsg, *cmsg_top;
+ SOCKLEN_T cmsg_sz;
+ union {
+ /* Ensure alignment */
+ struct cmsghdr hdr;
+ /* Room for (IP_TOS | IPV6_TCLASS) + IP_TTL */
+ char buf[2*CMSG_SPACE(sizeof(int))];
+ } cmsgbuf;
+ /* Select between IPv4 or IPv6 PKTOPTIONS
+ * depending on the socket protocol family
+ */
+ switch (desc->sfamily) {
+#if defined(IPPROTO_IP) && defined(IP_PKTOPTIONS)
+ case AF_INET: {
+ proto = IPPROTO_IP;
+ type = IP_PKTOPTIONS;
+ }
+ break;
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_PKTOPTIONS) && defined(AF_INET6)
+ case AF_INET6: {
+ proto = IPPROTO_IPV6;
+ type = IPV6_PKTOPTIONS;
+ }
+ break;
+#endif
+ default: {
+ RETURN_ERROR();
+ }
+ } /* switch */
+ TRUNCATE_TO(0, ptr);
+ /* Fetch a cmsg buffer from the socket */
+ cmsg_sz = sizeof(cmsgbuf.buf);
+ if (IS_SOCKET_ERROR(sock_getopt(desc->s, proto, type,
+ cmsgbuf.buf, &cmsg_sz))) {
+ continue;
+ }
+ /* Reply with Opt/8, Length/32, [COpt/8, Value/32]*
+ * i.e opt, total length and then all returned
+ * cmsg options and values
+ */
+ PLACE_FOR(1+4, ptr);
+ *ptr++ = opt;
+ arg_ptr = ptr; /* Where to put total length */
+ arg_sz = 0; /* Total length */
+ for (cmsg_top = (struct cmsghdr*)(cmsgbuf.buf + cmsg_sz),
+ cmsg = (struct cmsghdr*)cmsgbuf.buf;
+ cmsg < cmsg_top;
+ cmsg = NXT_CMSG_HDR(cmsg)) {
+#define PUT_CMSG_INT32(CMSG_LEVEL, CMSG_TYPE, OPT) \
+ if ((cmsg->cmsg_level == CMSG_LEVEL) && \
+ (cmsg->cmsg_type == CMSG_TYPE)) { \
+ PLACE_FOR(1+4, ptr); \
+ *ptr++ = OPT; \
+ put_cmsg_int32(cmsg, ptr); \
+ arg_sz += 1+4; \
+ continue; \
+ }
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+ PUT_CMSG_INT32(IPPROTO_IP, IP_TOS, INET_OPT_TOS);
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS)
+ PUT_CMSG_INT32(IPPROTO_IPV6, IPV6_TCLASS, INET_OPT_TCLASS);
+#endif
+#if defined(IPPROTO_IP) && defined(IP_TTL)
+ PUT_CMSG_INT32(IPPROTO_IP, IP_TTL, INET_OPT_TTL);
+#endif
+ /* BSD uses the RECV* names in CMSG fields */
+#if defined(IPPROTO_IP) && defined(IP_RECVTOS)
+ PUT_CMSG_INT32(IPPROTO_IP, IP_RECVTOS, INET_OPT_TOS);
+#endif
+#if defined(IPPROTO_IPV6) && defined(IPV6_RECVTCLASS)
+ PUT_CMSG_INT32(IPPROTO_IPV6, IPV6_RECVTCLASS, INET_OPT_TCLASS);
+#endif
+#if defined(IPPROTO_IP) && defined(IP_RECVTTL)
+ PUT_CMSG_INT32(IPPROTO_IP, IP_RECVTTL, INET_OPT_TTL);
+#endif
+#undef PUT_CMSG_INT32
+ }
+ put_int32(arg_sz, arg_ptr); /* Put total length */
+ continue;
+ }
+#endif /* #ifdef __WIN32__ */
+
default:
RETURN_ERROR();
}
@@ -7493,6 +8036,7 @@ static int load_paddrinfo (ErlDrvTermData * spec, int i,
return i;
}
+
/*
** "sctp_fill_opts": Returns {ok, Results}, or an error:
*/
@@ -7742,6 +8286,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
case INET_OPT_PRIORITY :
case INET_OPT_TOS :
case INET_OPT_TCLASS :
+ case INET_OPT_TTL :
case INET_OPT_IPV6_V6ONLY:
case SCTP_OPT_AUTOCLOSE:
case SCTP_OPT_MAXSEG :
@@ -7749,6 +8294,9 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
case SCTP_OPT_NODELAY :
case SCTP_OPT_DISABLE_FRAGMENTS:
case SCTP_OPT_I_WANT_MAPPED_V4_ADDR:
+ case INET_OPT_RECVTOS :
+ case INET_OPT_RECVTCLASS :
+ case INET_OPT_RECVTTL :
{
int res = 0;
unsigned int sz = sizeof(res);
@@ -7804,8 +8352,8 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
}
case INET_OPT_TOS:
{
-# if defined(IP_TOS) && defined(SOL_IP)
- proto = SOL_IP;
+# if defined(IP_TOS) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
type = IP_TOS;
is_int = 1;
tag = am_tos;
@@ -7817,8 +8365,8 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
}
case INET_OPT_TCLASS:
{
-# if defined(IPV6_TCLASS) && defined(SOL_IPV6)
- proto = SOL_IPV6;
+# if defined(IPV6_TCLASS) && defined(IPPROTO_IPV6)
+ proto = IPPROTO_IPV6;
type = IPV6_TCLASS;
is_int = 1;
tag = am_tclass;
@@ -7828,8 +8376,60 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
continue;
# endif
}
+ case INET_OPT_TTL:
+ {
+# if defined(IP_TTL) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_TTL;
+ is_int = 1;
+ tag = am_ttl;
+ break;
+# else
+ /* Not supported -- ignore */
+ continue;
+# endif
+ }
+ case INET_OPT_RECVTOS:
+ {
+# if defined(IP_RECVTOS) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_RECVTOS;
+ is_int = 0;
+ tag = am_recvtos;
+ break;
+# else
+ /* Not supported -- ignore */
+ continue;
+# endif
+ }
+ case INET_OPT_RECVTCLASS:
+ {
+# if defined(IPV6_RECVTCLASS) && defined(IPPROTO_IPV6)
+ proto = IPPROTO_IPV6;
+ type = IPV6_RECVTCLASS;
+ is_int = 0;
+ tag = am_recvtclass;
+ break;
+# else
+ /* Not supported -- ignore */
+ continue;
+# endif
+ }
+ case INET_OPT_RECVTTL:
+ {
+# if defined(IP_RECVTTL) && defined(IPPROTO_IP)
+ proto = IPPROTO_IP;
+ type = IP_RECVTTL;
+ is_int = 0;
+ tag = am_recvttl;
+ break;
+# else
+ /* Not supported -- ignore */
+ continue;
+# endif
+ }
case INET_OPT_IPV6_V6ONLY:
-# if HAVE_DECL_IPV6_V6ONLY
+# if HAVE_DECL_IPV6_V6ONLY && defined(IPPROTO_IPV6)
{
proto = IPPROTO_IPV6;
type = IPV6_V6ONLY;
@@ -8494,6 +9094,8 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol)
desc->netns = NULL;
#endif
+ desc->recv_cmsgflags = 0;
+
return (ErlDrvData)desc;
}
@@ -11912,10 +12514,10 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
if (IS_SCTP(desc))
{
ErlDrvSizeT data_len;
- struct iovec iov[1]; /* For real data */
- struct msghdr mhdr; /* Message wrapper */
- struct sctp_sndrcvinfo *sri; /* The actual ancilary data */
- union { /* For ancilary data */
+ struct iovec iov[1]; /* For real data */
+ struct msghdr mhdr; /* Message wrapper */
+ struct sctp_sndrcvinfo *sri; /* The actual ancillary data */
+ union { /* For ancillary data */
struct cmsghdr hdr;
char ancd[CMSG_SPACE(sizeof(*sri))];
} cmsg;
@@ -11925,12 +12527,12 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
return;
}
- /* The ancilary data */
+ /* The ancillary data */
sri = (struct sctp_sndrcvinfo *) (CMSG_DATA(&cmsg.hdr));
/* Get the "sndrcvinfo" from the buffer, advancing the "ptr": */
ptr = sctp_get_sendparams(sri, ptr);
- /* The ancilary data wrapper */
+ /* The ancillary data wrapper */
cmsg.hdr.cmsg_level = IPPROTO_SCTP;
cmsg.hdr.cmsg_type = SCTP_SNDRCV;
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(*sri));
@@ -11945,7 +12547,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
iov[0].iov_base = ptr; /* The real data */
mhdr.msg_iov = iov;
mhdr.msg_iovlen = 1;
- mhdr.msg_control = cmsg.ancd; /* For ancilary data */
+ mhdr.msg_control = cmsg.ancd; /* For ancillary data */
mhdr.msg_controllen = cmsg.hdr.cmsg_len;
VALGRIND_MAKE_MEM_DEFINED(mhdr.msg_control, mhdr.msg_controllen); /*suppress "uninitialised bytes"*/
mhdr.msg_flags = 0; /* Not used with "sendmsg" */
@@ -12029,10 +12631,12 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
char abuf[sizeof(inet_address)]; /* buffer address; enough??? */
int packet_count = udesc->read_packets;
int count = 0; /* number of packets delivered to owner */
-#ifdef HAVE_SCTP
+#ifndef __WIN32__
struct msghdr mhdr; /* Top-level msg structure */
struct iovec iov[1]; /* Data or Notification Event */
- char ancd[SCTP_ANC_BUFF_SIZE]; /* Ancillary Data */
+ char ancd[ANC_BUFF_SIZE]; /* Ancillary Data */
+#endif
+#ifdef HAVE_SCTP
int short_recv = 0;
#endif
@@ -12042,15 +12646,11 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
sys_memzero((char *) &other, sizeof(other));
/* udesc->i_buf is only kept between SCTP fragments */
- if (udesc->i_buf == NULL) {
- udesc->i_bufsz = desc->bufsz + len;
- if ((udesc->i_buf = alloc_buffer(udesc->i_bufsz)) == NULL)
- return packet_error(udesc, ENOMEM);
- /* pointer to message start */
- udesc->i_ptr = udesc->i_buf->orig_bytes + len;
- } else {
- ErlDrvBinary* tmp;
+#ifdef HAVE_SCTP
+ if (udesc->i_buf != NULL) {
+ ErlDrvBinary* tmp;
int bufsz;
+ ASSERT(IS_SCTP(desc));
bufsz = desc->bufsz + (udesc->i_ptr - udesc->i_buf->orig_bytes);
if ((tmp = realloc_buffer(udesc->i_buf, bufsz)) == NULL) {
release_buffer(udesc->i_buf);
@@ -12062,6 +12662,15 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
udesc->i_buf = tmp;
udesc->i_bufsz = bufsz;
}
+ } else
+#endif
+ {
+ ASSERT(udesc->i_buf == NULL);
+ udesc->i_bufsz = desc->bufsz + len;
+ if ((udesc->i_buf = alloc_buffer(udesc->i_bufsz)) == NULL)
+ return packet_error(udesc, ENOMEM);
+ /* pointer to message start */
+ udesc->i_ptr = udesc->i_buf->orig_bytes + len;
}
/* Note: On Windows NT, recvfrom() fails if the socket is connected. */
@@ -12076,7 +12685,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
mhdr.msg_iov = iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = ancd;
- mhdr.msg_controllen = SCTP_ANC_BUFF_SIZE;
+ mhdr.msg_controllen = ANC_BUFF_SIZE;
mhdr.msg_flags = 0; /* To be filled by "recvmsg" */
/* Do the actual SCTP receive: */
@@ -12091,6 +12700,24 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
other = desc->remote;
goto check_result;
}
+#ifndef __WIN32__
+ /* recvmsg() does not exist in the Winsock API */
+ if (desc->recv_cmsgflags) {
+ /* Use recvmsg() */
+ iov->iov_base = udesc->i_ptr;
+ iov->iov_len = desc->bufsz;
+ mhdr.msg_name = &other;
+ mhdr.msg_namelen = len;
+ mhdr.msg_iov = iov;
+ mhdr.msg_iovlen = 1;
+ mhdr.msg_control = ancd;
+ mhdr.msg_controllen = ANC_BUFF_SIZE;
+ mhdr.msg_flags = 0;
+ n = sock_recvmsg(desc->s, &mhdr, 0);
+ len = mhdr.msg_namelen;
+ goto check_result;
+ }
+#endif
n = sock_recvfrom(desc->s, udesc->i_ptr, desc->bufsz,
0, &other.sa, &len);
check_result:
@@ -12120,6 +12747,14 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
) {
sock_select(desc,FD_READ,1);
}
+#ifdef HAVE_SCTP
+ if (!short_recv) {
+#endif
+ release_buffer(udesc->i_buf);
+ udesc->i_buf = NULL;
+#ifdef HAVE_SCTP
+ }
+#endif
return count; /* strange, not ready */
}
@@ -12135,7 +12770,7 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
{
/* message received */
int code;
- void * extra = NULL;
+ void *mp;
char * ptr;
int nsz;
@@ -12166,14 +12801,18 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
udesc->i_ptr = NULL; /* not used from here */
}
}
+ mp = NULL;
#ifdef HAVE_SCTP
- if (IS_SCTP(desc)) extra = &mhdr;
+ if (IS_SCTP(desc)) mp = &mhdr;
+#endif
+#ifndef __WIN32__
+ if (desc->recv_cmsgflags) mp = &mhdr;
#endif
/* Actual parsing and return of the data received, occur here: */
code = packet_reply_binary_data(desc, len, udesc->i_buf,
(sizeof(other) - len),
nsz,
- extra);
+ mp);
free_buffer(udesc->i_buf);
udesc->i_buf = NULL;
if (code < 0)
diff --git a/erts/emulator/drivers/unix/ttsl_drv.c b/erts/emulator/drivers/unix/ttsl_drv.c
index 28c6cc0f94..11bb4373d8 100644
--- a/erts/emulator/drivers/unix/ttsl_drv.c
+++ b/erts/emulator/drivers/unix/ttsl_drv.c
@@ -31,7 +31,7 @@
static int ttysl_init(void);
static ErlDrvData ttysl_start(ErlDrvPort, char*);
-#ifdef HAVE_TERMCAP /* else make an empty driver that can not be opened */
+#ifdef HAVE_TERMCAP /* else make an empty driver that cannot be opened */
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
diff --git a/erts/emulator/internal_doc/CarrierMigration.md b/erts/emulator/internal_doc/CarrierMigration.md
index 6c79bd731c..bb3d8aac28 100644
--- a/erts/emulator/internal_doc/CarrierMigration.md
+++ b/erts/emulator/internal_doc/CarrierMigration.md
@@ -203,8 +203,8 @@ limited. We only inspect a limited number of carriers. If none of
those carriers had a free block large enough to satisfy the allocation
request, the search will fail. A carrier in the pool can also be BUSY
if another thread is currently doing block deallocation work on the
-carrier. A BUSY carrier will also be skipped by the search as it can
-not satisfy the request. The pool is lock-free and we do not want to
+carrier. A BUSY carrier will also be skipped by the search as it cannot
+satisfy the request. The pool is lock-free and we do not want to
block, waiting for the other thread to finish.
### The bad cluster problem ###
diff --git a/erts/emulator/nifs/common/prim_file_nif.c b/erts/emulator/nifs/common/prim_file_nif.c
index a05d50b333..009761a7f8 100644
--- a/erts/emulator/nifs/common/prim_file_nif.c
+++ b/erts/emulator/nifs/common/prim_file_nif.c
@@ -442,7 +442,8 @@ static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
ERL_NIF_TERM result;
efile_path_t path;
- if(argc != 2 || !enif_is_list(env, argv[1])) {
+ ASSERT(argc == 2);
+ if(!enif_is_list(env, argv[1])) {
return enif_make_badarg(env);
}
@@ -469,9 +470,7 @@ static ERL_NIF_TERM open_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
static ERL_NIF_TERM close_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
enum efile_state_t previous_state;
- if(argc != 0) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 0);
previous_state = erts_atomic32_cmpxchg_acqb(&d->state,
EFILE_STATE_CLOSED, EFILE_STATE_BUSY);
@@ -495,7 +494,8 @@ static ERL_NIF_TERM read_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, con
SysIOVec read_vec[1];
ErlNifBinary result;
- if(argc != 1 || !enif_is_number(env, argv[0])) {
+ ASSERT(argc == 1);
+ if(!enif_is_number(env, argv[0])) {
return enif_make_badarg(env);
}
@@ -514,6 +514,7 @@ static ERL_NIF_TERM read_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, con
ASSERT(bytes_read <= block_size);
if(bytes_read < 0) {
+ enif_release_binary(&result);
return posix_error_to_tuple(env, d->posix_errno);
} else if(bytes_read == 0) {
enif_release_binary(&result);
@@ -532,7 +533,8 @@ static ERL_NIF_TERM write_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, co
Sint64 bytes_written;
ERL_NIF_TERM tail;
- if(argc != 1 || !enif_inspect_iovec(env, 64, argv[0], &tail, &input)) {
+ ASSERT(argc == 1);
+ if(!enif_inspect_iovec(env, 64, argv[0], &tail, &input)) {
return enif_make_badarg(env);
}
@@ -555,8 +557,8 @@ static ERL_NIF_TERM pread_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, co
SysIOVec read_vec[1];
ErlNifBinary result;
- if(argc != 2 || !enif_is_number(env, argv[0])
- || !enif_is_number(env, argv[1])) {
+ ASSERT(argc == 2);
+ if(!enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) {
return enif_make_badarg(env);
}
@@ -576,6 +578,7 @@ static ERL_NIF_TERM pread_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, co
bytes_read = efile_preadv(d, offset, read_vec, 1);
if(bytes_read < 0) {
+ enif_release_binary(&result);
return posix_error_to_tuple(env, d->posix_errno);
} else if(bytes_read == 0) {
enif_release_binary(&result);
@@ -594,8 +597,9 @@ static ERL_NIF_TERM pwrite_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, c
Sint64 bytes_written, offset;
ERL_NIF_TERM tail;
- if(argc != 2 || !enif_is_number(env, argv[0])
- || !enif_inspect_iovec(env, 64, argv[1], &tail, &input)) {
+ ASSERT(argc == 2);
+ if(!enif_is_number(env, argv[0])
+ || !enif_inspect_iovec(env, 64, argv[1], &tail, &input)) {
return enif_make_badarg(env);
}
@@ -622,7 +626,8 @@ static ERL_NIF_TERM seek_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, con
Sint64 new_position, offset;
enum efile_seek_t seek;
- if(argc != 2 || !enif_get_int64(env, argv[1], &offset)) {
+ ASSERT(argc == 2);
+ if(!enif_get_int64(env, argv[1], &offset)) {
return enif_make_badarg(env);
}
@@ -646,7 +651,8 @@ static ERL_NIF_TERM seek_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, con
static ERL_NIF_TERM sync_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
int data_only;
- if(argc != 1 || !enif_get_int(env, argv[0], &data_only)) {
+ ASSERT(argc == 1);
+ if(!enif_get_int(env, argv[0], &data_only)) {
return enif_make_badarg(env);
}
@@ -658,9 +664,7 @@ static ERL_NIF_TERM sync_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, con
}
static ERL_NIF_TERM truncate_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
- if(argc != 0) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 0);
if(!efile_truncate(d)) {
return posix_error_to_tuple(env, d->posix_errno);
@@ -672,8 +676,8 @@ static ERL_NIF_TERM truncate_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc,
static ERL_NIF_TERM allocate_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
Sint64 offset, length;
- if(argc != 2 || !enif_is_number(env, argv[0])
- || !enif_is_number(env, argv[1])) {
+ ASSERT(argc == 2);
+ if(!enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) {
return enif_make_badarg(env);
}
@@ -694,8 +698,8 @@ static ERL_NIF_TERM advise_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, c
enum efile_advise_t advise;
Sint64 offset, length;
- if(argc != 3 || !enif_is_number(env, argv[0])
- || !enif_is_number(env, argv[1])) {
+ ASSERT(argc == 3);
+ if(!enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) {
return enif_make_badarg(env);
}
@@ -758,8 +762,8 @@ static ERL_NIF_TERM ipread_s32bu_p32bu_nif_impl(efile_data_t *d, ErlNifEnv *env,
ErlNifBinary payload;
- if(argc != 2 || !enif_is_number(env, argv[0])
- || !enif_is_number(env, argv[1])) {
+ ASSERT(argc == 2);
+ if(!enif_is_number(env, argv[0]) || !enif_is_number(env, argv[1])) {
return enif_make_badarg(env);
}
@@ -802,6 +806,7 @@ static ERL_NIF_TERM ipread_s32bu_p32bu_nif_impl(efile_data_t *d, ErlNifEnv *env,
bytes_read = efile_preadv(d, payload_offset, read_vec, 1);
if(bytes_read < 0) {
+ enif_release_binary(&payload);
return posix_error_to_tuple(env, d->posix_errno);
} else if(bytes_read == 0) {
enif_release_binary(&payload);
@@ -825,9 +830,7 @@ static ERL_NIF_TERM ipread_s32bu_p32bu_nif_impl(efile_data_t *d, ErlNifEnv *env,
}
static ERL_NIF_TERM get_handle_nif_impl(efile_data_t *d, ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {
- if(argc != 0) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 0);
return efile_get_handle(env, d);
}
@@ -839,7 +842,8 @@ static ERL_NIF_TERM read_info_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
efile_path_t path;
int follow_links;
- if(argc != 2 || !enif_get_int(env, argv[1], &follow_links)) {
+ ASSERT(argc == 2);
+ if(!enif_get_int(env, argv[1], &follow_links)) {
return enif_make_badarg(env);
}
@@ -874,7 +878,8 @@ static ERL_NIF_TERM set_permissions_nif(ErlNifEnv *env, int argc, const ERL_NIF_
efile_path_t path;
Uint32 permissions;
- if(argc != 2 || !enif_get_uint(env, argv[1], &permissions)) {
+ ASSERT(argc == 2);
+ if(!enif_get_uint(env, argv[1], &permissions)) {
return enif_make_badarg(env);
}
@@ -893,8 +898,8 @@ static ERL_NIF_TERM set_owner_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
efile_path_t path;
Sint32 uid, gid;
- if(argc != 3 || !enif_get_int(env, argv[1], &uid)
- || !enif_get_int(env, argv[2], &gid)) {
+ ASSERT(argc == 3);
+ if(!enif_get_int(env, argv[1], &uid) || !enif_get_int(env, argv[2], &gid)) {
return enif_make_badarg(env);
}
@@ -913,9 +918,10 @@ static ERL_NIF_TERM set_time_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
Sint64 accessed, modified, created;
efile_path_t path;
- if(argc != 4 || !enif_get_int64(env, argv[1], &accessed)
- || !enif_get_int64(env, argv[2], &modified)
- || !enif_get_int64(env, argv[3], &created)) {
+ ASSERT(argc == 4);
+ if(!enif_get_int64(env, argv[1], &accessed)
+ || !enif_get_int64(env, argv[2], &modified)
+ || !enif_get_int64(env, argv[3], &created)) {
return enif_make_badarg(env);
}
@@ -934,9 +940,7 @@ static ERL_NIF_TERM read_link_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
efile_path_t path;
ERL_NIF_TERM result;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -953,9 +957,7 @@ static ERL_NIF_TERM list_dir_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
efile_path_t path;
ERL_NIF_TERM result;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -971,9 +973,7 @@ static ERL_NIF_TERM rename_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv
efile_path_t existing_path, new_path;
- if(argc != 2) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 2);
if((posix_errno = efile_marshal_path(env, argv[0], &existing_path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -991,9 +991,7 @@ static ERL_NIF_TERM make_hard_link_nif(ErlNifEnv *env, int argc, const ERL_NIF_T
efile_path_t existing_path, new_path;
- if(argc != 2) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 2);
if((posix_errno = efile_marshal_path(env, argv[0], &existing_path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1011,9 +1009,7 @@ static ERL_NIF_TERM make_soft_link_nif(ErlNifEnv *env, int argc, const ERL_NIF_T
efile_path_t existing_path, new_path;
- if(argc != 2) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 2);
if((posix_errno = efile_marshal_path(env, argv[0], &existing_path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1031,9 +1027,7 @@ static ERL_NIF_TERM make_dir_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
efile_path_t path;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1049,9 +1043,7 @@ static ERL_NIF_TERM del_file_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM ar
efile_path_t path;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1067,9 +1059,7 @@ static ERL_NIF_TERM del_dir_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
efile_path_t path;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1086,7 +1076,8 @@ static ERL_NIF_TERM get_device_cwd_nif(ErlNifEnv *env, int argc, const ERL_NIF_T
ERL_NIF_TERM result;
int device_index;
- if(argc != 1 || !enif_get_int(env, argv[0], &device_index)) {
+ ASSERT(argc == 1);
+ if(!enif_get_int(env, argv[0], &device_index)) {
return enif_make_badarg(env);
}
@@ -1101,9 +1092,7 @@ static ERL_NIF_TERM get_cwd_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
posix_errno_t posix_errno;
ERL_NIF_TERM result;
- if(argc != 0) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 0);
if((posix_errno = efile_get_cwd(env, &result))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1117,9 +1106,7 @@ static ERL_NIF_TERM set_cwd_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
efile_path_t path;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1195,9 +1182,7 @@ static ERL_NIF_TERM read_file_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM a
ErlNifBinary result;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
@@ -1223,9 +1208,7 @@ static ERL_NIF_TERM altname_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM arg
efile_path_t path;
ERL_NIF_TERM result;
- if(argc != 1) {
- return enif_make_badarg(env);
- }
+ ASSERT(argc == 1);
if((posix_errno = efile_marshal_path(env, argv[0], &path))) {
return posix_error_to_tuple(env, posix_errno);
diff --git a/erts/emulator/nifs/win32/win_prim_file.c b/erts/emulator/nifs/win32/win_prim_file.c
index f7fae3c637..602a282dd1 100644
--- a/erts/emulator/nifs/win32/win_prim_file.c
+++ b/erts/emulator/nifs/win32/win_prim_file.c
@@ -33,16 +33,32 @@
#define FILE_SHARE_FLAGS (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE)
-#define LP_PREFIX L"\\\\?\\"
-#define LP_PREFIX_SIZE (sizeof(LP_PREFIX) - sizeof(WCHAR))
+/* Long paths can either be in the file (?) or the device (.) namespace. UNC
+ * paths are always in the file namespace. */
+#define LP_FILE_PREFIX L"\\\\?\\"
+#define LP_DEV_PREFIX L"\\\\.\\"
+#define LP_UNC_PREFIX (LP_FILE_PREFIX L"UNC\\")
+
+#define LP_PREFIX_SIZE (sizeof(LP_FILE_PREFIX) - sizeof(WCHAR))
#define LP_PREFIX_LENGTH (LP_PREFIX_SIZE / sizeof(WCHAR))
+#define LP_UNC_PREFIX_SIZE (sizeof(LP_UNC_PREFIX) - sizeof(WCHAR))
+#define LP_UNC_PREFIX_LENGTH (LP_UNC_PREFIX_SIZE / sizeof(WCHAR))
+
+#define IS_LONG_PATH(length, data) \
+ ((length) >= LP_PREFIX_LENGTH && \
+ (!sys_memcmp((data), LP_FILE_PREFIX, LP_PREFIX_SIZE) || \
+ !sys_memcmp((data), LP_DEV_PREFIX, LP_PREFIX_SIZE)))
+
+#define IS_LONG_UNC_PATH(length, data) \
+ ((length) >= LP_UNC_PREFIX_LENGTH && \
+ !sys_memcmp((data), LP_UNC_PREFIX, LP_UNC_PREFIX_SIZE))
+
#define PATH_LENGTH(path) (path->size / sizeof(WCHAR) - 1)
#define ASSERT_PATH_FORMAT(path) \
do { \
- ASSERT(PATH_LENGTH(path) >= 4 && \
- !memcmp(path->data, LP_PREFIX, LP_PREFIX_SIZE)); \
+ ASSERT(IS_LONG_PATH(PATH_LENGTH(path), (path)->data)); \
ASSERT(PATH_LENGTH(path) == wcslen((WCHAR*)path->data)); \
} while(0)
@@ -106,7 +122,7 @@ static posix_errno_t get_full_path(ErlNifEnv *env, WCHAR *input, efile_path_t *r
return ENOENT;
}
- maximum_length += LP_PREFIX_LENGTH;
+ maximum_length += MAX(LP_PREFIX_LENGTH, LP_UNC_PREFIX_LENGTH);
if(!enif_alloc_binary(maximum_length * sizeof(WCHAR), result)) {
return ENOMEM;
@@ -115,18 +131,28 @@ static posix_errno_t get_full_path(ErlNifEnv *env, WCHAR *input, efile_path_t *r
actual_length = GetFullPathNameW(input, maximum_length, (WCHAR*)result->data, NULL);
if(actual_length < maximum_length) {
- int has_long_path_prefix;
+ int is_long_path, maybe_unc_path;
WCHAR *path_start;
- /* Make sure we have a long-path prefix; GetFullPathNameW only adds one
- * if the path is relative. */
- has_long_path_prefix = actual_length >= LP_PREFIX_LENGTH &&
- !sys_memcmp(result->data, LP_PREFIX, LP_PREFIX_SIZE);
-
- if(!has_long_path_prefix) {
+ /* The APIs we use have varying path length limits and sometimes
+ * behave differently when given a long-path prefix, so it's simplest
+ * to always use long paths. */
+
+ is_long_path = IS_LONG_PATH(actual_length, result->data);
+ maybe_unc_path = !sys_memcmp(result->data, L"\\\\", sizeof(WCHAR) * 2);
+
+ if(maybe_unc_path && !is_long_path) {
+ /* \\localhost\c$\gurka -> \\?\UNC\localhost\c$\gurka */
+ sys_memmove(result->data + LP_UNC_PREFIX_SIZE,
+ &((WCHAR*)result->data)[2],
+ (actual_length - 1) * sizeof(WCHAR));
+ sys_memcpy(result->data, LP_UNC_PREFIX, LP_UNC_PREFIX_SIZE);
+ actual_length += LP_UNC_PREFIX_LENGTH;
+ } else if(!is_long_path) {
+ /* C:\gurka -> \\?\C:\gurka */
sys_memmove(result->data + LP_PREFIX_SIZE, result->data,
(actual_length + 1) * sizeof(WCHAR));
- sys_memcpy(result->data, LP_PREFIX, LP_PREFIX_SIZE);
+ sys_memcpy(result->data, LP_FILE_PREFIX, LP_PREFIX_SIZE);
actual_length += LP_PREFIX_LENGTH;
}
@@ -200,13 +226,19 @@ static int normalize_path_result(ErlNifBinary *path) {
ASSERT(length < path->size / sizeof(WCHAR));
/* Get rid of the long-path prefix, if present. */
- if(length >= LP_PREFIX_LENGTH) {
- if(!sys_memcmp(path_start, LP_PREFIX, LP_PREFIX_SIZE)) {
- length -= LP_PREFIX_LENGTH;
- sys_memmove(path_start, &path_start[LP_PREFIX_LENGTH],
- length * sizeof(WCHAR));
- }
+ if(IS_LONG_UNC_PATH(length, path_start)) {
+ /* The first two characters (\\) are the same for both long and short
+ * UNC paths. */
+ sys_memmove(&path_start[2], &path_start[LP_UNC_PREFIX_LENGTH],
+ (length - LP_UNC_PREFIX_LENGTH) * sizeof(WCHAR));
+
+ length -= LP_UNC_PREFIX_LENGTH - 2;
+ } else if(IS_LONG_PATH(length, path_start)) {
+ length -= LP_PREFIX_LENGTH;
+
+ sys_memmove(path_start, &path_start[LP_PREFIX_LENGTH],
+ length * sizeof(WCHAR));
}
path_end = &path_start[length];
@@ -318,49 +350,55 @@ static int has_same_mount_point(const efile_path_t *path_a, const efile_path_t *
/* Mirrors the PathIsRootW function of the shell API, but doesn't choke on
* paths longer than MAX_PATH. */
static int is_path_root(const efile_path_t *path) {
- const WCHAR *path_start, *path_end;
+ const WCHAR *path_start, *path_end, *path_iterator;
int length;
ASSERT_PATH_FORMAT(path);
- path_start = (WCHAR*)path->data + LP_PREFIX_LENGTH;
- length = PATH_LENGTH(path) - LP_PREFIX_LENGTH;
+ if(!IS_LONG_UNC_PATH(PATH_LENGTH(path), path->data)) {
+ path_start = (WCHAR*)path->data + LP_PREFIX_LENGTH;
+ length = PATH_LENGTH(path) - LP_PREFIX_LENGTH;
- path_end = &path_start[length];
-
- if(length == 1) {
/* A single \ refers to the root of the current working directory. */
- return IS_SLASH(path_start[0]);
- } else if(length == 3 && iswalpha(path_start[0]) && path_start[1] == L':') {
- /* Drive letter. */
- return IS_SLASH(path_start[2]);
- } else if(length >= 4) {
- /* Check whether we're a UNC root, eg. \\server, \\server\share */
- const WCHAR *path_iterator;
+ if(length == 1) {
+ return IS_SLASH(path_start[0]);
+ }
- if(!IS_SLASH(path_start[0]) || !IS_SLASH(path_start[1])) {
- return 0;
+ /* Drive letter. */
+ if(length == 3 && iswalpha(path_start[0]) && path_start[1] == L':') {
+ return IS_SLASH(path_start[2]);
}
- path_iterator = path_start + 2;
+ return 0;
+ }
- /* Slide to the slash between the server and share names, if present. */
- while(path_iterator < path_end && !IS_SLASH(*path_iterator)) {
- path_iterator++;
- }
+ /* Check whether we're a UNC root, eg. \\server, \\server\share */
- /* Slide past the end of the string, stopping at the first slash we
- * encounter. */
- do {
- path_iterator++;
- } while(path_iterator < path_end && !IS_SLASH(*path_iterator));
+ path_start = (WCHAR*)path->data + LP_UNC_PREFIX_LENGTH;
+ length = PATH_LENGTH(path) - LP_UNC_PREFIX_LENGTH;
- /* If we're past the end of the string and it didnt't end with a slash,
- * then we're a root path. */
- return path_iterator >= path_end && !IS_SLASH(path_start[length - 1]);
+ path_end = &path_start[length];
+ path_iterator = path_start;
+
+ /* Server name must be at least one character. */
+ if(length <= 1) {
+ return 0;
}
- return 0;
+ /* Slide to the slash between the server and share names, if present. */
+ while(path_iterator < path_end && !IS_SLASH(*path_iterator)) {
+ path_iterator++;
+ }
+
+ /* Slide past the end of the string, stopping at the first slash we
+ * encounter. */
+ do {
+ path_iterator++;
+ } while(path_iterator < path_end && !IS_SLASH(*path_iterator));
+
+ /* If we're past the end of the string and it didnt't end with a slash,
+ * then we're a root path. */
+ return path_iterator >= path_end && !IS_SLASH(path_start[length - 1]);
}
posix_errno_t efile_open(const efile_path_t *path, enum efile_modes_t modes,
@@ -687,7 +725,7 @@ static int is_name_surrogate(const efile_path_t *path) {
if(handle != INVALID_HANDLE_VALUE) {
REPARSE_GUID_DATA_BUFFER reparse_buffer;
- LPDWORD unused_length;
+ DWORD unused_length;
BOOL success;
success = DeviceIoControl(handle,
@@ -1248,11 +1286,22 @@ posix_errno_t efile_set_cwd(const efile_path_t *path) {
/* We have to use _wchdir since that's the only function that updates the
* per-drive working directory, but it naively assumes that all paths
- * starting with \\ are UNC paths, so we have to skip the \\?\-prefix. */
- path_start = (WCHAR*)path->data + LP_PREFIX_LENGTH;
+ * starting with \\ are UNC paths, so we have to skip the long-path prefix.
+ *
+ * _wchdir doesn't handle long-prefixed UNC paths either so we hand those
+ * to SetCurrentDirectoryW instead. The per-drive working directory is
+ * irrelevant for such paths anyway. */
- if(_wchdir(path_start)) {
- return windows_to_posix_errno(GetLastError());
+ if(!IS_LONG_UNC_PATH(PATH_LENGTH(path), path->data)) {
+ path_start = (WCHAR*)path->data + LP_PREFIX_LENGTH;
+
+ if(_wchdir(path_start)) {
+ return windows_to_posix_errno(GetLastError());
+ }
+ } else {
+ if(!SetCurrentDirectoryW((WCHAR*)path->data)) {
+ return windows_to_posix_errno(GetLastError());
+ }
}
return 0;
@@ -1333,7 +1382,7 @@ posix_errno_t efile_altname(ErlNifEnv *env, const efile_path_t *path, ERL_NIF_TE
int name_length;
/* Reject path wildcards. */
- if(wcspbrk(&((const WCHAR*)path->data)[4], L"?*")) {
+ if(wcspbrk(&((const WCHAR*)path->data)[LP_PREFIX_LENGTH], L"?*")) {
return ENOENT;
}
diff --git a/erts/emulator/pcre/LICENCE b/erts/emulator/pcre/LICENCE
new file mode 100644
index 0000000000..f6ef7fd766
--- /dev/null
+++ b/erts/emulator/pcre/LICENCE
@@ -0,0 +1,93 @@
+PCRE LICENCE
+------------
+
+PCRE is a library of functions to support regular expressions whose syntax
+and semantics are as close as possible to those of the Perl 5 language.
+
+Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
+specified below. The documentation for PCRE, supplied in the "doc"
+directory, is distributed under the same terms as the software itself. The data
+in the testdata directory is not copyrighted and is in the public domain.
+
+The basic library functions are written in C and are freestanding. Also
+included in the distribution is a set of C++ wrapper functions, and a
+just-in-time compiler that can be used to optimize pattern matching. These
+are both optional features that can be omitted when the library is built.
+
+
+THE BASIC LIBRARY FUNCTIONS
+---------------------------
+
+Written by: Philip Hazel
+Email local part: ph10
+Email domain: cam.ac.uk
+
+University of Cambridge Computing Service,
+Cambridge, England.
+
+Copyright (c) 1997-2018 University of Cambridge
+All rights reserved.
+
+
+PCRE JUST-IN-TIME COMPILATION SUPPORT
+-------------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2010-2018 Zoltan Herczeg
+All rights reserved.
+
+
+STACK-LESS JUST-IN-TIME COMPILER
+--------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2009-2018 Zoltan Herczeg
+All rights reserved.
+
+
+THE C++ WRAPPER FUNCTIONS
+-------------------------
+
+Contributed by: Google Inc.
+
+Copyright (c) 2007-2012, Google Inc.
+All rights reserved.
+
+
+THE "BSD" LICENCE
+-----------------
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the name of Google
+ Inc. nor the names of their contributors may be used to endorse or
+ promote products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+
+End
diff --git a/erts/emulator/pcre/README.pcre_update.md b/erts/emulator/pcre/README.pcre_update.md
index 599e3d0d12..5df1e15bde 100644
--- a/erts/emulator/pcre/README.pcre_update.md
+++ b/erts/emulator/pcre/README.pcre_update.md
@@ -723,6 +723,12 @@ requires thorough reading of all new text. For the upgrade from 7.6
to 8.33, the update of the pcrepattern part of our manual page took
about eight hours.
+## Update Licence
+
+Copy the LICENCE file to `erts/emulator/pcre/LICENCE` and update
+the `[PCRE]` section in `system/COPYRIGHT` with the content of
+the `LICENCE` file.
+
## Add new relevant options to re
Then, when all this is done, you should add any new relevant options
diff --git a/erts/emulator/pcre/local_config.h b/erts/emulator/pcre/local_config.h
index c6af423d72..c3b4dab586 100644
--- a/erts/emulator/pcre/local_config.h
+++ b/erts/emulator/pcre/local_config.h
@@ -86,4 +86,4 @@
#define SUPPORT_UTF
/* Version number of package */
-#define VERSION "8.41"
+#define VERSION "8.42"
diff --git a/erts/emulator/pcre/pcre-8.41.tar.bz2 b/erts/emulator/pcre/pcre-8.41.tar.bz2
deleted file mode 100644
index 1798432dc9..0000000000
--- a/erts/emulator/pcre/pcre-8.41.tar.bz2
+++ /dev/null
Binary files differ
diff --git a/erts/emulator/pcre/pcre-8.42.tar.bz2 b/erts/emulator/pcre/pcre-8.42.tar.bz2
new file mode 100644
index 0000000000..61bfa38970
--- /dev/null
+++ b/erts/emulator/pcre/pcre-8.42.tar.bz2
Binary files differ
diff --git a/erts/emulator/pcre/pcre.h b/erts/emulator/pcre/pcre.h
index ab8f40cfc1..3563791223 100644
--- a/erts/emulator/pcre/pcre.h
+++ b/erts/emulator/pcre/pcre.h
@@ -43,9 +43,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */
#define PCRE_MAJOR 8
-#define PCRE_MINOR 41
+#define PCRE_MINOR 42
#define PCRE_PRERELEASE
-#define PCRE_DATE 2017-07-05
+#define PCRE_DATE 2018-03-20
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
@@ -328,11 +328,11 @@ these bits, just add new ones on the end, in order to remain compatible. */
/* Types */
-struct real_pcre; /* declaration; the definition is private */
-typedef struct real_pcre pcre;
+struct real_pcre8_or_16; /* declaration; the definition is private */
+typedef struct real_pcre8_or_16 pcre;
-struct real_pcre16; /* declaration; the definition is private */
-typedef struct real_pcre16 pcre16;
+struct real_pcre8_or_16; /* declaration; the definition is private */
+typedef struct real_pcre8_or_16 pcre16;
struct real_pcre32; /* declaration; the definition is private */
typedef struct real_pcre32 pcre32;
diff --git a/erts/emulator/pcre/pcre_chartables.c b/erts/emulator/pcre/pcre_chartables.c
index b3d9020f25..06482c08d2 100644
--- a/erts/emulator/pcre/pcre_chartables.c
+++ b/erts/emulator/pcre/pcre_chartables.c
@@ -19,7 +19,9 @@ array definition from the final binary if PCRE is built into a static library
and dead code stripping is activated. This leads to link errors. Pulling in the
header ensures that the array gets flagged as "someone outside this compilation
unit might reference this" and so it will always be supplied to the linker. */
+
/* %ExternalCopyright% */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
diff --git a/erts/emulator/pcre/pcre_compile.c b/erts/emulator/pcre/pcre_compile.c
index e79284ab79..ae7f6e2a2a 100644
--- a/erts/emulator/pcre/pcre_compile.c
+++ b/erts/emulator/pcre/pcre_compile.c
@@ -8061,7 +8061,7 @@ for (;; ptr++)
single group (i.e. not to a duplicated name. */
HANDLE_REFERENCE:
- if (firstcharflags == REQ_UNSET) firstcharflags = REQ_NONE;
+ if (firstcharflags == REQ_UNSET) zerofirstcharflags = firstcharflags = REQ_NONE;
previous = code;
item_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = ((options & PCRE_CASELESS) != 0)? OP_REFI : OP_REF;
diff --git a/erts/emulator/pcre/pcre_dfa_exec.c b/erts/emulator/pcre/pcre_dfa_exec.c
index c859d67fc7..c101656fd7 100644
--- a/erts/emulator/pcre/pcre_dfa_exec.c
+++ b/erts/emulator/pcre/pcre_dfa_exec.c
@@ -2288,12 +2288,14 @@ for (;;)
case OP_NOTI:
if (clen > 0)
{
- unsigned int otherd;
+ pcre_uint32 otherd;
#ifdef SUPPORT_UTF
if (utf && d >= 128)
{
#ifdef SUPPORT_UCP
otherd = UCD_OTHERCASE(d);
+#else
+ otherd = d;
#endif /* SUPPORT_UCP */
}
else
diff --git a/erts/emulator/pcre/pcre_exec.c b/erts/emulator/pcre/pcre_exec.c
index 6708ba92a6..1946e97a72 100644
--- a/erts/emulator/pcre/pcre_exec.c
+++ b/erts/emulator/pcre/pcre_exec.c
@@ -6,7 +6,7 @@
and semantics are as close as possible to those of the Perl 5 language.
Written by Philip Hazel
- Copyright (c) 1997-2014 University of Cambridge
+ Copyright (c) 1997-2018 University of Cambridge
-----------------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
@@ -2407,7 +2407,7 @@ for (;;)
case OP_ANY:
if (IS_NEWLINE(eptr)) RRETURN(MATCH_NOMATCH);
if (md->partial != 0 &&
- eptr + 1 >= md->end_subject &&
+ eptr == md->end_subject - 1 &&
NLBLOCK->nltype == NLTYPE_FIXED &&
NLBLOCK->nllen == 2 &&
UCHAR21TEST(eptr) == NLBLOCK->nl[0])
@@ -3167,7 +3167,7 @@ for (;;)
{
RMATCH(eptr, ecode, offset_top, md, eptrb, RM18);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- if (eptr-- == pp) break; /* Stop if tried at original pos */
+ if (eptr-- <= pp) break; /* Stop if tried at original pos */
BACKCHAR(eptr);
}
}
@@ -3326,7 +3326,7 @@ for (;;)
{
RMATCH(eptr, ecode, offset_top, md, eptrb, RM21);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
- if (eptr-- == pp) break; /* Stop if tried at original pos */
+ if (eptr-- <= pp) break; /* Stop if tried at original pos */
#ifdef SUPPORT_UTF
if (utf) BACKCHAR(eptr);
#endif
diff --git a/erts/emulator/pcre/pcre_jit_compile.c b/erts/emulator/pcre/pcre_jit_compile.c
index 932ca2c389..926e40f6d3 100644
--- a/erts/emulator/pcre/pcre_jit_compile.c
+++ b/erts/emulator/pcre/pcre_jit_compile.c
@@ -164,7 +164,6 @@ typedef struct jit_arguments {
const pcre_uchar *begin;
const pcre_uchar *end;
int *offsets;
- pcre_uchar *uchar_ptr;
pcre_uchar *mark_ptr;
void *callout_data;
/* Everything else after. */
@@ -214,7 +213,7 @@ enum control_types {
type_then_trap = 1
};
-typedef int (SLJIT_CALL *jit_function)(jit_arguments *args);
+typedef int (SLJIT_FUNC *jit_function)(jit_arguments *args);
/* The following structure is the key data type for the recursive
code generator. It is allocated by compile_matchingpath, and contains
@@ -489,9 +488,24 @@ typedef struct compare_context {
/* Used for accessing the elements of the stack. */
#define STACK(i) ((i) * (int)sizeof(sljit_sw))
+#ifdef SLJIT_PREF_SHIFT_REG
+#if SLJIT_PREF_SHIFT_REG == SLJIT_R2
+/* Nothing. */
+#elif SLJIT_PREF_SHIFT_REG == SLJIT_R3
+#define SHIFT_REG_IS_R3
+#else
+#error "Unsupported shift register"
+#endif
+#endif
+
#define TMP1 SLJIT_R0
+#ifdef SHIFT_REG_IS_R3
+#define TMP2 SLJIT_R3
+#define TMP3 SLJIT_R2
+#else
#define TMP2 SLJIT_R2
#define TMP3 SLJIT_R3
+#endif
#define STR_PTR SLJIT_S0
#define STR_END SLJIT_S1
#define STACK_TOP SLJIT_R1
@@ -520,13 +534,10 @@ the start pointers when the end of the capturing group has not yet reached. */
#if defined COMPILE_PCRE8
#define MOV_UCHAR SLJIT_MOV_U8
-#define MOVU_UCHAR SLJIT_MOVU_U8
#elif defined COMPILE_PCRE16
#define MOV_UCHAR SLJIT_MOV_U16
-#define MOVU_UCHAR SLJIT_MOVU_U16
#elif defined COMPILE_PCRE32
#define MOV_UCHAR SLJIT_MOV_U32
-#define MOVU_UCHAR SLJIT_MOVU_U32
#else
#error Unsupported compiling mode
#endif
@@ -2383,12 +2394,25 @@ if (length < 8)
}
else
{
- GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START);
- OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
- loop = LABEL();
- OP1(SLJIT_MOVU, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw), SLJIT_R0, 0);
- OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, loop);
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START);
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, SLJIT_R0, SLJIT_MEM1(SLJIT_R1), sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ else
+ {
+ GET_LOCAL_BASE(SLJIT_R1, 0, OVECTOR_START + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_IMM, length - 1);
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), 0, SLJIT_R0, 0);
+ OP2(SLJIT_ADD, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
}
}
@@ -2421,12 +2445,25 @@ if (length < 8)
}
else
{
- GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw));
- OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
- loop = LABEL();
- OP1(SLJIT_MOVU, SLJIT_MEM1(TMP2), sizeof(sljit_sw), TMP1, 0);
- OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
- JUMPTO(SLJIT_NOT_ZERO, loop);
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw)) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_STORE | SLJIT_MEM_PRE, TMP1, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
+ else
+ {
+ GET_LOCAL_BASE(TMP2, 0, OVECTOR_START + 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, length - 2);
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_MEM1(TMP2), 0, TMP1, 0);
+ OP2(SLJIT_ADD, TMP2, 0, TMP2, 0, SLJIT_IMM, sizeof(sljit_sw));
+ OP2(SLJIT_SUB | SLJIT_SET_Z, STACK_TOP, 0, STACK_TOP, 0, SLJIT_IMM, 1);
+ JUMPTO(SLJIT_NOT_ZERO, loop);
+ }
}
OP1(SLJIT_MOV, STACK_TOP, 0, ARGUMENTS, 0);
@@ -2436,10 +2473,10 @@ if (common->control_head_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr, SLJIT_IMM, 0);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->start_ptr);
-OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, base));
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(STACK_TOP), SLJIT_OFFSETOF(struct sljit_stack, end));
}
-static sljit_sw SLJIT_CALL do_search_mark(sljit_sw *current, const pcre_uchar *skip_arg)
+static sljit_sw SLJIT_FUNC do_search_mark(sljit_sw *current, const pcre_uchar *skip_arg)
{
while (current != NULL)
{
@@ -2460,7 +2497,7 @@ while (current != NULL)
SLJIT_ASSERT(current[0] == 0 || current < (sljit_sw*)current[0]);
current = (sljit_sw*)current[0];
}
-return -1;
+return 0;
}
static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
@@ -2468,6 +2505,7 @@ static SLJIT_INLINE void copy_ovector(compiler_common *common, int topbracket)
DEFINE_COMPILER;
struct sljit_label *loop;
struct sljit_jump *early_quit;
+BOOL has_pre;
/* At this point we can freely use all registers. */
OP1(SLJIT_MOV, SLJIT_S2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(1));
@@ -2481,17 +2519,30 @@ if (common->mark_ptr != 0)
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, mark_ptr), SLJIT_R2, 0);
OP2(SLJIT_SUB, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, offsets), SLJIT_IMM, sizeof(int));
OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, begin));
-GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START);
+
+has_pre = sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw)) == SLJIT_SUCCESS;
+GET_LOCAL_BASE(SLJIT_S0, 0, OVECTOR_START - (has_pre ? sizeof(sljit_sw) : 0));
+
/* Unlikely, but possible */
early_quit = CMP(SLJIT_EQUAL, SLJIT_R1, 0, SLJIT_IMM, 0);
loop = LABEL();
-OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0, SLJIT_R0, 0);
-OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw));
+
+if (has_pre)
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_S1, SLJIT_MEM1(SLJIT_S0), sizeof(sljit_sw));
+else
+ {
+ OP1(SLJIT_MOV, SLJIT_S1, 0, SLJIT_MEM1(SLJIT_S0), 0);
+ OP2(SLJIT_ADD, SLJIT_S0, 0, SLJIT_S0, 0, SLJIT_IMM, sizeof(sljit_sw));
+ }
+
+OP2(SLJIT_ADD, SLJIT_R2, 0, SLJIT_R2, 0, SLJIT_IMM, sizeof(int));
+OP2(SLJIT_SUB, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_R0, 0);
/* Copy the integer value to the output buffer */
#if defined COMPILE_PCRE16 || defined COMPILE_PCRE32
OP2(SLJIT_ASHR, SLJIT_S1, 0, SLJIT_S1, 0, SLJIT_IMM, UCHAR_SHIFT);
#endif
-OP1(SLJIT_MOVU_S32, SLJIT_MEM1(SLJIT_R2), sizeof(int), SLJIT_S1, 0);
+
+OP1(SLJIT_MOV_S32, SLJIT_MEM1(SLJIT_R2), 0, SLJIT_S1, 0);
OP2(SLJIT_SUB | SLJIT_SET_Z, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
JUMPTO(SLJIT_NOT_ZERO, loop);
JUMPHERE(early_quit);
@@ -2499,14 +2550,29 @@ JUMPHERE(early_quit);
/* Calculate the return value, which is the maximum ovector value. */
if (topbracket > 1)
{
- GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw));
- OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+ if (sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw))) == SLJIT_SUCCESS)
+ {
+ GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + topbracket * 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
- /* OVECTOR(0) is never equal to SLJIT_S2. */
- loop = LABEL();
- OP1(SLJIT_MOVU, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw)));
- OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
- CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+ /* OVECTOR(0) is never equal to SLJIT_S2. */
+ loop = LABEL();
+ sljit_emit_mem(compiler, SLJIT_MOV | SLJIT_MEM_PRE, SLJIT_R2, SLJIT_MEM1(SLJIT_R0), -(2 * (sljit_sw)sizeof(sljit_sw)));
+ OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+ CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+ }
+ else
+ {
+ GET_LOCAL_BASE(SLJIT_R0, 0, OVECTOR_START + (topbracket - 1) * 2 * sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R1, 0, SLJIT_IMM, topbracket + 1);
+
+ /* OVECTOR(0) is never equal to SLJIT_S2. */
+ loop = LABEL();
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_R0), 0);
+ OP2(SLJIT_SUB, SLJIT_R0, 0, SLJIT_R0, 0, SLJIT_IMM, 2 * (sljit_sw)sizeof(sljit_sw));
+ OP2(SLJIT_SUB, SLJIT_R1, 0, SLJIT_R1, 0, SLJIT_IMM, 1);
+ CMPTO(SLJIT_EQUAL, SLJIT_R2, 0, SLJIT_S2, 0, loop);
+ }
OP1(SLJIT_MOV, SLJIT_RETURN_REG, 0, SLJIT_R1, 0);
}
else
@@ -5167,93 +5233,190 @@ OP_FLAGS(SLJIT_OR | SLJIT_SET_Z, TMP2, 0, SLJIT_EQUAL);
sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
}
-#define CHAR1 STR_END
-#define CHAR2 STACK_TOP
-
static void do_casefulcmp(compiler_common *common)
{
DEFINE_COMPILER;
struct sljit_jump *jump;
struct sljit_label *label;
+int char1_reg;
+int char2_reg;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+if (sljit_get_register_index(TMP3) < 0)
+ {
+ char1_reg = STR_END;
+ char2_reg = STACK_TOP;
+ }
+else
+ {
+ char1_reg = TMP3;
+ char2_reg = RETURN_ADDR;
+ }
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
-OP1(SLJIT_MOV, TMP3, 0, CHAR1, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, CHAR2, 0);
-OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
-OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-label = LABEL();
-OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1));
-OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
-jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
-OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
-JUMPTO(SLJIT_NOT_ZERO, label);
+if (char1_reg == STR_END)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, char1_reg, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, char2_reg, 0);
+ }
-JUMPHERE(jump);
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-OP1(SLJIT_MOV, CHAR1, 0, TMP3, 0);
-OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
-sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
-}
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ {
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ }
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
-#define LCC_TABLE STACK_LIMIT
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
+else
+ {
+ label = LABEL();
+ OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+ OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+ jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
+ OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
+ JUMPTO(SLJIT_NOT_ZERO, label);
+
+ JUMPHERE(jump);
+ OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ }
+
+if (char1_reg == STR_END)
+ {
+ OP1(SLJIT_MOV, char1_reg, 0, TMP3, 0);
+ OP1(SLJIT_MOV, char2_reg, 0, RETURN_ADDR, 0);
+ }
+
+sljit_emit_fast_return(compiler, TMP1, 0);
+}
static void do_caselesscmp(compiler_common *common)
{
DEFINE_COMPILER;
struct sljit_jump *jump;
struct sljit_label *label;
+int char1_reg = STR_END;
+int char2_reg;
+int lcc_table;
+int opt_type = 0;
-sljit_emit_fast_enter(compiler, RETURN_ADDR, 0);
+if (sljit_get_register_index(TMP3) < 0)
+ {
+ char2_reg = STACK_TOP;
+ lcc_table = STACK_LIMIT;
+ }
+else
+ {
+ char2_reg = RETURN_ADDR;
+ lcc_table = TMP3;
+ }
+
+if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ opt_type = 1;
+else if (sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_SUPP | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1)) == SLJIT_SUCCESS)
+ opt_type = 2;
+
+sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, TMP2, 0);
-OP1(SLJIT_MOV, TMP3, 0, LCC_TABLE, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, CHAR1, 0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, CHAR2, 0);
-OP1(SLJIT_MOV, LCC_TABLE, 0, SLJIT_IMM, common->lcc);
-OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
-OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, char1_reg, 0);
+
+if (char2_reg == STACK_TOP)
+ {
+ OP1(SLJIT_MOV, TMP3, 0, char2_reg, 0);
+ OP1(SLJIT_MOV, RETURN_ADDR, 0, lcc_table, 0);
+ }
+
+OP1(SLJIT_MOV, lcc_table, 0, SLJIT_IMM, common->lcc);
+
+if (opt_type == 1)
+ {
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_POST, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ }
+else if (opt_type == 2)
+ {
+ OP2(SLJIT_SUB, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ OP2(SLJIT_SUB, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+ label = LABEL();
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char1_reg, SLJIT_MEM1(TMP1), IN_UCHARS(1));
+ sljit_emit_mem(compiler, MOV_UCHAR | SLJIT_MEM_PRE, char2_reg, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
+ }
+else
+ {
+ label = LABEL();
+ OP1(MOV_UCHAR, char1_reg, 0, SLJIT_MEM1(TMP1), 0);
+ OP1(MOV_UCHAR, char2_reg, 0, SLJIT_MEM1(STR_PTR), 0);
+ OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, IN_UCHARS(1));
+ }
-label = LABEL();
-OP1(MOVU_UCHAR, CHAR1, 0, SLJIT_MEM1(TMP1), IN_UCHARS(1));
-OP1(MOVU_UCHAR, CHAR2, 0, SLJIT_MEM1(STR_PTR), IN_UCHARS(1));
#ifndef COMPILE_PCRE8
-jump = CMP(SLJIT_GREATER, CHAR1, 0, SLJIT_IMM, 255);
+jump = CMP(SLJIT_GREATER, char1_reg, 0, SLJIT_IMM, 255);
#endif
-OP1(SLJIT_MOV_U8, CHAR1, 0, SLJIT_MEM2(LCC_TABLE, CHAR1), 0);
+OP1(SLJIT_MOV_U8, char1_reg, 0, SLJIT_MEM2(lcc_table, char1_reg), 0);
#ifndef COMPILE_PCRE8
JUMPHERE(jump);
-jump = CMP(SLJIT_GREATER, CHAR2, 0, SLJIT_IMM, 255);
+jump = CMP(SLJIT_GREATER, char2_reg, 0, SLJIT_IMM, 255);
#endif
-OP1(SLJIT_MOV_U8, CHAR2, 0, SLJIT_MEM2(LCC_TABLE, CHAR2), 0);
+OP1(SLJIT_MOV_U8, char2_reg, 0, SLJIT_MEM2(lcc_table, char2_reg), 0);
#ifndef COMPILE_PCRE8
JUMPHERE(jump);
#endif
-jump = CMP(SLJIT_NOT_EQUAL, CHAR1, 0, CHAR2, 0);
+
+if (opt_type == 0)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
+
+jump = CMP(SLJIT_NOT_EQUAL, char1_reg, 0, char2_reg, 0);
OP2(SLJIT_SUB | SLJIT_SET_Z, TMP2, 0, TMP2, 0, SLJIT_IMM, IN_UCHARS(1));
JUMPTO(SLJIT_NOT_ZERO, label);
JUMPHERE(jump);
-OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-OP1(SLJIT_MOV, LCC_TABLE, 0, TMP3, 0);
-OP1(SLJIT_MOV, CHAR1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
-OP1(SLJIT_MOV, CHAR2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
-sljit_emit_fast_return(compiler, RETURN_ADDR, 0);
-}
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+
+if (opt_type == 2)
+ OP2(SLJIT_ADD, STR_PTR, 0, STR_PTR, 0, SLJIT_IMM, IN_UCHARS(1));
-#undef LCC_TABLE
-#undef CHAR1
-#undef CHAR2
+if (char2_reg == STACK_TOP)
+ {
+ OP1(SLJIT_MOV, char2_reg, 0, TMP3, 0);
+ OP1(SLJIT_MOV, lcc_table, 0, RETURN_ADDR, 0);
+ }
+
+OP1(SLJIT_MOV, char1_reg, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+sljit_emit_fast_return(compiler, TMP1, 0);
+}
#if defined SUPPORT_UTF && defined SUPPORT_UCP
-static const pcre_uchar * SLJIT_CALL do_utf_caselesscmp(pcre_uchar *src1, jit_arguments *args, pcre_uchar *end1)
+static const pcre_uchar * SLJIT_FUNC do_utf_caselesscmp(pcre_uchar *src1, pcre_uchar *src2, pcre_uchar *end1, pcre_uchar *end2)
{
/* This function would be ineffective to do in JIT level. */
sljit_u32 c1, c2;
-const pcre_uchar *src2 = args->uchar_ptr;
-const pcre_uchar *end2 = args->end;
const ucd_record *ur;
const sljit_u32 *pp;
@@ -6776,32 +6939,37 @@ else
#if defined SUPPORT_UTF && defined SUPPORT_UCP
if (common->utf && *cc == OP_REFI)
{
- SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1 && TMP2 == SLJIT_R2);
+ SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1);
if (ref)
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(SLJIT_SP), OVECTOR(offset + 1));
else
- OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
+ OP1(SLJIT_MOV, SLJIT_R2, 0, SLJIT_MEM1(TMP2), sizeof(sljit_sw));
if (withchecks)
- jump = CMP(SLJIT_EQUAL, TMP1, 0, TMP2, 0);
+ jump = CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_R2, 0);
- /* Needed to save important temporary registers. */
+ /* No free saved registers so save data on stack. */
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
- OP1(SLJIT_MOV, SLJIT_R1, 0, ARGUMENTS, 0);
- OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_R1), SLJIT_OFFSETOF(jit_arguments, uchar_ptr), STR_PTR, 0);
- sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp));
+ OP1(SLJIT_MOV, SLJIT_R1, 0, STR_PTR, 0);
+ OP1(SLJIT_MOV, SLJIT_R3, 0, STR_END, 0);
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW) | SLJIT_ARG4(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_utf_caselesscmp));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
+
if (common->mode == JIT_COMPILE)
add_jump(compiler, backtracks, CMP(SLJIT_LESS_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1));
else
{
- add_jump(compiler, backtracks, CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0));
- nopartial = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
+ OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_LESS, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 1);
+
+ add_jump(compiler, backtracks, JUMP(SLJIT_LESS));
+
+ nopartial = JUMP(SLJIT_NOT_EQUAL);
+ OP1(SLJIT_MOV, STR_PTR, 0, STR_END, 0);
check_partial(common, FALSE);
add_jump(compiler, backtracks, JUMP(SLJIT_JUMP));
JUMPHERE(nopartial);
}
- OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_RETURN_REG, 0);
}
else
#endif /* SUPPORT_UTF && SUPPORT_UCP */
@@ -7125,7 +7293,7 @@ add_jump(compiler, &backtrack->topbacktracks, CMP(SLJIT_EQUAL, TMP1, 0, SLJIT_IM
return cc + 1 + LINK_SIZE;
}
-static int SLJIT_CALL do_callout(struct jit_arguments *arguments, PUBL(callout_block) *callout_block, pcre_uchar **jit_ovector)
+static sljit_s32 SLJIT_FUNC do_callout(struct jit_arguments *arguments, PUBL(callout_block) *callout_block, pcre_uchar **jit_ovector)
{
const pcre_uchar *begin = arguments->begin;
int *offset_vector = arguments->offsets;
@@ -7207,18 +7375,17 @@ OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
/* SLJIT_R0 = arguments */
OP1(SLJIT_MOV, SLJIT_R1, 0, STACK_TOP, 0);
GET_LOCAL_BASE(SLJIT_R2, 0, OVECTOR_START);
-sljit_emit_ijump(compiler, SLJIT_CALL3, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout));
-OP1(SLJIT_MOV_S32, SLJIT_RETURN_REG, 0, SLJIT_RETURN_REG, 0);
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(S32) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW) | SLJIT_ARG3(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_callout));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
free_stack(common, CALLOUT_ARG_SIZE / sizeof(sljit_sw));
/* Check return value. */
-OP2(SLJIT_SUB | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
-add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER));
+OP2(SLJIT_SUB32 | SLJIT_SET_Z | SLJIT_SET_SIG_GREATER, SLJIT_UNUSED, 0, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+add_jump(compiler, &backtrack->topbacktracks, JUMP(SLJIT_SIG_GREATER32));
if (common->forced_quit_label == NULL)
- add_jump(compiler, &common->forced_quit, JUMP(SLJIT_NOT_EQUAL) /* SIG_LESS */);
+ add_jump(compiler, &common->forced_quit, JUMP(SLJIT_NOT_EQUAL32) /* SIG_LESS */);
else
- JUMPTO(SLJIT_NOT_EQUAL /* SIG_LESS */, common->forced_quit_label);
+ JUMPTO(SLJIT_NOT_EQUAL32 /* SIG_LESS */, common->forced_quit_label);
return cc + 2 + 2 * LINK_SIZE;
}
@@ -10439,11 +10606,11 @@ if (opcode == OP_SKIP_ARG)
OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), common->control_head_ptr);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS0, STACK_TOP, 0);
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_IMM, (sljit_sw)(current->cc + 2));
- sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark));
+ sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(do_search_mark));
OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
OP1(SLJIT_MOV, STR_PTR, 0, TMP1, 0);
- add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, -1));
+ add_jump(compiler, &common->reset_match, CMP(SLJIT_NOT_EQUAL, STR_PTR, 0, SLJIT_IMM, 0));
return;
}
@@ -11031,7 +11198,7 @@ if (!compiler)
common->compiler = compiler;
/* Main pcre_jit_exec entry. */
-sljit_emit_enter(compiler, 0, 1, 5, 5, 0, 0, private_data_size);
+sljit_emit_enter(compiler, 0, SLJIT_ARG1(SW), 5, 5, 0, 0, private_data_size);
/* Register init. */
reset_ovector(common, (re->top_bracket + 1) * 2);
@@ -11044,8 +11211,8 @@ OP1(SLJIT_MOV, STR_PTR, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, str))
OP1(SLJIT_MOV, STR_END, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, end));
OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
OP1(SLJIT_MOV_U32, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, limit_match));
-OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, base));
-OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, limit));
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, end));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP2), SLJIT_OFFSETOF(struct sljit_stack, start));
OP2(SLJIT_ADD, TMP1, 0, TMP1, 0, SLJIT_IMM, 1);
OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LIMIT_MATCH, TMP1, 0);
@@ -11251,20 +11418,22 @@ common->quit_label = quit_label;
set_jumps(common->stackalloc, LABEL());
/* RETURN_ADDR is not a saved register. */
sljit_emit_fast_enter(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
-OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, TMP2, 0);
-OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
-OP1(SLJIT_MOV, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top), STACK_TOP, 0);
-OP2(SLJIT_SUB, TMP2, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit), SLJIT_IMM, STACK_GROWTH_RATE);
-sljit_emit_ijump(compiler, SLJIT_CALL2, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
-jump = CMP(SLJIT_NOT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
-OP1(SLJIT_MOV, TMP1, 0, ARGUMENTS, 0);
-OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(jit_arguments, stack));
-OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, top));
-OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_MEM1(TMP1), SLJIT_OFFSETOF(struct sljit_stack, limit));
-OP1(SLJIT_MOV, TMP2, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
-sljit_emit_fast_return(compiler, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+SLJIT_ASSERT(TMP1 == SLJIT_R0 && STACK_TOP == SLJIT_R1);
+
+OP1(SLJIT_MOV, SLJIT_MEM1(SLJIT_SP), LOCALS1, STACK_TOP, 0);
+OP1(SLJIT_MOV, SLJIT_R0, 0, ARGUMENTS, 0);
+OP2(SLJIT_SUB, SLJIT_R1, 0, STACK_LIMIT, 0, SLJIT_IMM, STACK_GROWTH_RATE);
+OP1(SLJIT_MOV, SLJIT_R0, 0, SLJIT_MEM1(SLJIT_R0), SLJIT_OFFSETOF(jit_arguments, stack));
+OP1(SLJIT_MOV, STACK_LIMIT, 0, TMP2, 0);
+
+sljit_emit_icall(compiler, SLJIT_CALL, SLJIT_RET(SW) | SLJIT_ARG1(SW) | SLJIT_ARG2(SW), SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_stack_resize));
+jump = CMP(SLJIT_EQUAL, SLJIT_RETURN_REG, 0, SLJIT_IMM, 0);
+OP1(SLJIT_MOV, TMP2, 0, STACK_LIMIT, 0);
+OP1(SLJIT_MOV, STACK_LIMIT, 0, SLJIT_RETURN_REG, 0);
+OP1(SLJIT_MOV, TMP1, 0, SLJIT_MEM1(SLJIT_SP), LOCALS0);
+OP1(SLJIT_MOV, STACK_TOP, 0, SLJIT_MEM1(SLJIT_SP), LOCALS1);
+sljit_emit_fast_return(compiler, TMP1, 0);
/* Allocation failed. */
JUMPHERE(jump);
@@ -11409,9 +11578,9 @@ union {
sljit_u8 local_space[MACHINE_STACK_SIZE];
struct sljit_stack local_stack;
-local_stack.max_limit = local_space;
-local_stack.limit = local_space;
-local_stack.base = local_space + MACHINE_STACK_SIZE;
+local_stack.min_start = local_space;
+local_stack.start = local_space;
+local_stack.end = local_space + MACHINE_STACK_SIZE;
local_stack.top = local_space + MACHINE_STACK_SIZE;
arguments->stack = &local_stack;
convert_executable_func.executable_func = executable_func;
@@ -11536,7 +11705,7 @@ if ((options & PCRE_PARTIAL_HARD) != 0)
else if ((options & PCRE_PARTIAL_SOFT) != 0)
mode = JIT_PARTIAL_SOFT_COMPILE;
-if (functions->executable_funcs[mode] == NULL)
+if (functions == NULL || functions->executable_funcs[mode] == NULL)
return PCRE_ERROR_JIT_BADOPTION;
/* Sanity checks should be handled by pcre_exec. */
diff --git a/erts/emulator/pcre/pcre_latin_1_table.c b/erts/emulator/pcre/pcre_latin_1_table.c
index aa29275a94..d6cf38fa3b 100644
--- a/erts/emulator/pcre/pcre_latin_1_table.c
+++ b/erts/emulator/pcre/pcre_latin_1_table.c
@@ -14,6 +14,7 @@ Pulling in the header ensures that the array gets flagged as "someone
outside this compilation unit might reference this" and so it will always
be supplied to the linker. */
/* %ExternalCopyright% */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -120,7 +121,7 @@ print, punct, and cntrl. Other classes are built from combinations. */
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xfe,0xff,0xff,0x07,
- 0x00,0x00,0x00,0x00,0x00,0x00,0x20,0x00,
+ 0x00,0x00,0x00,0x00,0x00,0x04,0x20,0x04,
0x00,0x00,0x00,0x80,0xff,0xff,0x7f,0xff,
0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x03,
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index b03e19ee71..f421794f91 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -1507,7 +1507,6 @@ send_event_tuple(struct erts_nif_select_event* e, ErtsResource* resource,
}
tuple = TUPLE4(hp, am_select, resource_term, ref_term, event_atom);
- ERL_MESSAGE_TOKEN(mp) = am_undefined;
erts_queue_message(rp, rp_locks, mp, tuple, am_system);
if (rp_locks)
diff --git a/erts/emulator/sys/common/erl_osenv.c b/erts/emulator/sys/common/erl_osenv.c
index 487ff87116..6a16377736 100644
--- a/erts/emulator/sys/common/erl_osenv.c
+++ b/erts/emulator/sys/common/erl_osenv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2017. All Rights Reserved.
+ * Copyright Ericsson AB 2017-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 70b5532af9..b4d1575ee5 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -803,6 +803,23 @@ update_pollset(ErtsPollSet *ps, int fd, ErtsPollOp op, ErtsPollEvents events)
struct kevent evts[2];
struct timespec ts = {0, 0};
+ if (op == ERTS_POLL_OP_ADD) {
+ /* This is a hack to make the "noshell" option work; kqueue can poll
+ * these fds but will not report EV_EOF, so we return NVAL to use the
+ * fallback instead.
+ *
+ * This may be common to all pipes but we have no way to tell whether
+ * an fd is a pipe or not. */
+ switch (fd) {
+ case STDIN_FILENO:
+ case STDOUT_FILENO:
+ case STDERR_FILENO:
+ return ERTS_POLL_EV_NVAL;
+ default:
+ break;
+ }
+ }
+
#if defined(EV_DISPATCH) && !defined(__OpenBSD__)
/* If we have EV_DISPATCH we use it, unless we are on OpenBSD as the
behavior of EV_EOF seems to be edge triggered there and we need it
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index 2541ab5d31..d34e1a9ec0 100644
--- a/erts/emulator/sys/common/erl_sys_common_misc.c
+++ b/erts/emulator/sys/common/erl_sys_common_misc.c
@@ -176,6 +176,7 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals,
double af;
Uint64 int_part, frac_part;
int neg;
+ int has_decimals = decimals != 0;
char *p = buffer;
if (decimals < 0)
@@ -257,7 +258,7 @@ sys_double_to_chars_fast(double f, char *buffer, int buffer_size, int decimals,
}
/* Delete trailing zeroes */
- if (compact)
+ if (compact && has_decimals)
p = find_first_trailing_zero(p);
*p = '\0';
return p - buffer;
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 221ee2a69d..129861ebd5 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -133,6 +133,7 @@ static int sigchld_pipe[2];
static int
start_new_child(int pipes[])
{
+ struct sigaction sa;
int errln = -1;
int size, res, i, pos = 0;
char *buff, *o_buff;
@@ -143,6 +144,16 @@ start_new_child(int pipes[])
/* only child executes here */
+ /* Restore default handling of sigterm... */
+ sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGTERM, &sa, 0) == -1) {
+ perror(NULL);
+ exit(1);
+ }
+
do {
res = read(pipes[0], (char*)&size, sizeof(size));
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 189ca083d7..4823e549ea 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -452,9 +452,9 @@ prepare_crash_dump(int secs)
envsz = sizeof(env);
i = erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_NICE", env, &envsz);
- if (i >= 0) {
+ if (i != 0) {
int nice_val;
- nice_val = i != 1 ? 0 : atoi(env);
+ nice_val = (i != 1) ? 0 : atoi(env);
if (nice_val > 39) {
nice_val = 39;
}
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 872c3a80b1..816bdea9c5 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -685,7 +685,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
/* we send the request to do the fork */
if ((res = writev(ofd[1], io_vector, iov_len > MAXIOV ? MAXIOV : iov_len)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
res = 0;
} else {
int err = errno;
@@ -1000,7 +1000,7 @@ static void clear_fd_data(ErtsSysFdData *fdd)
static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd)
{
- driver_select(prt, abs(fdd->fd), DO_READ|DO_WRITE, 0);
+ driver_select(prt, abs(fdd->fd), ERL_DRV_USE_NO_CALLBACK|DO_READ|DO_WRITE, 0);
clear_fd_data(fdd);
SET_BLOCKING(abs(fdd->fd));
@@ -1257,6 +1257,8 @@ static int port_inp_failure(ErtsSysDriverData *dd, int res)
}
driver_failure_eof(dd->port_num);
} else if (dd->ifd) {
+ if (dd->alive == -1)
+ errno = dd->status;
erl_drv_init_ack(dd->port_num, ERL_DRV_ERROR_ERRNO);
} else {
driver_failure_posix(dd->port_num, err);
@@ -1287,10 +1289,10 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
int res;
if((res = read(ready_fd, &proto, sizeof(proto))) <= 0) {
+ if (res < 0 && (errno == ERRNO_BLOCK || errno == EINTR))
+ return;
/* hmm, child setup seems to have closed the pipe too early...
we close the port as there is not much else we can do */
- if (res < 0 && errno == ERRNO_BLOCK)
- return;
driver_select(port_num, ready_fd, ERL_DRV_READ, 0);
if (res == 0)
errno = EPIPE;
@@ -1424,7 +1426,7 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
continue;
}
else { /* The last message we got was split */
- char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
+ char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
if (!buf) {
errno = ENOMEM;
port_inp_failure(dd, -1);
@@ -1670,15 +1672,37 @@ static void forker_stop(ErlDrvData e)
the port has been closed by the user. */
}
+static ErlDrvSizeT forker_deq(ErlDrvPort port_num, ErtsSysForkerProto *proto)
+{
+ close(proto->u.start.fds[0]);
+ close(proto->u.start.fds[1]);
+ if (proto->u.start.fds[1] != proto->u.start.fds[2])
+ close(proto->u.start.fds[2]);
+
+ return driver_deq(port_num, sizeof(*proto));
+}
+
+static void forker_sigchld(Eterm port_id, int error)
+{
+ ErtsSysForkerProto *proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
+ proto->action = ErtsSysForkerProtoAction_SigChld;
+ proto->u.sigchld.error_number = error;
+ proto->u.sigchld.port_id = port_id;
+
+ /* ideally this would be a port_command call, but as command is
+ already used by the spawn_driver, we use control instead.
+ Note that when using erl_drv_port_control it is an asynchronous
+ control. */
+ erl_drv_port_control(port_id, 'S', (char*)proto, sizeof(*proto));
+}
+
static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
{
int res;
- ErtsSysForkerProto *proto;
+ ErtsSysForkerProto proto;
- proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
-
- if ((res = read(fd, proto, sizeof(*proto))) < 0) {
- if (errno == ERRNO_BLOCK)
+ if ((res = read(fd, &proto, sizeof(proto))) < 0) {
+ if (errno == ERRNO_BLOCK || errno == EINTR)
return;
erts_exit(ERTS_DUMP_EXIT, "Failed to read from erl_child_setup: %d\n", errno);
}
@@ -1686,10 +1710,10 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
if (res == 0)
erts_exit(ERTS_DUMP_EXIT, "erl_child_setup closed\n");
- ASSERT(res == sizeof(*proto));
+ ASSERT(res == sizeof(proto));
#ifdef FORKER_PROTO_START_ACK
- if (proto->action == ErtsSysForkerProtoAction_StartAck) {
+ if (proto.action == ErtsSysForkerProtoAction_StartAck) {
/* Ideally we would like to not have to ack each Start
command being sent over the uds, but it would seem
that some operating systems (only observed on FreeBSD)
@@ -1699,28 +1723,15 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
- ErtsSysForkerProto *proto = (ErtsSysForkerProto *)iov[0].iov_base;
-
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
+ ErtsSysForkerProto *qproto = (ErtsSysForkerProto *)iov[0].iov_base;
- driver_deq(port_num, sizeof(*proto));
-
- if (driver_sizeq(port_num) > 0)
+ if (forker_deq(port_num, qproto))
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
} else
#endif
{
- ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
-
- /* ideally this would be a port_command call, but as command is
- already used by the spawn_driver, we use control instead.
- Note that when using erl_drv_port_control it is an asynchronous
- control. */
- erl_drv_port_control(proto->u.sigchld.port_id, 'S',
- (char*)proto, sizeof(*proto));
+ ASSERT(proto.action == ErtsSysForkerProtoAction_SigChld);
+ forker_sigchld(proto.u.sigchld.port_id, proto.u.sigchld.error_number);
}
}
@@ -1730,7 +1741,8 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
#ifndef FORKER_PROTO_START_ACK
- while (driver_sizeq(port_num) > 0) {
+ int loops = 10;
+ while (driver_sizeq(port_num) > 0 && --loops) {
#endif
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
@@ -1738,20 +1750,24 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ASSERT(iov[0].iov_len >= (sizeof(*proto)));
if (sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0) < 0) {
- if (errno == ERRNO_BLOCK)
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
return;
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+ return;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ }
}
#ifndef FORKER_PROTO_START_ACK
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
}
-#endif
-
+#else
driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+#endif
}
static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
@@ -1777,20 +1793,21 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
if ((res = sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
return 0;
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ forker_deq(port_num, proto);
+ return 0;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
#ifndef FORKER_PROTO_START_ACK
ASSERT(res == sizeof(*proto));
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ forker_deq(port_num, proto);
#endif
return 0;
diff --git a/erts/emulator/sys/unix/sys_uds.c b/erts/emulator/sys/unix/sys_uds.c
index c328fd00bb..c9f73622ba 100644
--- a/erts/emulator/sys/unix/sys_uds.c
+++ b/erts/emulator/sys/unix/sys_uds.c
@@ -88,8 +88,9 @@ sys_uds_readv(int fd, struct iovec *iov, size_t iov_len,
if((msg.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
{
/* We assume that we have given enough space for any header
- that are sent to us. So the only remaining reason to get
- this flag set is if the caller has run out of file descriptors.
+ that are sent to us. So the only remaining reasons to get
+ this flag set is if the caller has run out of file descriptors
+ or an SELinux policy prunes the response (eg. O_APPEND on STDERR).
*/
errno = EMFILE;
return -1;
@@ -132,7 +133,7 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
struct msghdr msg;
struct cmsghdr *cmsg = NULL;
- int res, i;
+ int res, i, error;
/* initialize socket message */
memset(&msg, 0, sizeof(struct msghdr));
@@ -173,11 +174,22 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
res = sendmsg(fd, &msg, flags);
+#ifdef ETOOMANYREFS
+ /* Linux may give ETOOMANYREFS when there are too many fds in transit.
+ We map this to EMFILE as bsd and other use this error code and we want
+ the behaviour to be the same on all OSs */
+ if (errno == ETOOMANYREFS)
+ errno = EMFILE;
+#endif
+ error = errno;
+
if (iov_len > MAXIOV)
free(iov[0].iov_base);
free(msg.msg_control);
+ errno = error;
+
return res;
}
diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c
index fd4c745c3b..39bb4d515e 100644
--- a/erts/emulator/sys/win32/erl_poll.c
+++ b/erts/emulator/sys/win32/erl_poll.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2007-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2007-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -362,11 +362,11 @@ is_io_ready(ErtsPollSet *ps)
}
static ERTS_INLINE void
-woke_up(ErtsPollSet *ps)
+woke_up(ErtsPollSet *ps, int waketype)
{
if (erts_atomic32_read_nob(&ps->wakeup_state) == ERTS_POLL_NOT_WOKEN)
erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
- ERTS_POLL_WOKEN_TIMEDOUT,
+ waketype,
ERTS_POLL_NOT_WOKEN);
#ifdef DEBUG
{
@@ -960,12 +960,12 @@ static int cancel_driver_select(ErtsPollSet *ps, HANDLE event)
void erts_poll_interrupt(ErtsPollSet *ps, int set /* bool */)
{
- HARDTRACEF(("In erts_poll_interrupt(%d)",set));
+ HARDTRACEF(("In erts_poll_interrupt(%p, %d)",ps,set));
if (!set)
reset_interrupt(ps);
else
set_interrupt(ps);
- HARDTRACEF(("Out erts_poll_interrupt(%d)",set));
+ HARDTRACEF(("Out erts_poll_interrupt(%p, %d)",ps,set));
}
@@ -1051,19 +1051,20 @@ int erts_poll_wait(ErtsPollSet *ps,
if (!erts_atomic32_read_nob(&break_waiter_state)) {
HANDLE harr[2] = {ps->event_io_ready, break_happened_event};
- int num_h = 2;
+ int num_h = 2, handle;
ERTS_MSACC_PUSH_STATE();
HARDDEBUGF(("Start waiting %d [%d]",num_h, (int) timeout));
ERTS_POLLSET_UNLOCK(ps);
erts_thr_progress_prepare_wait(NULL);
ERTS_MSACC_SET_STATE_CACHED(ERTS_MSACC_STATE_SLEEP);
- WaitForMultipleObjects(num_h, harr, FALSE, timeout);
+ handle = WaitForMultipleObjects(num_h, harr, FALSE, timeout);
erts_thr_progress_finalize_wait(NULL);
ERTS_MSACC_POP_STATE();
ERTS_POLLSET_LOCK(ps);
HARDDEBUGF(("Stop waiting %d [%d]",num_h, (int) timeout));
- woke_up(ps);
+ if (handle == WAIT_OBJECT_0)
+ woke_up(ps, ERTS_POLL_WOKEN_TIMEDOUT);
}
ERTS_UNSET_BREAK_REQUESTED;
@@ -1075,7 +1076,10 @@ int erts_poll_wait(ErtsPollSet *ps,
erts_mtx_unlock(&break_waiter_lock);
switch (break_state) {
case BREAK_WAITER_GOT_BREAK:
+ woke_up(ps, ERTS_POLL_WOKEN_INTR);
ERTS_SET_BREAK_REQUESTED;
+ /* Wake aux thread to get handle break */
+ erts_aux_thread_poke();
break;
case BREAK_WAITER_GOT_HALT:
erts_exit(0,"");
diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl
index d19f7f81ad..742592f88e 100644
--- a/erts/emulator/test/call_trace_SUITE.erl
+++ b/erts/emulator/test/call_trace_SUITE.erl
@@ -1395,7 +1395,7 @@ seq(M, N, R) when M =< N ->
seq(M, N-1, [N|R]);
seq(_, _, R) -> R.
-%% lists:reverse can not be called since it is traced
+%% lists:reverse cannot be called since it is traced
reverse(L) ->
reverse(L, []).
%%
diff --git a/erts/emulator/test/code_SUITE.erl b/erts/emulator/test/code_SUITE.erl
index 9c6dc3ff83..493c6ebe99 100644
--- a/erts/emulator/test/code_SUITE.erl
+++ b/erts/emulator/test/code_SUITE.erl
@@ -28,7 +28,7 @@
fake_literals/1,
false_dependency/1,coverage/1,fun_confusion/1,
t_copy_literals/1, t_copy_literals_frags/1,
- erl_544/1]).
+ erl_544/1, max_heap_size/1]).
-define(line_trace, 1).
-include_lib("common_test/include/ct.hrl").
@@ -43,7 +43,7 @@ all() ->
constant_pools, constant_refc_binaries, fake_literals,
false_dependency,
coverage, fun_confusion, t_copy_literals, t_copy_literals_frags,
- erl_544].
+ erl_544, max_heap_size].
init_per_suite(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
@@ -332,6 +332,7 @@ constant_pools(Config) when is_list(Config) ->
A = literals:a(),
B = literals:b(),
C = literals:huge_bignum(),
+ D = literals:funs(),
process_flag(trap_exit, true),
Self = self(),
@@ -345,7 +346,7 @@ constant_pools(Config) when is_list(Config) ->
true = erlang:purge_module(literals),
NoOldHeap ! done,
receive
- {'EXIT',NoOldHeap,{A,B,C}} ->
+ {'EXIT',NoOldHeap,{A,B,C,D}} ->
ok;
Other ->
ct:fail({unexpected,Other})
@@ -362,7 +363,7 @@ constant_pools(Config) when is_list(Config) ->
erlang:purge_module(literals),
OldHeap ! done,
receive
- {'EXIT',OldHeap,{A,B,C,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
+ {'EXIT',OldHeap,{A,B,C,D,[1,2,3|_]=Seq}} when length(Seq) =:= 16 ->
ok
end,
@@ -390,7 +391,7 @@ constant_pools(Config) when is_list(Config) ->
{'DOWN', Mon, process, Hib, Reason} ->
{undef, [{no_module,
no_function,
- [{A,B,C,[1,2,3|_]=Seq}], _}]} = Reason,
+ [{A,B,C,D,[1,2,3|_]=Seq}], _}]} = Reason,
16 = length(Seq)
end,
HeapSz = TotHeapSz, %% Ensure restored to hibernated state...
@@ -400,7 +401,9 @@ constant_pools(Config) when is_list(Config) ->
no_old_heap(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum()},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D},
Parent ! go,
receive
done ->
@@ -410,7 +413,9 @@ no_old_heap(Parent) ->
old_heap(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum(),lists:seq(1, 16)},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D,lists:seq(1, 16)},
create_old_heap(),
Parent ! go,
receive
@@ -421,7 +426,9 @@ old_heap(Parent) ->
hibernated(Parent) ->
A = literals:a(),
B = literals:b(),
- Res = {A,B,literals:huge_bignum(),lists:seq(1, 16)},
+ C = literals:huge_bignum(),
+ D = literals:funs(),
+ Res = {A,B,C,D,lists:seq(1, 16)},
Parent ! go,
erlang:hibernate(no_module, no_function, [Res]).
@@ -755,7 +762,8 @@ t_copy_literals_frags(Config) when is_list(Config) ->
0, 1, 2, 3, 4, 5, 6, 7,
8, 9,10,11,12,13,14,15,
0, 1, 2, 3, 4, 5, 6, 7,
- 8, 9,10,11,12,13,14,15>>}]),
+ 8, 9,10,11,12,13,14,15>>},
+ {f, fun ?MODULE:all/0}]),
{module, ?mod} = erlang:load_module(?mod, Bin),
N = 6000,
@@ -796,6 +804,7 @@ literal_receiver() ->
C = ?mod:c(),
D = ?mod:d(),
E = ?mod:e(),
+ F = ?mod:f(),
literal_receiver();
{Pid, sender_confirm} ->
io:format("sender confirm ~w~n", [Pid]),
@@ -811,7 +820,8 @@ literal_sender(N, Recv) ->
?mod:b(),
?mod:c(),
?mod:d(),
- ?mod:e()]},
+ ?mod:e(),
+ ?mod:f()]},
literal_sender(N - 1, Recv).
literal_switcher() ->
@@ -968,6 +978,39 @@ erl_544(Config) when is_list(Config) ->
{skipped, "Only run when native file name encoding is utf8"}
end.
+%% Test that the copying of literals to a process during purging of
+%% literals will cause the process to be killed if the max heap size
+%% is exceeded.
+max_heap_size(_Config) ->
+ Mod = ?FUNCTION_NAME,
+ Value = [I || I <- lists:seq(1, 5000)],
+ Code = gen_lit(Mod, [{term,Value}]),
+ {module,Mod} = erlang:load_module(Mod, Code),
+ SpawnOpts = [monitor,
+ {max_heap_size,
+ #{size=>1024,
+ kill=>true,
+ error_logger=>true}}],
+ {Pid,Ref} = spawn_opt(fun() ->
+ max_heap_size_proc(Mod)
+ end, SpawnOpts),
+ receive
+ {'DOWN',Ref,process,Pid,Reason} ->
+ killed = Reason;
+ Other ->
+ ct:fail({unexpected_message,Other})
+ after 10000 ->
+ ct:fail({process_did_not_die, Pid, erlang:process_info(Pid)})
+ end.
+
+max_heap_size_proc(Mod) ->
+ Value = Mod:term(),
+ code:delete(Mod),
+ code:purge(Mod),
+ receive
+ _ -> Value
+ end.
+
%% Utilities.
make_sub_binary(Bin) when is_binary(Bin) ->
diff --git a/erts/emulator/test/code_SUITE_data/literals.erl b/erts/emulator/test/code_SUITE_data/literals.erl
index 7c3b0ebe73..13c8b412b0 100644
--- a/erts/emulator/test/code_SUITE_data/literals.erl
+++ b/erts/emulator/test/code_SUITE_data/literals.erl
@@ -19,7 +19,8 @@
%%
-module(literals).
--export([a/0,b/0,huge_bignum/0,binary/0,unused_binaries/0,bits/0]).
+-export([a/0,b/0,huge_bignum/0,funs/0,
+ binary/0,unused_binaries/0,bits/0]).
-export([msg1/0,msg2/0,msg3/0,msg4/0,msg5/0]).
a() ->
@@ -108,3 +109,8 @@ msg2() -> {"hello","world"}.
msg3() -> <<"halloj">>.
msg4() -> #{ 1=> "hello", b => "world"}.
msg5() -> {1,2,3,4,5,6}.
+
+funs() ->
+ %% Literal funs (in a non-literal list).
+ [fun ?MODULE:a/0,
+ fun() -> ok end]. %No environment.
diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl
index bb76e6f24b..9ffb484eb4 100644
--- a/erts/emulator/test/driver_SUITE.erl
+++ b/erts/emulator/test/driver_SUITE.erl
@@ -81,6 +81,7 @@
thr_msg_blast/1,
consume_timeslice/1,
env/1,
+ poll_pipe/1,
z_test/1]).
-export([bin_prefix/2]).
@@ -168,6 +169,7 @@ all() -> %% Keep a_test first and z_test last...
thr_msg_blast,
consume_timeslice,
env,
+ poll_pipe,
z_test].
groups() ->
@@ -2676,3 +2678,25 @@ rpc(Config, Fun) ->
ct:fail(Other)
end
end.
+
+poll_pipe(Config) when is_list(Config) ->
+ %% ERL-647; we wouldn't see any events on EOF when polling a pipe using
+ %% kqueue(2).
+ case os:type() of
+ {unix, _} ->
+ Command = "erl -noshell -eval "
+ "'\"DATA\n\" = io:get_line(\"\"),"
+ "eof = io:get_line(\"\"),"
+ "halt()' <<< 'DATA'",
+ Ref = make_ref(),
+ Self = self(),
+ Pid = spawn(fun() -> os:cmd(Command), Self ! Ref end),
+ receive
+ Ref -> ok
+ after 5000 ->
+ exit(Pid, kill),
+ ct:fail("Stuck reading from stdin.")
+ end;
+ _ ->
+ {skipped, "Unix-only test"}
+ end.
diff --git a/erts/emulator/test/fun_SUITE.erl b/erts/emulator/test/fun_SUITE.erl
index 73fe9b0d8f..f8a879182e 100644
--- a/erts/emulator/test/fun_SUITE.erl
+++ b/erts/emulator/test/fun_SUITE.erl
@@ -576,7 +576,7 @@ refc_dist(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Pid = spawn_link(Node, fun() -> receive
Fun when is_function(Fun) ->
- 2 = fun_refc(Fun),
+ 3 = fun_refc(Fun),
exit({normal,Fun}) end
end),
F = fun() -> 42 end,
@@ -598,7 +598,7 @@ refc_dist_send(Node, F) ->
Pid = spawn_link(Node, fun() -> receive
{To,Fun} when is_function(Fun) ->
wait_until(fun () ->
- 2 =:= fun_refc(Fun)
+ 3 =:= fun_refc(Fun)
end),
To ! Fun
end
@@ -626,7 +626,7 @@ refc_dist_reg_send(Node, F) ->
Me ! Ref,
receive
{Me,Fun} when is_function(Fun) ->
- 2 = fun_refc(Fun),
+ 3 = fun_refc(Fun),
Me ! Fun
end
end),
@@ -806,11 +806,13 @@ verify_not_undef(Fun, Tag) ->
ct:fail("tag ~w not defined in fun_info", [Tag]);
{Tag,_} -> ok
end.
-
+
id(X) ->
X.
spawn_call(Node, AFun) ->
+ Parent = self(),
+ Init = erlang:whereis(init),
Pid = spawn_link(Node,
fun() ->
receive
@@ -821,8 +823,10 @@ spawn_call(Node, AFun) ->
_ -> lists:seq(0, Arity-1)
end,
Res = apply(Fun, Args),
- {pid,Creator} = erlang:fun_info(Fun, pid),
- Creator ! {result,Res}
+ case erlang:fun_info(Fun, pid) of
+ {pid,Init} -> Parent ! {result,Res};
+ {pid,Creator} -> Creator ! {result,Res}
+ end
end
end),
Pid ! {AFun,AFun,AFun},
diff --git a/erts/emulator/test/map_SUITE.erl b/erts/emulator/test/map_SUITE.erl
index f93c637650..d0a6763fe5 100644
--- a/erts/emulator/test/map_SUITE.erl
+++ b/erts/emulator/test/map_SUITE.erl
@@ -3080,8 +3080,19 @@ y_regs(Config) when is_list(Config) ->
true = is_map(Map2) andalso is_map(Map4),
+ gurka = y_regs_literal(0),
+ gaffel = y_regs_literal(1),
+
ok.
+y_regs_literal(Key) when is_integer(Key) ->
+ %% Forces the key to be placed in a Y register.
+ lists:seq(1, 2),
+ case is_map_key(Key, #{ 0 => 0 }) of
+ true -> gurka;
+ false -> gaffel
+ end.
+
y_regs_update(Map0, Val0) ->
Val1 = {t,Val0},
K1 = id({key,1}),
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index 87cf7bf81d..edad62a9fb 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -45,8 +45,9 @@
api_macros/1,
from_array/1, iolist_as_binary/1, resource/1, resource_binary/1,
resource_takeover/1,
- threading/1, send/1, send2/1, send3/1, send_threaded/1, neg/1,
- is_checks/1,
+ threading/1, send/1, send2/1, send3/1, send_threaded/1,
+ send_trace/1, send_seq_trace/1,
+ neg/1, is_checks/1,
get_length/1, make_atom/1, make_string/1, reverse_list_test/1,
otp_9828/1,
otp_9668/1, consume_timeslice/1, nif_schedule/1,
@@ -1809,6 +1810,59 @@ send(Config) when is_list(Config) ->
{ok,0} = send_list_seq(7, DeadPid),
ok.
+
+%% Test tracing of enif_send
+send_trace(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ Papa = self(),
+ N = 1500,
+ List = lists:seq(1,N),
+
+ Tracer = spawn_link(fun F() -> receive get -> Papa ! receive_any(), F() end end),
+
+ erlang:trace(self(), true, [send,'receive',{tracer,Tracer}]),
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+ Tracer ! get,
+ {trace,Papa,send,List,Papa} = receive_any(),
+ Tracer ! get,
+ {trace,Papa,'receive',List} = receive_any().
+
+%% Test that seq_trace works with nif trace
+send_seq_trace(Config) when is_list(Config) ->
+ ensure_lib_loaded(Config),
+
+ Papa = self(),
+ N = 1500,
+ List = lists:seq(1,N),
+ Label = make_ref(),
+
+ Tracer = spawn_link(fun F() -> receive get -> Papa ! receive_any(), F() end end),
+
+ seq_trace:set_system_tracer(Tracer),
+ seq_trace:set_token(label,Label),
+ seq_trace:set_token(send,true),
+ seq_trace:set_token('receive',true),
+
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+ {ok,1} = send_list_seq(N, self()),
+ List = receive_any(),
+ timeout = receive_any(0),
+
+ Tracer ! get,
+ {seq_trace,Label,{send,{0,1},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{'receive',{0,1},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{send,{1,2},Papa,Papa,List}} = receive_any(),
+ Tracer ! get,
+ {seq_trace,Label,{'receive',{1,2},Papa,Papa,List}} = receive_any().
+
+
%% More NIF message sending
send2(Config) when is_list(Config) ->
ensure_lib_loaded(Config),
diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl
index 7df001fec5..300b4ed036 100644
--- a/erts/emulator/test/node_container_SUITE.erl
+++ b/erts/emulator/test/node_container_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -50,7 +50,8 @@
bad_nc/1,
unique_pid/1,
iter_max_procs/1,
- magic_ref/1]).
+ magic_ref/1,
+ dist_entry_gc/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -58,7 +59,7 @@ suite() ->
all() ->
- [term_to_binary_to_term_eq, round_trip_eq, cmp, ref_eq,
+ [dist_entry_gc, term_to_binary_to_term_eq, round_trip_eq, cmp, ref_eq,
node_table_gc, dist_link_refc, dist_monitor_refc,
node_controller_refc, ets_refc, match_spec_refc,
timer_refc, pid_wrap, port_wrap, bad_nc,
@@ -894,6 +895,29 @@ magic_ref(Config) when is_list(Config) ->
true = is_reference(MRef2),
true = erts_debug:get_internal_state({magic_ref,MRef2}),
ok.
+
+
+lost_pending_connection(Node) ->
+ _ = (catch erts_internal:new_connection(Node)),
+ ok.
+
+dist_entry_gc(Config) when is_list(Config) ->
+ Me = self(),
+ {ok, Node} = start_node(get_nodefirstname(), "+zdntgc 0"),
+ P = spawn_link(Node,
+ fun () ->
+ LostNode = list_to_atom("lost_pending_connection@" ++ hostname()),
+ lost_pending_connection(LostNode),
+ garbage_collect(), %% Could crash...
+ Me ! {self(), ok}
+ end),
+ receive
+ {P, ok} -> ok
+ end,
+ unlink(P),
+ stop_node(Node),
+ ok.
+
%%
%% -- Internal utils ---------------------------------------------------------
%%
diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl
index 700734cd0b..f15217814a 100644
--- a/erts/emulator/test/num_bif_SUITE.erl
+++ b/erts/emulator/test/num_bif_SUITE.erl
@@ -161,6 +161,7 @@ t_float_to_string(Config) when is_list(Config) ->
test_fts("1.000",1.0, [{decimals, 3}]),
test_fts("1.0",1.0, [{decimals, 1}]),
test_fts("1.0",1.0, [{decimals, 3}, compact]),
+ test_fts("10",10.0, [{decimals, 0}, compact]),
test_fts("1.12",1.123, [{decimals, 2}]),
test_fts("1.123",1.123, [{decimals, 3}]),
test_fts("1.123",1.123, [{decimals, 3}, compact]),
diff --git a/erts/emulator/test/ref_SUITE.erl b/erts/emulator/test/ref_SUITE.erl
index 5f519d522e..925c30caa5 100644
--- a/erts/emulator/test/ref_SUITE.erl
+++ b/erts/emulator/test/ref_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,6 +22,7 @@
-export([all/0, suite/0]).
-export([wrap_1/1]).
+-export([compare_list/1, compare_ets/1]).
-export([loop_ref/1]).
@@ -32,7 +33,7 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [wrap_1].
+ [wrap_1, compare_list, compare_ets].
%% Check that refs don't wrap around easily.
wrap_1(Config) when is_list(Config) ->
@@ -53,3 +54,28 @@ loop_ref(Parent) ->
loop_ref(R, R, _) -> ok;
loop_ref(R0, _, N) ->
loop_ref(R0, make_ref(), N+1).
+
+%% Check that ref ordering works
+compare_list(Config) when is_list(Config) ->
+ %% Although this test uses external refs, it would apply the same to plain refs
+ ExtRef1 = <<131,114,0,3,100,0,3,110,64,98,3, 0,0,173,156, 0,216,0,4, 0,0,0,0>>,
+ ExtRef2 = <<131,114,0,3,100,0,3,110,64,98,3, 0,1,31,27, 129,4,0,1, 0,0,0,0>>,
+
+ Ref1 = binary_to_term(ExtRef1), %% #Ref<[email protected]>
+ Ref2 = binary_to_term(ExtRef2), %% #Ref<[email protected]>
+ OrderedList = [Ref1, Ref2],
+ OrderedList = lists:sort(OrderedList),
+ ok.
+
+%% This is the scarier case since it makes terms "invisible" in ets or Mnesia
+%% (the underlying fault cause is the same as compare_list/1)
+compare_ets(Config) when is_list(Config) ->
+ W2s = [610350147,899574699,2994196869,686384822,2397690439, 923302211],
+ ExtRefBase = <<131,114,0,3,100,0,3,110,64,98,3>>,
+ ExtRefs = [<<ExtRefBase/binary, 1:32, W2:32, 0:32>> || W2 <- W2s],
+ Refs = [binary_to_term(Bin) || Bin <- ExtRefs],
+
+ Ets = ets:new(refbug, [ordered_set]),
+ ets:insert(Ets, [{Ref,Ref} || Ref <- Refs]),
+ 0 = length([R || R <- ets:tab2list(Ets), ets:lookup(Ets, element(1,R)) == []]),
+ ok.
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index 7eebbe8b19..f04efb9003 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -2155,7 +2155,7 @@ workers_exit([Ps|Pss]) ->
workers_exit(Pss).
do_work(PartTime) ->
- lists:reverse(lists:seq(1, 50)),
+ _ = id(lists:seq(1, 50)),
receive stop_work -> receive after infinity -> ok end after 0 -> ok end,
case PartTime of
true -> receive after 1 -> ok end;
@@ -2163,6 +2163,8 @@ do_work(PartTime) ->
end,
do_work(PartTime).
+id(I) -> I.
+
workers(N, _Prio, _PartTime) when N =< 0 ->
[];
workers(N, Prio, PartTime) ->
diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl
index 26c610e3a8..5b46342127 100644
--- a/erts/emulator/test/smoke_test_SUITE.erl
+++ b/erts/emulator/test/smoke_test_SUITE.erl
@@ -56,7 +56,7 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
%%%
boot_combo(Config) when is_list(Config) ->
- ZFlags = os:getenv("ERL_ZFLAGS"),
+ ZFlags = os:getenv("ERL_ZFLAGS", ""),
NOOP = fun () -> ok end,
A42 = fun () ->
case erlang:system_info(threads) of
@@ -87,10 +87,7 @@ boot_combo(Config) when is_list(Config) ->
%% A lot more combos could be implemented...
ok
after
- os:putenv("ERL_ZFLAGS", case ZFlags of
- false -> "";
- _ -> ZFlags
- end)
+ os:putenv("ERL_ZFLAGS", ZFlags)
end.
native_atomics(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl
index fc11a04a31..15fe13c8c0 100644
--- a/erts/emulator/test/timer_bif_SUITE.erl
+++ b/erts/emulator/test/timer_bif_SUITE.erl
@@ -361,7 +361,7 @@ evil_timers(Config) when is_list(Config) ->
%%
%% 1. A timer started with erlang:start_timer(Time, Receiver, Msg),
%% where Msg is a composite term, expires, and the receivers main
- %% lock *can not* be acquired immediately (typically when the
+ %% lock *cannot* be acquired immediately (typically when the
%% receiver *is* running).
%%
%% The wrap tuple ({timeout, TRef, Msg}) will in this case
@@ -372,7 +372,7 @@ evil_timers(Config) when is_list(Config) ->
RecvTimeOutMsgs0 = evil_recv_timeouts(200),
%% 2. A timer started with erlang:start_timer(Time, Receiver, Msg),
%% where Msg is an immediate term, expires, and the receivers main
- %% lock *can not* be acquired immediately (typically when the
+ %% lock *cannot* be acquired immediately (typically when the
%% receiver *is* running).
%%
%% The wrap tuple will in this case be allocated in a new
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index 979b3185a5..c2d5cd7023 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -39,7 +39,7 @@
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
system_monitor_long_schedule/1,
bad_flag/1, trace_delivered/1, trap_exit_self_receive/1,
- trace_info_badarg/1]).
+ trace_info_badarg/1, erl_704/1]).
-include_lib("common_test/include/ct.hrl").
@@ -63,7 +63,7 @@ all() ->
system_monitor_long_gc_2, system_monitor_large_heap_1,
system_monitor_long_schedule,
system_monitor_large_heap_2, bad_flag, trace_delivered,
- trap_exit_self_receive, trace_info_badarg].
+ trap_exit_self_receive, trace_info_badarg, erl_704].
init_per_testcase(_Case, Config) ->
[{receiver,spawn(fun receiver/0)}|Config].
@@ -1739,6 +1739,21 @@ trace_info_badarg(Config) when is_list(Config) ->
catch erlang:trace_info({a,b,c},d),
ok.
+%% An incoming suspend monitor down wasn't handled
+%% correct when the local monitor half had been
+%% removed with an emulator crash as result.
+erl_704(Config) ->
+ erl_704_test(100).
+
+erl_704_test(0) ->
+ ok;
+erl_704_test(N) ->
+ P = spawn(fun () -> receive infinity -> ok end end),
+ erlang:suspend_process(P),
+ exit(P, kill),
+ (catch erlang:resume_process(P)),
+ erl_704_test(N-1).
+
drop_trace_until_down(Proc, Mon) ->
drop_trace_until_down(Proc, Mon, false, 0, 0).
diff --git a/erts/emulator/zlib/adler32.c b/erts/emulator/zlib/adler32.c
index c693a42b7c..d0be4380a3 100644
--- a/erts/emulator/zlib/adler32.c
+++ b/erts/emulator/zlib/adler32.c
@@ -1,20 +1,15 @@
/* adler32.c -- compute the Adler-32 checksum of a data stream
- * Copyright (C) 1995-2011 Mark Adler
+ * Copyright (C) 1995-2011, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "zutil.h"
-#define local static
-
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
-#define BASE 65521 /* largest prime smaller than 65536 */
+#define BASE 65521U /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
@@ -65,10 +60,10 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
#endif
/* ========================================================================= */
-uLong ZEXPORT adler32(adler, buf, len)
+uLong ZEXPORT adler32_z(adler, buf, len)
uLong adler;
const Bytef *buf;
- uInt len;
+ z_size_t len;
{
unsigned long sum2;
unsigned n;
@@ -136,6 +131,15 @@ uLong ZEXPORT adler32(adler, buf, len)
}
/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ return adler32_z(adler, buf, len);
+}
+
+/* ========================================================================= */
local uLong adler32_combine_(adler1, adler2, len2)
uLong adler1;
uLong adler2;
@@ -159,7 +163,7 @@ local uLong adler32_combine_(adler1, adler2, len2)
sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
if (sum1 >= BASE) sum1 -= BASE;
if (sum1 >= BASE) sum1 -= BASE;
- if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1);
if (sum2 >= BASE) sum2 -= BASE;
return sum1 | (sum2 << 16);
}
diff --git a/erts/emulator/zlib/compress.c b/erts/emulator/zlib/compress.c
index 8ecef0f790..e2db404abf 100644
--- a/erts/emulator/zlib/compress.c
+++ b/erts/emulator/zlib/compress.c
@@ -1,13 +1,10 @@
/* compress.c -- compress a memory buffer
- * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#define ZLIB_INTERNAL
#include "zlib.h"
@@ -31,16 +28,11 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
{
z_stream stream;
int err;
+ const uInt max = (uInt)-1;
+ uLong left;
- stream.next_in = (z_const Bytef *)source;
- stream.avail_in = (uInt)sourceLen;
-#ifdef MAXSEG_64K
- /* Check for source > 64K on 16-bit machine: */
- if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
-#endif
- stream.next_out = dest;
- stream.avail_out = (uInt)*destLen;
- if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+ left = *destLen;
+ *destLen = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
@@ -49,15 +41,26 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
err = deflateInit(&stream, level);
if (err != Z_OK) return err;
- err = deflate(&stream, Z_FINISH);
- if (err != Z_STREAM_END) {
- deflateEnd(&stream);
- return err == Z_OK ? Z_BUF_ERROR : err;
- }
- *destLen = stream.total_out;
+ stream.next_out = dest;
+ stream.avail_out = 0;
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = 0;
+
+ do {
+ if (stream.avail_out == 0) {
+ stream.avail_out = left > (uLong)max ? max : (uInt)left;
+ left -= stream.avail_out;
+ }
+ if (stream.avail_in == 0) {
+ stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen;
+ sourceLen -= stream.avail_in;
+ }
+ err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH);
+ } while (err == Z_OK);
- err = deflateEnd(&stream);
- return err;
+ *destLen = stream.total_out;
+ deflateEnd(&stream);
+ return err == Z_STREAM_END ? Z_OK : err;
}
/* ===========================================================================
diff --git a/erts/emulator/zlib/crc32.c b/erts/emulator/zlib/crc32.c
index ba506d8dd3..9580440c0e 100644
--- a/erts/emulator/zlib/crc32.c
+++ b/erts/emulator/zlib/crc32.c
@@ -1,5 +1,5 @@
/* crc32.c -- compute the CRC-32 of a data stream
- * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler
+ * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*
* Thanks to Rodney Brown <[email protected]> for his contribution of faster
@@ -28,23 +28,17 @@
# endif /* !DYNAMIC_CRC_TABLE */
#endif /* MAKECRCH */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#include "zutil.h" /* for STDC and FAR definitions */
-#define local static
-
/* Definitions for doing the crc four data bytes at a time. */
#if !defined(NOBYFOUR) && defined(Z_U4)
# define BYFOUR
#endif
#ifdef BYFOUR
local unsigned long crc32_little OF((unsigned long,
- const unsigned char FAR *, unsigned));
+ const unsigned char FAR *, z_size_t));
local unsigned long crc32_big OF((unsigned long,
- const unsigned char FAR *, unsigned));
+ const unsigned char FAR *, z_size_t));
# define TBLS 8
#else
# define TBLS 1
@@ -205,10 +199,10 @@ const z_crc_t FAR * ZEXPORT get_crc_table()
#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
/* ========================================================================= */
-unsigned long ZEXPORT crc32(crc, buf, len)
+unsigned long ZEXPORT crc32_z(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
- uInt len;
+ z_size_t len;
{
if (buf == Z_NULL) return 0UL;
@@ -239,8 +233,29 @@ unsigned long ZEXPORT crc32(crc, buf, len)
return crc ^ 0xffffffffUL;
}
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ uInt len;
+{
+ return crc32_z(crc, buf, len);
+}
+
#ifdef BYFOUR
+/*
+ This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit
+ integer pointer type. This violates the strict aliasing rule, where a
+ compiler can assume, for optimization purposes, that two pointers to
+ fundamentally different types won't ever point to the same memory. This can
+ manifest as a problem only if one of the pointers is written to. This code
+ only reads from those pointers. So long as this code remains isolated in
+ this compilation unit, there won't be a problem. For this reason, this code
+ should not be copied and pasted into a compilation unit in which other code
+ writes to the buffer that is passed to these routines.
+ */
+
/* ========================================================================= */
#define DOLIT4 c ^= *buf4++; \
c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
@@ -251,7 +266,7 @@ unsigned long ZEXPORT crc32(crc, buf, len)
local unsigned long crc32_little(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
- unsigned len;
+ z_size_t len;
{
register z_crc_t c;
register const z_crc_t FAR *buf4;
@@ -282,7 +297,7 @@ local unsigned long crc32_little(crc, buf, len)
}
/* ========================================================================= */
-#define DOBIG4 c ^= *++buf4; \
+#define DOBIG4 c ^= *buf4++; \
c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
@@ -291,7 +306,7 @@ local unsigned long crc32_little(crc, buf, len)
local unsigned long crc32_big(crc, buf, len)
unsigned long crc;
const unsigned char FAR *buf;
- unsigned len;
+ z_size_t len;
{
register z_crc_t c;
register const z_crc_t FAR *buf4;
@@ -304,7 +319,6 @@ local unsigned long crc32_big(crc, buf, len)
}
buf4 = (const z_crc_t FAR *)(const void FAR *)buf;
- buf4--;
while (len >= 32) {
DOBIG32;
len -= 32;
@@ -313,7 +327,6 @@ local unsigned long crc32_big(crc, buf, len)
DOBIG4;
len -= 4;
}
- buf4++;
buf = (const unsigned char FAR *)buf4;
if (len) do {
diff --git a/erts/emulator/zlib/deflate.c b/erts/emulator/zlib/deflate.c
index 943c26dfb2..1ec761448d 100644
--- a/erts/emulator/zlib/deflate.c
+++ b/erts/emulator/zlib/deflate.c
@@ -1,5 +1,5 @@
/* deflate.c -- compress data using the deflation algorithm
- * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -49,13 +49,10 @@
/* @(#) $Id$ */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "deflate.h"
const char deflate_copyright[] =
- " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler ";
+ " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -76,6 +73,8 @@ typedef enum {
typedef block_state (*compress_func) OF((deflate_state *s, int flush));
/* Compression function. Returns the block state after the call. */
+local int deflateStateCheck OF((z_streamp strm));
+local void slide_hash OF((deflate_state *s));
local void fill_window OF((deflate_state *s));
local block_state deflate_stored OF((deflate_state *s, int flush));
local block_state deflate_fast OF((deflate_state *s, int flush));
@@ -87,15 +86,16 @@ local block_state deflate_huff OF((deflate_state *s, int flush));
local void lm_init OF((deflate_state *s));
local void putShortMSB OF((deflate_state *s, uInt b));
local void flush_pending OF((z_streamp strm));
-local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
#ifdef ASMV
+# pragma message("Assembler code may have bugs -- use at your own risk")
void match_init OF((void)); /* asm code initialization */
uInt longest_match OF((deflate_state *s, IPos cur_match));
#else
local uInt longest_match OF((deflate_state *s, IPos cur_match));
#endif
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
local void check_match OF((deflate_state *s, IPos start, IPos match,
int length));
#endif
@@ -151,21 +151,14 @@ local const config configuration_table[10] = {
* meaning.
*/
-#define EQUAL 0
-/* result of memcmp for equal strings */
-
-#ifndef NO_DUMMY_DECL
-struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
-#endif
-
/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */
-#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))
+#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0))
/* ===========================================================================
* Update a hash value with the given input byte
- * IN assertion: all calls to to UPDATE_HASH are made with consecutive
- * input characters, so that a running hash key can be computed from the
- * previous key instead of complete recalculation each time.
+ * IN assertion: all calls to UPDATE_HASH are made with consecutive input
+ * characters, so that a running hash key can be computed from the previous
+ * key instead of complete recalculation each time.
*/
#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
@@ -176,9 +169,9 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
* the previous length of the hash chain.
* If this file is compiled with -DFASTEST, the compression level is forced
* to 1, and no hash chains are maintained.
- * IN assertion: all calls to to INSERT_STRING are made with consecutive
- * input characters and the first MIN_MATCH bytes of str are valid
- * (except for the last MIN_MATCH-1 bytes of the input file).
+ * IN assertion: all calls to INSERT_STRING are made with consecutive input
+ * characters and the first MIN_MATCH bytes of str are valid (except for
+ * the last MIN_MATCH-1 bytes of the input file).
*/
#ifdef FASTEST
#define INSERT_STRING(s, str, match_head) \
@@ -200,6 +193,37 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
s->head[s->hash_size-1] = NIL; \
zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+/* ===========================================================================
+ * Slide the hash table when sliding the window down (could be avoided with 32
+ * bit values at the expense of memory usage). We slide even when level == 0 to
+ * keep the hash table consistent if we switch back to level > 0 later.
+ */
+local void slide_hash(s)
+ deflate_state *s;
+{
+ unsigned n, m;
+ Posf *p;
+ uInt wsize = s->w_size;
+
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m - wsize : NIL);
+ } while (--n);
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m - wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+}
+
/* ========================================================================= */
int ZEXPORT deflateInit_(strm, level, version, stream_size)
z_streamp strm;
@@ -273,7 +297,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
#endif
if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
- strategy < 0 || strategy > Z_FIXED) {
+ strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) {
return Z_STREAM_ERROR;
}
if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
@@ -281,14 +305,15 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
if (s == Z_NULL) return Z_MEM_ERROR;
strm->state = (struct internal_state FAR *)s;
s->strm = strm;
+ s->status = INIT_STATE; /* to pass state test in deflateReset() */
s->wrap = wrap;
s->gzhead = Z_NULL;
- s->w_bits = windowBits;
+ s->w_bits = (uInt)windowBits;
s->w_size = 1 << s->w_bits;
s->w_mask = s->w_size - 1;
- s->hash_bits = memLevel + 7;
+ s->hash_bits = (uInt)memLevel + 7;
s->hash_size = 1 << s->hash_bits;
s->hash_mask = s->hash_size - 1;
s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
@@ -322,6 +347,31 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
return deflateReset(strm);
}
+/* =========================================================================
+ * Check for a valid deflate stream state. Return 0 if ok, 1 if not.
+ */
+local int deflateStateCheck (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+ if (strm == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
+ return 1;
+ s = strm->state;
+ if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE &&
+#ifdef GZIP
+ s->status != GZIP_STATE &&
+#endif
+ s->status != EXTRA_STATE &&
+ s->status != NAME_STATE &&
+ s->status != COMMENT_STATE &&
+ s->status != HCRC_STATE &&
+ s->status != BUSY_STATE &&
+ s->status != FINISH_STATE))
+ return 1;
+ return 0;
+}
+
/* ========================================================================= */
int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
z_streamp strm;
@@ -334,7 +384,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
unsigned avail;
z_const unsigned char *next;
- if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL)
+ if (deflateStateCheck(strm) || dictionary == Z_NULL)
return Z_STREAM_ERROR;
s = strm->state;
wrap = s->wrap;
@@ -392,13 +442,34 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
}
/* ========================================================================= */
+int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ Bytef *dictionary;
+ uInt *dictLength;
+{
+ deflate_state *s;
+ uInt len;
+
+ if (deflateStateCheck(strm))
+ return Z_STREAM_ERROR;
+ s = strm->state;
+ len = s->strstart + s->lookahead;
+ if (len > s->w_size)
+ len = s->w_size;
+ if (dictionary != Z_NULL && len)
+ zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len);
+ if (dictLength != Z_NULL)
+ *dictLength = len;
+ return Z_OK;
+}
+
+/* ========================================================================= */
int ZEXPORT deflateResetKeep (strm)
z_streamp strm;
{
deflate_state *s;
- if (strm == Z_NULL || strm->state == Z_NULL ||
- strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ if (deflateStateCheck(strm)) {
return Z_STREAM_ERROR;
}
@@ -413,7 +484,11 @@ int ZEXPORT deflateResetKeep (strm)
if (s->wrap < 0) {
s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
}
- s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ s->status =
+#ifdef GZIP
+ s->wrap == 2 ? GZIP_STATE :
+#endif
+ s->wrap ? INIT_STATE : BUSY_STATE;
strm->adler =
#ifdef GZIP
s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
@@ -443,8 +518,8 @@ int ZEXPORT deflateSetHeader (strm, head)
z_streamp strm;
gz_headerp head;
{
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
- if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm) || strm->state->wrap != 2)
+ return Z_STREAM_ERROR;
strm->state->gzhead = head;
return Z_OK;
}
@@ -455,7 +530,7 @@ int ZEXPORT deflatePending (strm, pending, bits)
int *bits;
z_streamp strm;
{
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
if (pending != Z_NULL)
*pending = strm->state->pending;
if (bits != Z_NULL)
@@ -472,7 +547,7 @@ int ZEXPORT deflatePrime (strm, bits, value)
deflate_state *s;
int put;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))
return Z_BUF_ERROR;
@@ -497,9 +572,8 @@ int ZEXPORT deflateParams(strm, level, strategy)
{
deflate_state *s;
compress_func func;
- int err = Z_OK;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
#ifdef FASTEST
@@ -513,13 +587,22 @@ int ZEXPORT deflateParams(strm, level, strategy)
func = configuration_table[s->level].func;
if ((strategy != s->strategy || func != configuration_table[level].func) &&
- strm->total_in != 0) {
+ s->high_water) {
/* Flush the last buffer: */
- err = deflate(strm, Z_BLOCK);
- if (err == Z_BUF_ERROR && s->pending == 0)
- err = Z_OK;
+ int err = deflate(strm, Z_BLOCK);
+ if (err == Z_STREAM_ERROR)
+ return err;
+ if (strm->avail_out == 0)
+ return Z_BUF_ERROR;
}
if (s->level != level) {
+ if (s->level == 0 && s->matches != 0) {
+ if (s->matches == 1)
+ slide_hash(s);
+ else
+ CLEAR_HASH(s);
+ s->matches = 0;
+ }
s->level = level;
s->max_lazy_match = configuration_table[level].max_lazy;
s->good_match = configuration_table[level].good_length;
@@ -527,7 +610,7 @@ int ZEXPORT deflateParams(strm, level, strategy)
s->max_chain_length = configuration_table[level].max_chain;
}
s->strategy = strategy;
- return err;
+ return Z_OK;
}
/* ========================================================================= */
@@ -540,12 +623,12 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
{
deflate_state *s;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
s = strm->state;
- s->good_match = good_length;
- s->max_lazy_match = max_lazy;
+ s->good_match = (uInt)good_length;
+ s->max_lazy_match = (uInt)max_lazy;
s->nice_match = nice_length;
- s->max_chain_length = max_chain;
+ s->max_chain_length = (uInt)max_chain;
return Z_OK;
}
@@ -572,14 +655,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
{
deflate_state *s;
uLong complen, wraplen;
- Bytef *str;
/* conservative upper bound for compressed data */
complen = sourceLen +
((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5;
/* if can't get parameters, return conservative bound plus zlib wrapper */
- if (strm == Z_NULL || strm->state == Z_NULL)
+ if (deflateStateCheck(strm))
return complen + 6;
/* compute wrapper length */
@@ -591,9 +673,11 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
case 1: /* zlib wrapper */
wraplen = 6 + (s->strstart ? 4 : 0);
break;
+#ifdef GZIP
case 2: /* gzip wrapper */
wraplen = 18;
if (s->gzhead != Z_NULL) { /* user-supplied gzip header */
+ Bytef *str;
if (s->gzhead->extra != Z_NULL)
wraplen += 2 + s->gzhead->extra_len;
str = s->gzhead->name;
@@ -610,6 +694,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen)
wraplen += 2;
}
break;
+#endif
default: /* for compiler happiness */
wraplen = 6;
}
@@ -637,10 +722,10 @@ local void putShortMSB (s, b)
}
/* =========================================================================
- * Flush as much pending output as possible. All deflate() output goes
- * through this function so some applications may wish to modify it
- * to avoid allocating a large strm->next_out buffer and copying into it.
- * (See also read_buf()).
+ * Flush as much pending output as possible. All deflate() output, except for
+ * some deflate_stored() output, goes through this function so some
+ * applications may wish to modify it to avoid allocating a large
+ * strm->next_out buffer and copying into it. (See also read_buf()).
*/
local void flush_pending(strm)
z_streamp strm;
@@ -657,13 +742,23 @@ local void flush_pending(strm)
strm->next_out += len;
s->pending_out += len;
strm->total_out += len;
- strm->avail_out -= len;
- s->pending -= len;
+ strm->avail_out -= len;
+ s->pending -= len;
if (s->pending == 0) {
s->pending_out = s->pending_buf;
}
}
+/* ===========================================================================
+ * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1].
+ */
+#define HCRC_UPDATE(beg) \
+ do { \
+ if (s->gzhead->hcrc && s->pending > (beg)) \
+ strm->adler = crc32(strm->adler, s->pending_buf + (beg), \
+ s->pending - (beg)); \
+ } while (0)
+
/* ========================================================================= */
int ZEXPORT deflate (strm, flush)
z_streamp strm;
@@ -672,230 +767,229 @@ int ZEXPORT deflate (strm, flush)
int old_flush; /* value of flush param for previous deflate call */
deflate_state *s;
- if (strm == Z_NULL || strm->state == Z_NULL ||
- flush > Z_BLOCK || flush < 0) {
+ if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {
return Z_STREAM_ERROR;
}
s = strm->state;
if (strm->next_out == Z_NULL ||
- (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (strm->avail_in != 0 && strm->next_in == Z_NULL) ||
(s->status == FINISH_STATE && flush != Z_FINISH)) {
ERR_RETURN(strm, Z_STREAM_ERROR);
}
if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
- s->strm = strm; /* just in case */
old_flush = s->last_flush;
s->last_flush = flush;
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
/* Write the header */
if (s->status == INIT_STATE) {
-#ifdef GZIP
- if (s->wrap == 2) {
- strm->adler = crc32(0L, Z_NULL, 0);
- put_byte(s, 31);
- put_byte(s, 139);
- put_byte(s, 8);
- if (s->gzhead == Z_NULL) {
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, 0);
- put_byte(s, s->level == 9 ? 2 :
- (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
- 4 : 0));
- put_byte(s, OS_CODE);
- s->status = BUSY_STATE;
- }
- else {
- put_byte(s, (s->gzhead->text ? 1 : 0) +
- (s->gzhead->hcrc ? 2 : 0) +
- (s->gzhead->extra == Z_NULL ? 0 : 4) +
- (s->gzhead->name == Z_NULL ? 0 : 8) +
- (s->gzhead->comment == Z_NULL ? 0 : 16)
- );
- put_byte(s, (Byte)(s->gzhead->time & 0xff));
- put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
- put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
- put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
- put_byte(s, s->level == 9 ? 2 :
- (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
- 4 : 0));
- put_byte(s, s->gzhead->os & 0xff);
- if (s->gzhead->extra != Z_NULL) {
- put_byte(s, s->gzhead->extra_len & 0xff);
- put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
- }
- if (s->gzhead->hcrc)
- strm->adler = crc32(strm->adler, s->pending_buf,
- s->pending);
- s->gzindex = 0;
- s->status = EXTRA_STATE;
- }
- }
+ /* zlib header */
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
else
-#endif
- {
- uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
- uInt level_flags;
-
- if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
- level_flags = 0;
- else if (s->level < 6)
- level_flags = 1;
- else if (s->level == 6)
- level_flags = 2;
- else
- level_flags = 3;
- header |= (level_flags << 6);
- if (s->strstart != 0) header |= PRESET_DICT;
- header += 31 - (header % 31);
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ /* Compression must start with an empty pending buffer */
+ flush_pending(strm);
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
+ }
+ }
+#ifdef GZIP
+ if (s->status == GZIP_STATE) {
+ /* gzip header */
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == Z_NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
s->status = BUSY_STATE;
- putShortMSB(s, header);
- /* Save the adler32 of the preset dictionary: */
- if (s->strstart != 0) {
- putShortMSB(s, (uInt)(strm->adler >> 16));
- putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ /* Compression must start with an empty pending buffer */
+ flush_pending(strm);
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
+ }
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != Z_NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
}
- strm->adler = adler32(0L, Z_NULL, 0);
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
}
}
-#ifdef GZIP
if (s->status == EXTRA_STATE) {
if (s->gzhead->extra != Z_NULL) {
- uInt beg = s->pending; /* start of bytes to update crc */
-
- while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
- if (s->pending == s->pending_buf_size) {
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
- flush_pending(strm);
- beg = s->pending;
- if (s->pending == s->pending_buf_size)
- break;
+ ulg beg = s->pending; /* start of bytes to update crc */
+ uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
+ while (s->pending + left > s->pending_buf_size) {
+ uInt copy = s->pending_buf_size - s->pending;
+ zmemcpy(s->pending_buf + s->pending,
+ s->gzhead->extra + s->gzindex, copy);
+ s->pending = s->pending_buf_size;
+ HCRC_UPDATE(beg);
+ s->gzindex += copy;
+ flush_pending(strm);
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
}
- put_byte(s, s->gzhead->extra[s->gzindex]);
- s->gzindex++;
- }
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
- if (s->gzindex == s->gzhead->extra_len) {
- s->gzindex = 0;
- s->status = NAME_STATE;
+ beg = 0;
+ left -= copy;
}
+ zmemcpy(s->pending_buf + s->pending,
+ s->gzhead->extra + s->gzindex, left);
+ s->pending += left;
+ HCRC_UPDATE(beg);
+ s->gzindex = 0;
}
- else
- s->status = NAME_STATE;
+ s->status = NAME_STATE;
}
if (s->status == NAME_STATE) {
if (s->gzhead->name != Z_NULL) {
- uInt beg = s->pending; /* start of bytes to update crc */
+ ulg beg = s->pending; /* start of bytes to update crc */
int val;
-
do {
if (s->pending == s->pending_buf_size) {
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
+ HCRC_UPDATE(beg);
flush_pending(strm);
- beg = s->pending;
- if (s->pending == s->pending_buf_size) {
- val = 1;
- break;
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
}
+ beg = 0;
}
val = s->gzhead->name[s->gzindex++];
put_byte(s, val);
} while (val != 0);
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
- if (val == 0) {
- s->gzindex = 0;
- s->status = COMMENT_STATE;
- }
+ HCRC_UPDATE(beg);
+ s->gzindex = 0;
}
- else
- s->status = COMMENT_STATE;
+ s->status = COMMENT_STATE;
}
if (s->status == COMMENT_STATE) {
if (s->gzhead->comment != Z_NULL) {
- uInt beg = s->pending; /* start of bytes to update crc */
+ ulg beg = s->pending; /* start of bytes to update crc */
int val;
-
do {
if (s->pending == s->pending_buf_size) {
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
+ HCRC_UPDATE(beg);
flush_pending(strm);
- beg = s->pending;
- if (s->pending == s->pending_buf_size) {
- val = 1;
- break;
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
}
+ beg = 0;
}
val = s->gzhead->comment[s->gzindex++];
put_byte(s, val);
} while (val != 0);
- if (s->gzhead->hcrc && s->pending > beg)
- strm->adler = crc32(strm->adler, s->pending_buf + beg,
- s->pending - beg);
- if (val == 0)
- s->status = HCRC_STATE;
+ HCRC_UPDATE(beg);
}
- else
- s->status = HCRC_STATE;
+ s->status = HCRC_STATE;
}
if (s->status == HCRC_STATE) {
if (s->gzhead->hcrc) {
- if (s->pending + 2 > s->pending_buf_size)
+ if (s->pending + 2 > s->pending_buf_size) {
flush_pending(strm);
- if (s->pending + 2 <= s->pending_buf_size) {
- put_byte(s, (Byte)(strm->adler & 0xff));
- put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
- strm->adler = crc32(0L, Z_NULL, 0);
- s->status = BUSY_STATE;
+ if (s->pending != 0) {
+ s->last_flush = -1;
+ return Z_OK;
+ }
}
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
}
- else
- s->status = BUSY_STATE;
- }
-#endif
+ s->status = BUSY_STATE;
- /* Flush as much pending output as possible */
- if (s->pending != 0) {
+ /* Compression must start with an empty pending buffer */
flush_pending(strm);
- if (strm->avail_out == 0) {
- /* Since avail_out is 0, deflate will be called again with
- * more output space, but possibly with both pending and
- * avail_in equal to zero. There won't be anything to do,
- * but this is not an error situation so make sure we
- * return OK instead of BUF_ERROR at next call of deflate:
- */
+ if (s->pending != 0) {
s->last_flush = -1;
return Z_OK;
}
-
- /* Make sure there is something to do and avoid duplicate consecutive
- * flushes. For repeated and useless calls with Z_FINISH, we keep
- * returning Z_STREAM_END instead of Z_BUF_ERROR.
- */
- } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
- flush != Z_FINISH) {
- ERR_RETURN(strm, Z_BUF_ERROR);
- }
-
- /* User must not provide more input after the first FINISH: */
- if (s->status == FINISH_STATE && strm->avail_in != 0) {
- ERR_RETURN(strm, Z_BUF_ERROR);
}
+#endif
/* Start a new block or continue the current one.
*/
@@ -903,9 +997,10 @@ int ZEXPORT deflate (strm, flush)
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
block_state bstate;
- bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
- (s->strategy == Z_RLE ? deflate_rle(s, flush) :
- (*(configuration_table[s->level].func))(s, flush));
+ bstate = s->level == 0 ? deflate_stored(s, flush) :
+ s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
+ s->strategy == Z_RLE ? deflate_rle(s, flush) :
+ (*(configuration_table[s->level].func))(s, flush);
if (bstate == finish_started || bstate == finish_done) {
s->status = FINISH_STATE;
@@ -947,7 +1042,6 @@ int ZEXPORT deflate (strm, flush)
}
}
}
- Assert(strm->avail_out > 0, "bug2");
if (flush != Z_FINISH) return Z_OK;
if (s->wrap <= 0) return Z_STREAM_END;
@@ -984,18 +1078,9 @@ int ZEXPORT deflateEnd (strm)
{
int status;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (deflateStateCheck(strm)) return Z_STREAM_ERROR;
status = strm->state->status;
- if (status != INIT_STATE &&
- status != EXTRA_STATE &&
- status != NAME_STATE &&
- status != COMMENT_STATE &&
- status != HCRC_STATE &&
- status != BUSY_STATE &&
- status != FINISH_STATE) {
- return Z_STREAM_ERROR;
- }
/* Deallocate in reverse order of allocations: */
TRY_FREE(strm, strm->state->pending_buf);
@@ -1026,7 +1111,7 @@ int ZEXPORT deflateCopy (dest, source)
ushf *overlay;
- if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ if (deflateStateCheck(source) || dest == Z_NULL) {
return Z_STREAM_ERROR;
}
@@ -1076,7 +1161,7 @@ int ZEXPORT deflateCopy (dest, source)
* allocating a large strm->next_in buffer and copying from it.
* (See also flush_pending()).
*/
-local int read_buf(strm, buf, size)
+local unsigned read_buf(strm, buf, size)
z_streamp strm;
Bytef *buf;
unsigned size;
@@ -1100,7 +1185,7 @@ local int read_buf(strm, buf, size)
strm->next_in += len;
strm->total_in += len;
- return (int)len;
+ return len;
}
/* ===========================================================================
@@ -1154,9 +1239,9 @@ local uInt longest_match(s, cur_match)
{
unsigned chain_length = s->max_chain_length;/* max hash chain length */
register Bytef *scan = s->window + s->strstart; /* current string */
- register Bytef *match; /* matched string */
+ register Bytef *match; /* matched string */
register int len; /* length of current match */
- int best_len = s->prev_length; /* best match length so far */
+ int best_len = (int)s->prev_length; /* best match length so far */
int nice_match = s->nice_match; /* stop if match long enough */
IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
s->strstart - (IPos)MAX_DIST(s) : NIL;
@@ -1191,7 +1276,7 @@ local uInt longest_match(s, cur_match)
/* Do not look for matches beyond the end of the input. This is necessary
* to make deflate deterministic.
*/
- if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+ if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead;
Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
@@ -1352,7 +1437,11 @@ local uInt longest_match(s, cur_match)
#endif /* FASTEST */
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
/* ===========================================================================
* Check that the match at match_start is indeed a match.
*/
@@ -1378,7 +1467,7 @@ local void check_match(s, start, match, length)
}
#else
# define check_match(s, start, match, length)
-#endif /* DEBUG */
+#endif /* ZLIB_DEBUG */
/* ===========================================================================
* Fill the window when the lookahead becomes insufficient.
@@ -1393,8 +1482,7 @@ local void check_match(s, start, match, length)
local void fill_window(s)
deflate_state *s;
{
- register unsigned n, m;
- register Posf *p;
+ unsigned n;
unsigned more; /* Amount of free space at the end of the window. */
uInt wsize = s->w_size;
@@ -1421,35 +1509,11 @@ local void fill_window(s)
*/
if (s->strstart >= wsize+MAX_DIST(s)) {
- zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more);
s->match_start -= wsize;
s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
s->block_start -= (long) wsize;
-
- /* Slide the hash table (could be avoided with 32 bit values
- at the expense of memory usage). We slide even when level == 0
- to keep the hash table consistent if we switch back to level > 0
- later. (Using level 0 permanently is not an optimal usage of
- zlib, so we don't care about this pathological case.)
- */
- n = s->hash_size;
- p = &s->head[n];
- do {
- m = *--p;
- *p = (Pos)(m >= wsize ? m-wsize : NIL);
- } while (--n);
-
- n = wsize;
-#ifndef FASTEST
- p = &s->prev[n];
- do {
- m = *--p;
- *p = (Pos)(m >= wsize ? m-wsize : NIL);
- /* If n is not on any hash chain, prev[n] is garbage but
- * its value will never be used.
- */
- } while (--n);
-#endif
+ slide_hash(s);
more += wsize;
}
if (s->strm->avail_in == 0) break;
@@ -1555,70 +1619,199 @@ local void fill_window(s)
if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \
}
+/* Maximum stored block length in deflate format (not including header). */
+#define MAX_STORED 65535
+
+/* Minimum of a and b. */
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
/* ===========================================================================
* Copy without compression as much as possible from the input stream, return
* the current block state.
- * This function does not insert new strings in the dictionary since
- * uncompressible data is probably not useful. This function is used
- * only for the level=0 compression option.
- * NOTE: this function should be optimized to avoid extra copying from
- * window to pending_buf.
+ *
+ * In case deflateParams() is used to later switch to a non-zero compression
+ * level, s->matches (otherwise unused when storing) keeps track of the number
+ * of hash table slides to perform. If s->matches is 1, then one hash table
+ * slide will be done when switching. If s->matches is 2, the maximum value
+ * allowed here, then the hash table will be cleared, since two or more slides
+ * is the same as a clear.
+ *
+ * deflate_stored() is written to minimize the number of times an input byte is
+ * copied. It is most efficient with large input and output buffers, which
+ * maximizes the opportunites to have a single copy from next_in to next_out.
*/
local block_state deflate_stored(s, flush)
deflate_state *s;
int flush;
{
- /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
- * to pending_buf_size, and each stored block has a 5 byte header:
+ /* Smallest worthy block size when not flushing or finishing. By default
+ * this is 32K. This can be as small as 507 bytes for memLevel == 1. For
+ * large input and output buffers, the stored block size will be larger.
*/
- ulg max_block_size = 0xffff;
- ulg max_start;
-
- if (max_block_size > s->pending_buf_size - 5) {
- max_block_size = s->pending_buf_size - 5;
- }
-
- /* Copy as much as possible from input to output: */
- for (;;) {
- /* Fill the window as much as possible: */
- if (s->lookahead <= 1) {
+ unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size);
- Assert(s->strstart < s->w_size+MAX_DIST(s) ||
- s->block_start >= (long)s->w_size, "slide too late");
+ /* Copy as many min_block or larger stored blocks directly to next_out as
+ * possible. If flushing, copy the remaining available input to next_out as
+ * stored blocks, if there is enough space.
+ */
+ unsigned len, left, have, last = 0;
+ unsigned used = s->strm->avail_in;
+ do {
+ /* Set len to the maximum size block that we can copy directly with the
+ * available input data and output space. Set left to how much of that
+ * would be copied from what's left in the window.
+ */
+ len = MAX_STORED; /* maximum deflate stored block length */
+ have = (s->bi_valid + 42) >> 3; /* number of header bytes */
+ if (s->strm->avail_out < have) /* need room for header */
+ break;
+ /* maximum stored block length that will fit in avail_out: */
+ have = s->strm->avail_out - have;
+ left = s->strstart - s->block_start; /* bytes left in window */
+ if (len > (ulg)left + s->strm->avail_in)
+ len = left + s->strm->avail_in; /* limit len to the input */
+ if (len > have)
+ len = have; /* limit len to the output */
+
+ /* If the stored block would be less than min_block in length, or if
+ * unable to copy all of the available input when flushing, then try
+ * copying to the window and the pending buffer instead. Also don't
+ * write an empty block when flushing -- deflate() does that.
+ */
+ if (len < min_block && ((len == 0 && flush != Z_FINISH) ||
+ flush == Z_NO_FLUSH ||
+ len != left + s->strm->avail_in))
+ break;
- fill_window(s);
- if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+ /* Make a dummy stored block in pending to get the header bytes,
+ * including any pending bits. This also updates the debugging counts.
+ */
+ last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0;
+ _tr_stored_block(s, (char *)0, 0L, last);
+
+ /* Replace the lengths in the dummy stored block with len. */
+ s->pending_buf[s->pending - 4] = len;
+ s->pending_buf[s->pending - 3] = len >> 8;
+ s->pending_buf[s->pending - 2] = ~len;
+ s->pending_buf[s->pending - 1] = ~len >> 8;
+
+ /* Write the stored block header bytes. */
+ flush_pending(s->strm);
+
+#ifdef ZLIB_DEBUG
+ /* Update debugging counts for the data about to be copied. */
+ s->compressed_len += len << 3;
+ s->bits_sent += len << 3;
+#endif
- if (s->lookahead == 0) break; /* flush the current block */
+ /* Copy uncompressed bytes from the window to next_out. */
+ if (left) {
+ if (left > len)
+ left = len;
+ zmemcpy(s->strm->next_out, s->window + s->block_start, left);
+ s->strm->next_out += left;
+ s->strm->avail_out -= left;
+ s->strm->total_out += left;
+ s->block_start += left;
+ len -= left;
}
- Assert(s->block_start >= 0L, "block gone");
-
- s->strstart += s->lookahead;
- s->lookahead = 0;
-
- /* Emit a stored block if pending_buf will be full: */
- max_start = s->block_start + max_block_size;
- if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
- /* strstart == 0 is possible when wraparound on 16-bit machine */
- s->lookahead = (uInt)(s->strstart - max_start);
- s->strstart = (uInt)max_start;
- FLUSH_BLOCK(s, 0);
+
+ /* Copy uncompressed bytes directly from next_in to next_out, updating
+ * the check value.
+ */
+ if (len) {
+ read_buf(s->strm, s->strm->next_out, len);
+ s->strm->next_out += len;
+ s->strm->avail_out -= len;
+ s->strm->total_out += len;
}
- /* Flush if we may have to slide, otherwise block_start may become
- * negative and the data will be gone:
+ } while (last == 0);
+
+ /* Update the sliding window with the last s->w_size bytes of the copied
+ * data, or append all of the copied data to the existing window if less
+ * than s->w_size bytes were copied. Also update the number of bytes to
+ * insert in the hash tables, in the event that deflateParams() switches to
+ * a non-zero compression level.
+ */
+ used -= s->strm->avail_in; /* number of input bytes directly copied */
+ if (used) {
+ /* If any input was used, then no unused input remains in the window,
+ * therefore s->block_start == s->strstart.
*/
- if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
- FLUSH_BLOCK(s, 0);
+ if (used >= s->w_size) { /* supplant the previous history */
+ s->matches = 2; /* clear hash */
+ zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size);
+ s->strstart = s->w_size;
}
+ else {
+ if (s->window_size - s->strstart <= used) {
+ /* Slide the window down. */
+ s->strstart -= s->w_size;
+ zmemcpy(s->window, s->window + s->w_size, s->strstart);
+ if (s->matches < 2)
+ s->matches++; /* add a pending slide_hash() */
+ }
+ zmemcpy(s->window + s->strstart, s->strm->next_in - used, used);
+ s->strstart += used;
+ }
+ s->block_start = s->strstart;
+ s->insert += MIN(used, s->w_size - s->insert);
}
- s->insert = 0;
- if (flush == Z_FINISH) {
- FLUSH_BLOCK(s, 1);
+ if (s->high_water < s->strstart)
+ s->high_water = s->strstart;
+
+ /* If the last block was written to next_out, then done. */
+ if (last)
return finish_done;
+
+ /* If flushing and all input has been consumed, then done. */
+ if (flush != Z_NO_FLUSH && flush != Z_FINISH &&
+ s->strm->avail_in == 0 && (long)s->strstart == s->block_start)
+ return block_done;
+
+ /* Fill the window with any remaining input. */
+ have = s->window_size - s->strstart - 1;
+ if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) {
+ /* Slide the window down. */
+ s->block_start -= s->w_size;
+ s->strstart -= s->w_size;
+ zmemcpy(s->window, s->window + s->w_size, s->strstart);
+ if (s->matches < 2)
+ s->matches++; /* add a pending slide_hash() */
+ have += s->w_size; /* more space now */
}
- if ((long)s->strstart > s->block_start)
- FLUSH_BLOCK(s, 0);
- return block_done;
+ if (have > s->strm->avail_in)
+ have = s->strm->avail_in;
+ if (have) {
+ read_buf(s->strm, s->window + s->strstart, have);
+ s->strstart += have;
+ }
+ if (s->high_water < s->strstart)
+ s->high_water = s->strstart;
+
+ /* There was not enough avail_out to write a complete worthy or flushed
+ * stored block to next_out. Write a stored block to pending instead, if we
+ * have enough input for a worthy block, or if flushing and there is enough
+ * room for the remaining input as a stored block in the pending buffer.
+ */
+ have = (s->bi_valid + 42) >> 3; /* number of header bytes */
+ /* maximum stored block length that will fit in pending: */
+ have = MIN(s->pending_buf_size - have, MAX_STORED);
+ min_block = MIN(have, s->w_size);
+ left = s->strstart - s->block_start;
+ if (left >= min_block ||
+ ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH &&
+ s->strm->avail_in == 0 && left <= have)) {
+ len = MIN(left, have);
+ last = flush == Z_FINISH && s->strm->avail_in == 0 &&
+ len == left ? 1 : 0;
+ _tr_stored_block(s, (charf *)s->window + s->block_start, len, last);
+ s->block_start += len;
+ flush_pending(s->strm);
+ }
+
+ /* We've done all we can with the available input and output. */
+ return last ? finish_started : need_more;
}
/* ===========================================================================
@@ -1895,7 +2088,7 @@ local block_state deflate_rle(s, flush)
prev == *++scan && prev == *++scan &&
prev == *++scan && prev == *++scan &&
scan < strend);
- s->match_length = MAX_MATCH - (int)(strend - scan);
+ s->match_length = MAX_MATCH - (uInt)(strend - scan);
if (s->match_length > s->lookahead)
s->match_length = s->lookahead;
}
diff --git a/erts/emulator/zlib/deflate.h b/erts/emulator/zlib/deflate.h
index ce0299edd1..23ecdd312b 100644
--- a/erts/emulator/zlib/deflate.h
+++ b/erts/emulator/zlib/deflate.h
@@ -1,5 +1,5 @@
/* deflate.h -- internal compression state
- * Copyright (C) 1995-2012 Jean-loup Gailly
+ * Copyright (C) 1995-2016 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -51,13 +51,16 @@
#define Buf_size 16
/* size of bit buffer in bi_buf */
-#define INIT_STATE 42
-#define EXTRA_STATE 69
-#define NAME_STATE 73
-#define COMMENT_STATE 91
-#define HCRC_STATE 103
-#define BUSY_STATE 113
-#define FINISH_STATE 666
+#define INIT_STATE 42 /* zlib header -> BUSY_STATE */
+#ifdef GZIP
+# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */
+#endif
+#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */
+#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */
+#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */
+#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */
+#define BUSY_STATE 113 /* deflate -> FINISH_STATE */
+#define FINISH_STATE 666 /* stream complete */
/* Stream status */
@@ -83,7 +86,7 @@ typedef struct static_tree_desc_s static_tree_desc;
typedef struct tree_desc_s {
ct_data *dyn_tree; /* the dynamic tree */
int max_code; /* largest code with non zero frequency */
- static_tree_desc *stat_desc; /* the corresponding static tree */
+ const static_tree_desc *stat_desc; /* the corresponding static tree */
} FAR tree_desc;
typedef ush Pos;
@@ -100,10 +103,10 @@ typedef struct internal_state {
Bytef *pending_buf; /* output still pending */
ulg pending_buf_size; /* size of pending_buf */
Bytef *pending_out; /* next pending byte to output to the stream */
- uInt pending; /* nb of bytes in the pending buffer */
+ ulg pending; /* nb of bytes in the pending buffer */
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
gz_headerp gzhead; /* gzip header information to write */
- uInt gzindex; /* where in extra, name, or comment */
+ ulg gzindex; /* where in extra, name, or comment */
Byte method; /* can only be DEFLATED */
int last_flush; /* value of flush param for previous deflate call */
@@ -249,7 +252,7 @@ typedef struct internal_state {
uInt matches; /* number of string matches in current block */
uInt insert; /* bytes at end of window left to insert */
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
#endif
@@ -275,7 +278,7 @@ typedef struct internal_state {
/* Output a byte on the stream.
* IN assertion: there is enough room in pending_buf.
*/
-#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);}
#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
@@ -309,7 +312,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
* used.
*/
-#ifndef DEBUG
+#ifndef ZLIB_DEBUG
/* Inline versions of _tr_tally for speed: */
#if defined(GEN_TREES_H) || !defined(STDC)
@@ -328,8 +331,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
flush = (s->last_lit == s->lit_bufsize-1); \
}
# define _tr_tally_dist(s, distance, length, flush) \
- { uch len = (length); \
- ush dist = (distance); \
+ { uch len = (uch)(length); \
+ ush dist = (ush)(distance); \
s->d_buf[s->last_lit] = dist; \
s->l_buf[s->last_lit++] = len; \
dist--; \
diff --git a/erts/emulator/zlib/gzguts.h b/erts/emulator/zlib/gzguts.h
index d87659d031..990a4d2514 100644
--- a/erts/emulator/zlib/gzguts.h
+++ b/erts/emulator/zlib/gzguts.h
@@ -1,5 +1,5 @@
/* gzguts.h -- zlib internal header definitions for gz* operations
- * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
+ * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -25,6 +25,10 @@
# include <stdlib.h>
# include <limits.h>
#endif
+
+#ifndef _POSIX_SOURCE
+# define _POSIX_SOURCE
+#endif
#include <fcntl.h>
#ifdef _WIN32
@@ -35,6 +39,10 @@
# include <io.h>
#endif
+#if defined(_WIN32) || defined(__CYGWIN__)
+# define WIDECHAR
+#endif
+
#ifdef WINAPI_FAMILY
# define open _open
# define read _read
@@ -95,18 +103,19 @@
# endif
#endif
-/* unlike snprintf (which is required in C99, yet still not supported by
- Microsoft more than a decade later!), _snprintf does not guarantee null
- termination of the result -- however this is only used in gzlib.c where
+/* unlike snprintf (which is required in C99), _snprintf does not guarantee
+ null termination of the result -- however this is only used in gzlib.c where
the result is assured to fit in the space provided */
-#ifdef _MSC_VER
+#if defined(_MSC_VER) && _MSC_VER < 1900
# define snprintf _snprintf
#endif
#ifndef local
# define local static
#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
+/* since "static" is used to mean two completely different things in C, we
+ define "local" for the non-static meaning of "static", for readability
+ (compile with -Dlocal if your debugger can't find static symbols) */
/* gz* functions always use library allocation functions */
#ifndef STDC
@@ -170,7 +179,7 @@ typedef struct {
char *path; /* path or fd for error messages */
unsigned size; /* buffer size, zero if not allocated yet */
unsigned want; /* requested buffer size, default is GZBUFSIZE */
- unsigned char *in; /* input buffer */
+ unsigned char *in; /* input buffer (double-sized when writing) */
unsigned char *out; /* output buffer (double-sized when reading) */
int direct; /* 0 if processing gzip, 1 if transparent */
/* just for reading */
diff --git a/erts/emulator/zlib/inffast.c b/erts/emulator/zlib/inffast.c
index 5187743fde..0dbd1dbc09 100644
--- a/erts/emulator/zlib/inffast.c
+++ b/erts/emulator/zlib/inffast.c
@@ -1,36 +1,16 @@
/* inffast.c -- fast decoding
- * Copyright (C) 1995-2008, 2010, 2013 Mark Adler
+ * Copyright (C) 1995-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"
-#ifndef ASMINF
-
-/* Allow machine dependent optimization for post-increment or pre-increment.
- Based on testing to date,
- Pre-increment preferred for:
- - PowerPC G3 (Adler)
- - MIPS R5000 (Randers-Pehrson)
- Post-increment preferred for:
- - none
- No measurable difference:
- - Pentium III (Anderson)
- - M68060 (Nikl)
- */
-#ifdef POSTINC
-# define OFF 0
-# define PUP(a) *(a)++
+#ifdef ASMINF
+# pragma message("Assembler code may have bugs -- use at your own risk")
#else
-# define OFF 1
-# define PUP(a) *++(a)
-#endif
/*
Decode literal, length, and distance codes and write out the resulting
@@ -99,9 +79,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
/* copy state to local variables */
state = (struct inflate_state FAR *)strm->state;
- in = strm->next_in - OFF;
+ in = strm->next_in;
last = in + (strm->avail_in - 5);
- out = strm->next_out - OFF;
+ out = strm->next_out;
beg = out - (start - strm->avail_out);
end = out + (strm->avail_out - 257);
#ifdef INFLATE_STRICT
@@ -122,9 +102,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
input data or output space */
do {
if (bits < 15) {
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = lcode[hold & lmask];
@@ -137,14 +117,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
"inflate: literal '%c'\n" :
"inflate: literal 0x%02x\n", here.val));
- PUP(out) = (unsigned char)(here.val);
+ *out++ = (unsigned char)(here.val);
}
else if (op & 16) { /* length base */
len = (unsigned)(here.val);
op &= 15; /* number of extra bits */
if (op) {
if (bits < op) {
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
}
len += (unsigned)hold & ((1U << op) - 1);
@@ -153,9 +133,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
}
Tracevv((stderr, "inflate: length %u\n", len));
if (bits < 15) {
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
}
here = dcode[hold & dmask];
@@ -168,10 +148,10 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
dist = (unsigned)(here.val);
op &= 15; /* number of extra bits */
if (bits < op) {
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
if (bits < op) {
- hold += (unsigned long)(PUP(in)) << bits;
+ hold += (unsigned long)(*in++) << bits;
bits += 8;
}
}
@@ -199,30 +179,30 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
if (len <= op - whave) {
do {
- PUP(out) = 0;
+ *out++ = 0;
} while (--len);
continue;
}
len -= op - whave;
do {
- PUP(out) = 0;
+ *out++ = 0;
} while (--op > whave);
if (op == 0) {
from = out - dist;
do {
- PUP(out) = PUP(from);
+ *out++ = *from++;
} while (--len);
continue;
}
#endif
}
- from = window - OFF;
+ from = window;
if (wnext == 0) { /* very common case */
from += wsize - op;
if (op < len) { /* some from window */
len -= op;
do {
- PUP(out) = PUP(from);
+ *out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
@@ -233,14 +213,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from end of window */
len -= op;
do {
- PUP(out) = PUP(from);
+ *out++ = *from++;
} while (--op);
- from = window - OFF;
+ from = window;
if (wnext < len) { /* some from start of window */
op = wnext;
len -= op;
do {
- PUP(out) = PUP(from);
+ *out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
@@ -251,35 +231,35 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
if (op < len) { /* some from window */
len -= op;
do {
- PUP(out) = PUP(from);
+ *out++ = *from++;
} while (--op);
from = out - dist; /* rest from output */
}
}
while (len > 2) {
- PUP(out) = PUP(from);
- PUP(out) = PUP(from);
- PUP(out) = PUP(from);
+ *out++ = *from++;
+ *out++ = *from++;
+ *out++ = *from++;
len -= 3;
}
if (len) {
- PUP(out) = PUP(from);
+ *out++ = *from++;
if (len > 1)
- PUP(out) = PUP(from);
+ *out++ = *from++;
}
}
else {
from = out - dist; /* copy direct from output */
do { /* minimum length is three */
- PUP(out) = PUP(from);
- PUP(out) = PUP(from);
- PUP(out) = PUP(from);
+ *out++ = *from++;
+ *out++ = *from++;
+ *out++ = *from++;
len -= 3;
} while (len > 2);
if (len) {
- PUP(out) = PUP(from);
+ *out++ = *from++;
if (len > 1)
- PUP(out) = PUP(from);
+ *out++ = *from++;
}
}
}
@@ -316,8 +296,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
hold &= (1U << bits) - 1;
/* update state and return */
- strm->next_in = in + OFF;
- strm->next_out = out + OFF;
+ strm->next_in = in;
+ strm->next_out = out;
strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
strm->avail_out = (unsigned)(out < end ?
257 + (end - out) : 257 - (out - end));
diff --git a/erts/emulator/zlib/inflate.c b/erts/emulator/zlib/inflate.c
index 532330b06b..ac333e8c2e 100644
--- a/erts/emulator/zlib/inflate.c
+++ b/erts/emulator/zlib/inflate.c
@@ -1,5 +1,5 @@
/* inflate.c -- zlib decompression
- * Copyright (C) 1995-2012 Mark Adler
+ * Copyright (C) 1995-2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -80,9 +80,6 @@
* The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "zutil.h"
#include "inftrees.h"
#include "inflate.h"
@@ -95,6 +92,7 @@
#endif
/* function prototypes */
+local int inflateStateCheck OF((z_streamp strm));
local void fixedtables OF((struct inflate_state FAR *state));
local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
unsigned copy));
@@ -104,12 +102,26 @@ local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
unsigned len));
+local int inflateStateCheck(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
+ return 1;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state == Z_NULL || state->strm != strm ||
+ state->mode < HEAD || state->mode > SYNC)
+ return 1;
+ return 0;
+}
+
int ZEXPORT inflateResetKeep(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
strm->total_in = strm->total_out = state->total = 0;
strm->msg = Z_NULL;
@@ -134,7 +146,7 @@ z_streamp strm;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
state->wsize = 0;
state->whave = 0;
@@ -150,7 +162,7 @@ int windowBits;
struct inflate_state FAR *state;
/* get the state */
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* extract wrap request from windowBits parameter */
@@ -159,7 +171,7 @@ int windowBits;
windowBits = -windowBits;
}
else {
- wrap = (windowBits >> 4) + 1;
+ wrap = (windowBits >> 4) + 5;
#ifdef GUNZIP
if (windowBits < 48)
windowBits &= 15;
@@ -213,7 +225,9 @@ int stream_size;
if (state == Z_NULL) return Z_MEM_ERROR;
Tracev((stderr, "inflate: allocated\n"));
strm->state = (struct internal_state FAR *)state;
+ state->strm = strm;
state->window = Z_NULL;
+ state->mode = HEAD; /* to pass state test in inflateReset2() */
ret = inflateReset2(strm, windowBits);
if (ret != Z_OK) {
ZFREE(strm, state);
@@ -237,17 +251,17 @@ int value;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (bits < 0) {
state->hold = 0;
state->bits = 0;
return Z_OK;
}
- if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR;
value &= (1L << bits) - 1;
- state->hold += value << state->bits;
- state->bits += bits;
+ state->hold += (unsigned)value << state->bits;
+ state->bits += (uInt)bits;
return Z_OK;
}
@@ -628,7 +642,7 @@ int flush;
static const unsigned short order[19] = /* permutation of code lengths */
{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
- if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ if (inflateStateCheck(strm) || strm->next_out == Z_NULL ||
(strm->next_in == Z_NULL && strm->avail_in != 0))
return Z_STREAM_ERROR;
@@ -648,6 +662,8 @@ int flush;
NEEDBITS(16);
#ifdef GUNZIP
if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ if (state->wbits == 0)
+ state->wbits = 15;
state->check = crc32(0L, Z_NULL, 0);
CRC2(state->check, hold);
INITBITS();
@@ -675,7 +691,7 @@ int flush;
len = BITS(4) + 8;
if (state->wbits == 0)
state->wbits = len;
- else if (len > state->wbits) {
+ if (len > 15 || len > state->wbits) {
strm->msg = (char *)"invalid window size";
state->mode = BAD;
break;
@@ -702,14 +718,16 @@ int flush;
}
if (state->head != Z_NULL)
state->head->text = (int)((hold >> 8) & 1);
- if (state->flags & 0x0200) CRC2(state->check, hold);
+ if ((state->flags & 0x0200) && (state->wrap & 4))
+ CRC2(state->check, hold);
INITBITS();
state->mode = TIME;
case TIME:
NEEDBITS(32);
if (state->head != Z_NULL)
state->head->time = hold;
- if (state->flags & 0x0200) CRC4(state->check, hold);
+ if ((state->flags & 0x0200) && (state->wrap & 4))
+ CRC4(state->check, hold);
INITBITS();
state->mode = OS;
case OS:
@@ -718,7 +736,8 @@ int flush;
state->head->xflags = (int)(hold & 0xff);
state->head->os = (int)(hold >> 8);
}
- if (state->flags & 0x0200) CRC2(state->check, hold);
+ if ((state->flags & 0x0200) && (state->wrap & 4))
+ CRC2(state->check, hold);
INITBITS();
state->mode = EXLEN;
case EXLEN:
@@ -727,7 +746,8 @@ int flush;
state->length = (unsigned)(hold);
if (state->head != Z_NULL)
state->head->extra_len = (unsigned)hold;
- if (state->flags & 0x0200) CRC2(state->check, hold);
+ if ((state->flags & 0x0200) && (state->wrap & 4))
+ CRC2(state->check, hold);
INITBITS();
}
else if (state->head != Z_NULL)
@@ -745,7 +765,7 @@ int flush;
len + copy > state->head->extra_max ?
state->head->extra_max - len : copy);
}
- if (state->flags & 0x0200)
+ if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@@ -764,9 +784,9 @@ int flush;
if (state->head != Z_NULL &&
state->head->name != Z_NULL &&
state->length < state->head->name_max)
- state->head->name[state->length++] = len;
+ state->head->name[state->length++] = (Bytef)len;
} while (len && copy < have);
- if (state->flags & 0x0200)
+ if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@@ -785,9 +805,9 @@ int flush;
if (state->head != Z_NULL &&
state->head->comment != Z_NULL &&
state->length < state->head->comm_max)
- state->head->comment[state->length++] = len;
+ state->head->comment[state->length++] = (Bytef)len;
} while (len && copy < have);
- if (state->flags & 0x0200)
+ if ((state->flags & 0x0200) && (state->wrap & 4))
state->check = crc32(state->check, next, copy);
have -= copy;
next += copy;
@@ -799,7 +819,7 @@ int flush;
case HCRC:
if (state->flags & 0x0200) {
NEEDBITS(16);
- if (hold != (state->check & 0xffff)) {
+ if ((state->wrap & 4) && hold != (state->check & 0xffff)) {
strm->msg = (char *)"header crc mismatch";
state->mode = BAD;
break;
@@ -1180,11 +1200,11 @@ int flush;
out -= left;
strm->total_out += out;
state->total += out;
- if (out)
+ if ((state->wrap & 4) && out)
strm->adler = state->check =
UPDATE(state->check, put - out, out);
out = left;
- if ((
+ if ((state->wrap & 4) && (
#ifdef GUNZIP
state->flags ? hold :
#endif
@@ -1243,10 +1263,10 @@ int flush;
strm->total_in += in;
strm->total_out += out;
state->total += out;
- if (state->wrap && out)
+ if ((state->wrap & 4) && out)
strm->adler = state->check =
UPDATE(state->check, strm->next_out - out, out);
- strm->data_type = state->bits + (state->last ? 64 : 0) +
+ strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
(state->mode == TYPE ? 128 : 0) +
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
@@ -1258,7 +1278,7 @@ int ZEXPORT inflateEnd(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ if (inflateStateCheck(strm))
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (state->window != Z_NULL) ZFREE(strm, state->window);
@@ -1276,7 +1296,7 @@ uInt *dictLength;
struct inflate_state FAR *state;
/* check state */
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
/* copy dictionary */
@@ -1301,7 +1321,7 @@ uInt dictLength;
int ret;
/* check state */
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (state->wrap != 0 && state->mode != DICT)
return Z_STREAM_ERROR;
@@ -1333,7 +1353,7 @@ gz_headerp head;
struct inflate_state FAR *state;
/* check state */
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
@@ -1386,7 +1406,7 @@ z_streamp strm;
struct inflate_state FAR *state;
/* check parameters */
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
@@ -1433,7 +1453,7 @@ z_streamp strm;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
return state->mode == STORED && state->bits == 0;
}
@@ -1448,8 +1468,7 @@ z_streamp source;
unsigned wsize;
/* check input */
- if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
- source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ if (inflateStateCheck(source) || dest == Z_NULL)
return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)source->state;
@@ -1470,6 +1489,7 @@ z_streamp source;
/* copy state */
zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));
zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state));
+ copy->strm = dest;
if (state->lencode >= state->codes &&
state->lencode <= state->codes + ENOUGH - 1) {
copy->lencode = copy->codes + (state->lencode - state->codes);
@@ -1491,25 +1511,51 @@ int subvert;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
state = (struct inflate_state FAR *)strm->state;
- state->sane = !subvert;
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+ state->sane = !subvert;
return Z_OK;
#else
+ (void)subvert;
state->sane = 1;
return Z_DATA_ERROR;
#endif
}
+int ZEXPORT inflateValidate(strm, check)
+z_streamp strm;
+int check;
+{
+ struct inflate_state FAR *state;
+
+ if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (check)
+ state->wrap |= 4;
+ else
+ state->wrap &= ~4;
+ return Z_OK;
+}
+
long ZEXPORT inflateMark(strm)
z_streamp strm;
{
struct inflate_state FAR *state;
- if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16;
+ if (inflateStateCheck(strm))
+ return -(1L << 16);
state = (struct inflate_state FAR *)strm->state;
- return ((long)(state->back) << 16) +
+ return (long)(((unsigned long)((long)state->back)) << 16) +
(state->mode == COPY ? state->length :
(state->mode == MATCH ? state->was - state->length : 0));
}
+
+unsigned long ZEXPORT inflateCodesUsed(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (inflateStateCheck(strm)) return (unsigned long)-1;
+ state = (struct inflate_state FAR *)strm->state;
+ return (unsigned long)(state->next - state->codes);
+}
diff --git a/erts/emulator/zlib/inflate.h b/erts/emulator/zlib/inflate.h
index 95f4986d40..a46cce6b6d 100644
--- a/erts/emulator/zlib/inflate.h
+++ b/erts/emulator/zlib/inflate.h
@@ -1,5 +1,5 @@
/* inflate.h -- internal inflate state definition
- * Copyright (C) 1995-2009 Mark Adler
+ * Copyright (C) 1995-2016 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -18,7 +18,7 @@
/* Possible inflate modes between inflate() calls */
typedef enum {
- HEAD, /* i: waiting for magic header */
+ HEAD = 16180, /* i: waiting for magic header */
FLAGS, /* i: waiting for method and flags (gzip) */
TIME, /* i: waiting for modification time (gzip) */
OS, /* i: waiting for extra flags and operating system (gzip) */
@@ -77,11 +77,14 @@ typedef enum {
CHECK -> LENGTH -> DONE
*/
-/* state maintained between inflate() calls. Approximately 10K bytes. */
+/* State maintained between inflate() calls -- approximately 7K bytes, not
+ including the allocated sliding window, which is up to 32K bytes. */
struct inflate_state {
+ z_streamp strm; /* pointer back to this zlib stream */
inflate_mode mode; /* current inflate mode */
int last; /* true if processing last block */
- int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
+ bit 2 true to validate check value */
int havedict; /* true if dictionary provided */
int flags; /* gzip header method and flags (0 if zlib) */
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
diff --git a/erts/emulator/zlib/inftrees.c b/erts/emulator/zlib/inftrees.c
index 3766fa2646..2ea08fc13e 100644
--- a/erts/emulator/zlib/inftrees.c
+++ b/erts/emulator/zlib/inftrees.c
@@ -1,18 +1,15 @@
/* inftrees.c -- generate Huffman trees for efficient decoding
- * Copyright (C) 1995-2013 Mark Adler
+ * Copyright (C) 1995-2017 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "zutil.h"
#include "inftrees.h"
#define MAXBITS 15
const char inflate_copyright[] =
- " inflate 1.2.8 Copyright 1995-2013 Mark Adler ";
+ " inflate 1.2.11 Copyright 1995-2017 Mark Adler ";
/*
If you use the zlib library in a product, an acknowledgment is welcome
in the documentation of your product. If for some reason you cannot
@@ -57,7 +54,7 @@ unsigned short FAR *work;
code FAR *next; /* next available space in table */
const unsigned short FAR *base; /* base value table to use */
const unsigned short FAR *extra; /* extra bits table to use */
- int end; /* use base and extra for symbol > end */
+ unsigned match; /* use base and extra for symbol >= match */
unsigned short count[MAXBITS+1]; /* number of codes of each length */
unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
static const unsigned short lbase[31] = { /* Length codes 257..285 base */
@@ -65,7 +62,7 @@ unsigned short FAR *work;
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
- 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78};
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
@@ -184,19 +181,17 @@ unsigned short FAR *work;
switch (type) {
case CODES:
base = extra = work; /* dummy value--not used */
- end = 19;
+ match = 20;
break;
case LENS:
base = lbase;
- base -= 257;
extra = lext;
- extra -= 257;
- end = 256;
+ match = 257;
break;
- default: /* DISTS */
+ default: /* DISTS */
base = dbase;
extra = dext;
- end = -1;
+ match = 0;
}
/* initialize state for loop */
@@ -219,13 +214,13 @@ unsigned short FAR *work;
for (;;) {
/* create table entry */
here.bits = (unsigned char)(len - drop);
- if ((int)(work[sym]) < end) {
+ if (work[sym] + 1U < match) {
here.op = (unsigned char)0;
here.val = work[sym];
}
- else if ((int)(work[sym]) > end) {
- here.op = (unsigned char)(extra[work[sym]]);
- here.val = base[work[sym]];
+ else if (work[sym] >= match) {
+ here.op = (unsigned char)(extra[work[sym] - match]);
+ here.val = base[work[sym] - match];
}
else {
here.op = (unsigned char)(32 + 64); /* end of block */
diff --git a/erts/emulator/zlib/trees.c b/erts/emulator/zlib/trees.c
index 465e944e5b..50cf4b4571 100644
--- a/erts/emulator/zlib/trees.c
+++ b/erts/emulator/zlib/trees.c
@@ -1,5 +1,5 @@
/* trees.c -- output deflated data using Huffman coding
- * Copyright (C) 1995-2012 Jean-loup Gailly
+ * Copyright (C) 1995-2017 Jean-loup Gailly
* detect_data_type() function provided freely by Cosmin Truta, 2006
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -34,12 +34,9 @@
/* #define GEN_TREES_H */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "deflate.h"
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
# include <ctype.h>
#endif
@@ -125,13 +122,13 @@ struct static_tree_desc_s {
int max_length; /* max bit length for the codes */
};
-local static_tree_desc static_l_desc =
+local const static_tree_desc static_l_desc =
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
-local static_tree_desc static_d_desc =
+local const static_tree_desc static_d_desc =
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
-local static_tree_desc static_bl_desc =
+local const static_tree_desc static_bl_desc =
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
/* ===========================================================================
@@ -155,18 +152,16 @@ local int detect_data_type OF((deflate_state *s));
local unsigned bi_reverse OF((unsigned value, int length));
local void bi_windup OF((deflate_state *s));
local void bi_flush OF((deflate_state *s));
-local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
- int header));
#ifdef GEN_TREES_H
local void gen_trees_header OF((void));
#endif
-#ifndef DEBUG
+#ifndef ZLIB_DEBUG
# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
/* Send a code of the given tree. c and tree must not have side effects */
-#else /* DEBUG */
+#else /* !ZLIB_DEBUG */
# define send_code(s, c, tree) \
{ if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
send_bits(s, tree[c].Code, tree[c].Len); }
@@ -185,7 +180,7 @@ local void gen_trees_header OF((void));
* Send a value on a given number of bits.
* IN assertion: length <= 16 and value fits in length bits.
*/
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
local void send_bits OF((deflate_state *s, int value, int length));
local void send_bits(s, value, length)
@@ -211,12 +206,12 @@ local void send_bits(s, value, length)
s->bi_valid += length;
}
}
-#else /* !DEBUG */
+#else /* !ZLIB_DEBUG */
#define send_bits(s, value, length) \
{ int len = length;\
if (s->bi_valid > (int)Buf_size - len) {\
- int val = value;\
+ int val = (int)value;\
s->bi_buf |= (ush)val << s->bi_valid;\
put_short(s, s->bi_buf);\
s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
@@ -226,7 +221,7 @@ local void send_bits(s, value, length)
s->bi_valid += len;\
}\
}
-#endif /* DEBUG */
+#endif /* ZLIB_DEBUG */
/* the arguments must not have side effects */
@@ -320,7 +315,7 @@ local void tr_static_init()
* Genererate the file trees.h describing the static trees.
*/
#ifdef GEN_TREES_H
-# ifndef DEBUG
+# ifndef ZLIB_DEBUG
# include <stdio.h>
# endif
@@ -397,7 +392,7 @@ void ZLIB_INTERNAL _tr_init(s)
s->bi_buf = 0;
s->bi_valid = 0;
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->compressed_len = 0L;
s->bits_sent = 0L;
#endif
@@ -525,12 +520,12 @@ local void gen_bitlen(s, desc)
xbits = 0;
if (n >= base) xbits = extra[n-base];
f = tree[n].Freq;
- s->opt_len += (ulg)f * (bits + xbits);
- if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ s->opt_len += (ulg)f * (unsigned)(bits + xbits);
+ if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
}
if (overflow == 0) return;
- Trace((stderr,"\nbit length overflow\n"));
+ Tracev((stderr,"\nbit length overflow\n"));
/* This happens for example on obj2 and pic of the Calgary corpus */
/* Find the first bit length which could increase: */
@@ -557,9 +552,8 @@ local void gen_bitlen(s, desc)
m = s->heap[--h];
if (m > max_code) continue;
if ((unsigned) tree[m].Len != (unsigned) bits) {
- Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
- s->opt_len += ((long)bits - (long)tree[m].Len)
- *(long)tree[m].Freq;
+ Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq;
tree[m].Len = (ush)bits;
}
n--;
@@ -581,7 +575,7 @@ local void gen_codes (tree, max_code, bl_count)
ushf *bl_count; /* number of codes at each bit length */
{
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
- ush code = 0; /* running code value */
+ unsigned code = 0; /* running code value */
int bits; /* bit index */
int n; /* code index */
@@ -589,7 +583,8 @@ local void gen_codes (tree, max_code, bl_count)
* without bit reversal.
*/
for (bits = 1; bits <= MAX_BITS; bits++) {
- next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ code = (code + bl_count[bits-1]) << 1;
+ next_code[bits] = (ush)code;
}
/* Check that the bit counts in bl_count are consistent. The last code
* must be all ones.
@@ -602,7 +597,7 @@ local void gen_codes (tree, max_code, bl_count)
int len = tree[n].Len;
if (len == 0) continue;
/* Now reverse the bits */
- tree[n].Code = bi_reverse(next_code[len]++, len);
+ tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
@@ -824,7 +819,7 @@ local int build_bl_tree(s)
if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
}
/* Update opt_len to include the bit length tree and counts */
- s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
s->opt_len, s->static_len));
@@ -872,11 +867,17 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
int last; /* one if this is the last block for a file */
{
send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
-#ifdef DEBUG
+ bi_windup(s); /* align on byte boundary */
+ put_short(s, (ush)stored_len);
+ put_short(s, (ush)~stored_len);
+ zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
+ s->pending += stored_len;
+#ifdef ZLIB_DEBUG
s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
s->compressed_len += (stored_len + 4) << 3;
+ s->bits_sent += 2*16;
+ s->bits_sent += stored_len<<3;
#endif
- copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
}
/* ===========================================================================
@@ -897,7 +898,7 @@ void ZLIB_INTERNAL _tr_align(s)
{
send_bits(s, STATIC_TREES<<1, 3);
send_code(s, END_BLOCK, static_ltree);
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
#endif
bi_flush(s);
@@ -905,7 +906,7 @@ void ZLIB_INTERNAL _tr_align(s)
/* ===========================================================================
* Determine the best encoding for the current block: dynamic trees, static
- * trees or store, and output the encoded block to the zip file.
+ * trees or store, and write out the encoded block.
*/
void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
deflate_state *s;
@@ -977,7 +978,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
send_bits(s, (STATIC_TREES<<1)+last, 3);
compress_block(s, (const ct_data *)static_ltree,
(const ct_data *)static_dtree);
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->static_len;
#endif
} else {
@@ -986,7 +987,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
max_blindex+1);
compress_block(s, (const ct_data *)s->dyn_ltree,
(const ct_data *)s->dyn_dtree);
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->compressed_len += 3 + s->opt_len;
#endif
}
@@ -998,7 +999,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
if (last) {
bi_windup(s);
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->compressed_len += 7; /* align on byte boundary */
#endif
}
@@ -1093,7 +1094,7 @@ local void compress_block(s, ltree, dtree)
send_code(s, code, dtree); /* send the distance code */
extra = extra_dbits[code];
if (extra != 0) {
- dist -= base_dist[code];
+ dist -= (unsigned)base_dist[code];
send_bits(s, dist, extra); /* send the extra distance bits */
}
} /* literal or match pair ? */
@@ -1196,34 +1197,7 @@ local void bi_windup(s)
}
s->bi_buf = 0;
s->bi_valid = 0;
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
s->bits_sent = (s->bits_sent+7) & ~7;
#endif
}
-
-/* ===========================================================================
- * Copy a stored block, storing first the length and its
- * one's complement if requested.
- */
-local void copy_block(s, buf, len, header)
- deflate_state *s;
- charf *buf; /* the input data */
- unsigned len; /* its length */
- int header; /* true if block header must be written */
-{
- bi_windup(s); /* align on byte boundary */
-
- if (header) {
- put_short(s, (ush)len);
- put_short(s, (ush)~len);
-#ifdef DEBUG
- s->bits_sent += 2*16;
-#endif
- }
-#ifdef DEBUG
- s->bits_sent += (ulg)len<<3;
-#endif
- while (len--) {
- put_byte(s, *buf++);
- }
-}
diff --git a/erts/emulator/zlib/uncompr.c b/erts/emulator/zlib/uncompr.c
index 864d571719..f03a1a865e 100644
--- a/erts/emulator/zlib/uncompr.c
+++ b/erts/emulator/zlib/uncompr.c
@@ -1,62 +1,93 @@
/* uncompr.c -- decompress a memory buffer
- * Copyright (C) 1995-2003, 2010 Jean-loup Gailly.
+ * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#define ZLIB_INTERNAL
#include "zlib.h"
/* ===========================================================================
- Decompresses the source buffer into the destination buffer. sourceLen is
- the byte length of the source buffer. Upon entry, destLen is the total
- size of the destination buffer, which must be large enough to hold the
- entire uncompressed data. (The size of the uncompressed data must have
- been saved previously by the compressor and transmitted to the decompressor
- by some mechanism outside the scope of this compression library.)
- Upon exit, destLen is the actual size of the compressed buffer.
-
- uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
- enough memory, Z_BUF_ERROR if there was not enough room in the output
- buffer, or Z_DATA_ERROR if the input data was corrupted.
+ Decompresses the source buffer into the destination buffer. *sourceLen is
+ the byte length of the source buffer. Upon entry, *destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit,
+ *destLen is the size of the decompressed data and *sourceLen is the number
+ of source bytes consumed. Upon return, source + *sourceLen points to the
+ first unused input byte.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer, or
+ Z_DATA_ERROR if the input data was corrupted, including if the input data is
+ an incomplete zlib stream.
*/
-int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
Bytef *dest;
uLongf *destLen;
const Bytef *source;
- uLong sourceLen;
+ uLong *sourceLen;
{
z_stream stream;
int err;
+ const uInt max = (uInt)-1;
+ uLong len, left;
+ Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */
- stream.next_in = (z_const Bytef *)source;
- stream.avail_in = (uInt)sourceLen;
- /* Check for source > 64K on 16-bit machine: */
- if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
-
- stream.next_out = dest;
- stream.avail_out = (uInt)*destLen;
- if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+ len = *sourceLen;
+ if (*destLen) {
+ left = *destLen;
+ *destLen = 0;
+ }
+ else {
+ left = 1;
+ dest = buf;
+ }
+ stream.next_in = (z_const Bytef *)source;
+ stream.avail_in = 0;
stream.zalloc = (alloc_func)0;
stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
err = inflateInit(&stream);
if (err != Z_OK) return err;
- err = inflate(&stream, Z_FINISH);
- if (err != Z_STREAM_END) {
- inflateEnd(&stream);
- if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
- return Z_DATA_ERROR;
- return err;
- }
- *destLen = stream.total_out;
+ stream.next_out = dest;
+ stream.avail_out = 0;
- err = inflateEnd(&stream);
- return err;
+ do {
+ if (stream.avail_out == 0) {
+ stream.avail_out = left > (uLong)max ? max : (uInt)left;
+ left -= stream.avail_out;
+ }
+ if (stream.avail_in == 0) {
+ stream.avail_in = len > (uLong)max ? max : (uInt)len;
+ len -= stream.avail_in;
+ }
+ err = inflate(&stream, Z_NO_FLUSH);
+ } while (err == Z_OK);
+
+ *sourceLen -= len + stream.avail_in;
+ if (dest != buf)
+ *destLen = stream.total_out;
+ else if (stream.total_out && err == Z_BUF_ERROR)
+ left = 1;
+
+ inflateEnd(&stream);
+ return err == Z_STREAM_END ? Z_OK :
+ err == Z_NEED_DICT ? Z_DATA_ERROR :
+ err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR :
+ err;
+}
+
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return uncompress2(dest, destLen, source, &sourceLen);
}
diff --git a/erts/emulator/zlib/zconf.h b/erts/emulator/zlib/zconf.h
index 9987a77553..5e1d68a004 100644
--- a/erts/emulator/zlib/zconf.h
+++ b/erts/emulator/zlib/zconf.h
@@ -1,5 +1,5 @@
/* zconf.h -- configuration of the zlib compression library
- * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -17,7 +17,7 @@
#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
# define Z_PREFIX_SET
-/* all linked symbols */
+/* all linked symbols and init macros */
# define _dist_code z__dist_code
# define _length_code z__length_code
# define _tr_align z__tr_align
@@ -29,6 +29,7 @@
# define adler32 z_adler32
# define adler32_combine z_adler32_combine
# define adler32_combine64 z_adler32_combine64
+# define adler32_z z_adler32_z
# ifndef Z_SOLO
# define compress z_compress
# define compress2 z_compress2
@@ -37,10 +38,14 @@
# define crc32 z_crc32
# define crc32_combine z_crc32_combine
# define crc32_combine64 z_crc32_combine64
+# define crc32_z z_crc32_z
# define deflate z_deflate
# define deflateBound z_deflateBound
# define deflateCopy z_deflateCopy
# define deflateEnd z_deflateEnd
+# define deflateGetDictionary z_deflateGetDictionary
+# define deflateInit z_deflateInit
+# define deflateInit2 z_deflateInit2
# define deflateInit2_ z_deflateInit2_
# define deflateInit_ z_deflateInit_
# define deflateParams z_deflateParams
@@ -67,6 +72,8 @@
# define gzeof z_gzeof
# define gzerror z_gzerror
# define gzflush z_gzflush
+# define gzfread z_gzfread
+# define gzfwrite z_gzfwrite
# define gzgetc z_gzgetc
# define gzgetc_ z_gzgetc_
# define gzgets z_gzgets
@@ -78,7 +85,6 @@
# define gzopen_w z_gzopen_w
# endif
# define gzprintf z_gzprintf
-# define gzvprintf z_gzvprintf
# define gzputc z_gzputc
# define gzputs z_gzputs
# define gzread z_gzread
@@ -89,32 +95,39 @@
# define gztell z_gztell
# define gztell64 z_gztell64
# define gzungetc z_gzungetc
+# define gzvprintf z_gzvprintf
# define gzwrite z_gzwrite
# endif
# define inflate z_inflate
# define inflateBack z_inflateBack
# define inflateBackEnd z_inflateBackEnd
+# define inflateBackInit z_inflateBackInit
# define inflateBackInit_ z_inflateBackInit_
+# define inflateCodesUsed z_inflateCodesUsed
# define inflateCopy z_inflateCopy
# define inflateEnd z_inflateEnd
+# define inflateGetDictionary z_inflateGetDictionary
# define inflateGetHeader z_inflateGetHeader
+# define inflateInit z_inflateInit
+# define inflateInit2 z_inflateInit2
# define inflateInit2_ z_inflateInit2_
# define inflateInit_ z_inflateInit_
# define inflateMark z_inflateMark
# define inflatePrime z_inflatePrime
# define inflateReset z_inflateReset
# define inflateReset2 z_inflateReset2
+# define inflateResetKeep z_inflateResetKeep
# define inflateSetDictionary z_inflateSetDictionary
-# define inflateGetDictionary z_inflateGetDictionary
# define inflateSync z_inflateSync
# define inflateSyncPoint z_inflateSyncPoint
# define inflateUndermine z_inflateUndermine
-# define inflateResetKeep z_inflateResetKeep
+# define inflateValidate z_inflateValidate
# define inflate_copyright z_inflate_copyright
# define inflate_fast z_inflate_fast
# define inflate_table z_inflate_table
# ifndef Z_SOLO
# define uncompress z_uncompress
+# define uncompress2 z_uncompress2
# endif
# define zError z_zError
# ifndef Z_SOLO
@@ -224,9 +237,19 @@
# define z_const
#endif
-/* Some Mac compilers merge all .h files incorrectly: */
-#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
-# define NO_DUMMY_DECL
+#ifdef Z_SOLO
+ typedef unsigned long z_size_t;
+#else
+# define z_longlong long long
+# if defined(NO_SIZE_T)
+ typedef unsigned NO_SIZE_T z_size_t;
+# elif defined(STDC)
+# include <stddef.h>
+ typedef size_t z_size_t;
+# else
+ typedef unsigned long z_size_t;
+# endif
+# undef z_longlong
#endif
/* Maximum value for memLevel in deflateInit2 */
@@ -256,7 +279,7 @@
Of course this will generally degrade compression (there's no free lunch).
The memory requirements for inflate are (in bytes) 1 << windowBits
- that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ that is, 32K for windowBits=15 (default value) plus about 7 kilobytes
for small objects.
*/
diff --git a/erts/emulator/zlib/zlib.h b/erts/emulator/zlib/zlib.h
index 3e0c7672ac..f09cdaf1e0 100644
--- a/erts/emulator/zlib/zlib.h
+++ b/erts/emulator/zlib/zlib.h
@@ -1,7 +1,7 @@
/* zlib.h -- interface of the 'zlib' general purpose compression library
- version 1.2.8, April 28th, 2013
+ version 1.2.11, January 15th, 2017
- Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler
+ Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@@ -37,11 +37,11 @@
extern "C" {
#endif
-#define ZLIB_VERSION "1.2.8"
-#define ZLIB_VERNUM 0x1280
+#define ZLIB_VERSION "1.2.11"
+#define ZLIB_VERNUM 0x12b0
#define ZLIB_VER_MAJOR 1
#define ZLIB_VER_MINOR 2
-#define ZLIB_VER_REVISION 8
+#define ZLIB_VER_REVISION 11
#define ZLIB_VER_SUBREVISION 0
/*
@@ -65,7 +65,8 @@ extern "C" {
with "gz". The gzip format is different from the zlib format. gzip is a
gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
- This library can optionally read and write gzip streams in memory as well.
+ This library can optionally read and write gzip and raw deflate streams in
+ memory as well.
The zlib format was designed to be compact and fast for use in memory
and on communications channels. The gzip format was designed for single-
@@ -74,7 +75,7 @@ extern "C" {
The library does not install any signal handler. The decoder checks
the consistency of the compressed data, so the library should never crash
- even in case of corrupted input.
+ even in the case of corrupted input.
*/
typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
@@ -87,7 +88,7 @@ typedef struct z_stream_s {
uInt avail_in; /* number of bytes available at next_in */
uLong total_in; /* total number of input bytes read so far */
- Bytef *next_out; /* next output byte should be put there */
+ Bytef *next_out; /* next output byte will go here */
uInt avail_out; /* remaining free space at next_out */
uLong total_out; /* total number of bytes output so far */
@@ -98,8 +99,9 @@ typedef struct z_stream_s {
free_func zfree; /* used to free the internal state */
voidpf opaque; /* private data object passed to zalloc and zfree */
- int data_type; /* best guess about the data type: binary or text */
- uLong adler; /* adler32 value of the uncompressed data */
+ int data_type; /* best guess about the data type: binary or text
+ for deflate, or the decoding state for inflate */
+ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */
uLong reserved; /* reserved for future use */
} z_stream;
@@ -142,7 +144,9 @@ typedef gz_header FAR *gz_headerp;
zalloc must return Z_NULL if there is not enough memory for the object.
If zlib is used in a multi-threaded application, zalloc and zfree must be
- thread safe.
+ thread safe. In that case, zlib is thread-safe. When zalloc and zfree are
+ Z_NULL on entry to the initialization function, they are set to internal
+ routines that use the standard library functions malloc() and free().
On 16-bit systems, the functions zalloc and zfree must be able to allocate
exactly 65536 bytes, but will not be required to allocate more than this if
@@ -155,7 +159,7 @@ typedef gz_header FAR *gz_headerp;
The fields total_in and total_out can be used for statistics or progress
reports. After compression, total_in holds the total size of the
- uncompressed data and may be saved for use in the decompressor (particularly
+ uncompressed data and may be saved for use by the decompressor (particularly
if the decompressor wants to decompress everything in a single step).
*/
@@ -200,7 +204,7 @@ typedef gz_header FAR *gz_headerp;
#define Z_TEXT 1
#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
#define Z_UNKNOWN 2
-/* Possible values of the data_type field (though see inflate()) */
+/* Possible values of the data_type field for deflate() */
#define Z_DEFLATED 8
/* The deflate compression method (the only one supported in this version) */
@@ -258,11 +262,11 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
enough room in the output buffer), next_in and avail_in are updated and
processing will resume at this point for the next call of deflate().
- - Provide more output starting at next_out and update next_out and avail_out
+ - Generate more output starting at next_out and update next_out and avail_out
accordingly. This action is forced if the parameter flush is non zero.
Forcing flush frequently degrades the compression ratio, so this parameter
- should be set only when necessary (in interactive applications). Some
- output may be provided even if flush is not set.
+ should be set only when necessary. Some output may be provided even if
+ flush is zero.
Before the call of deflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming more
@@ -271,7 +275,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
output when it wants, for example when the output buffer is full (avail_out
== 0), or after each call of deflate(). If deflate returns Z_OK and with
zero avail_out, it must be called again after making room in the output
- buffer because there might be more output pending.
+ buffer because there might be more output pending. See deflatePending(),
+ which can be used if desired to determine whether or not there is more ouput
+ in that case.
Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
decide how much data to accumulate before producing output, in order to
@@ -292,8 +298,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
This completes the current deflate block and follows it with an empty fixed
codes block that is 10 bits long. This assures that enough bytes are output
- in order for the decompressor to finish the block before the empty fixed code
- block.
+ in order for the decompressor to finish the block before the empty fixed
+ codes block.
If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
@@ -319,34 +325,38 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
If the parameter flush is set to Z_FINISH, pending input is processed,
pending output is flushed and deflate returns with Z_STREAM_END if there was
- enough output space; if deflate returns with Z_OK, this function must be
- called again with Z_FINISH and more output space (updated avail_out) but no
- more input data, until it returns with Z_STREAM_END or an error. After
- deflate has returned Z_STREAM_END, the only possible operations on the stream
- are deflateReset or deflateEnd.
-
- Z_FINISH can be used immediately after deflateInit if all the compression
- is to be done in a single step. In this case, avail_out must be at least the
- value returned by deflateBound (see below). Then deflate is guaranteed to
- return Z_STREAM_END. If not enough output space is provided, deflate will
- not return Z_STREAM_END, and it must be called again as described above.
-
- deflate() sets strm->adler to the adler32 checksum of all input read
- so far (that is, total_in bytes).
+ enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this
+ function must be called again with Z_FINISH and more output space (updated
+ avail_out) but no more input data, until it returns with Z_STREAM_END or an
+ error. After deflate has returned Z_STREAM_END, the only possible operations
+ on the stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used in the first deflate call after deflateInit if all the
+ compression is to be done in a single step. In order to complete in one
+ call, avail_out must be at least the value returned by deflateBound (see
+ below). Then deflate is guaranteed to return Z_STREAM_END. If not enough
+ output space is provided, deflate will not return Z_STREAM_END, and it must
+ be called again as described above.
+
+ deflate() sets strm->adler to the Adler-32 checksum of all input read
+ so far (that is, total_in bytes). If a gzip stream is being generated, then
+ strm->adler will be the CRC-32 checksum of the input read so far. (See
+ deflateInit2 below.)
deflate() may update strm->data_type if it can make a good guess about
- the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
- binary. This field is only for information purposes and does not affect the
- compression algorithm in any manner.
+ the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is
+ considered binary. This field is only for information purposes and does not
+ affect the compression algorithm in any manner.
deflate() returns Z_OK if some progress has been made (more input
processed or more output produced), Z_STREAM_END if all input has been
consumed and all output has been produced (only when flush is set to
Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
- if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
- (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
- fatal, and deflate() can be called again with more input and more output
- space to continue compressing.
+ if next_in or next_out was Z_NULL or the state was inadvertently written over
+ by the application), or Z_BUF_ERROR if no progress is possible (for example
+ avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and
+ deflate() can be called again with more input and more output space to
+ continue compressing.
*/
@@ -369,23 +379,21 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
Initializes the internal stream state for decompression. The fields
next_in, avail_in, zalloc, zfree and opaque must be initialized before by
- the caller. If next_in is not Z_NULL and avail_in is large enough (the
- exact value depends on the compression method), inflateInit determines the
- compression method from the zlib header and allocates all data structures
- accordingly; otherwise the allocation will be deferred to the first call of
- inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
- use default allocation functions.
+ the caller. In the current version of inflate, the provided input is not
+ read or consumed. The allocation of a sliding window will be deferred to
+ the first call of inflate (if the decompression does not complete on the
+ first call). If zalloc and zfree are set to Z_NULL, inflateInit updates
+ them to use default allocation functions.
inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
version assumed by the caller, or Z_STREAM_ERROR if the parameters are
invalid, such as a null pointer to the structure. msg is set to null if
- there is no error message. inflateInit does not perform any decompression
- apart from possibly reading the zlib header if present: actual decompression
- will be done by inflate(). (So next_in and avail_in may be modified, but
- next_out and avail_out are unused and unchanged.) The current implementation
- of inflateInit() does not process any header information -- that is deferred
- until inflate() is called.
+ there is no error message. inflateInit does not perform any decompression.
+ Actual decompression will be done by inflate(). So next_in, and avail_in,
+ next_out, and avail_out are unused and unchanged. The current
+ implementation of inflateInit() does not process any header information --
+ that is deferred until inflate() is called.
*/
@@ -401,17 +409,20 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
- Decompress more input starting at next_in and update next_in and avail_in
accordingly. If not all input can be processed (because there is not
- enough room in the output buffer), next_in is updated and processing will
- resume at this point for the next call of inflate().
+ enough room in the output buffer), then next_in and avail_in are updated
+ accordingly, and processing will resume at this point for the next call of
+ inflate().
- - Provide more output starting at next_out and update next_out and avail_out
+ - Generate more output starting at next_out and update next_out and avail_out
accordingly. inflate() provides as much output as possible, until there is
no more input data or no more space in the output buffer (see below about
the flush parameter).
Before the call of inflate(), the application should ensure that at least
one of the actions is possible, by providing more input and/or consuming more
- output, and updating the next_* and avail_* values accordingly. The
+ output, and updating the next_* and avail_* values accordingly. If the
+ caller of inflate() does not provide both available input and available
+ output space, it is possible that there will be no progress made. The
application can consume the uncompressed output when it wants, for example
when the output buffer is full (avail_out == 0), or after each call of
inflate(). If inflate returns Z_OK and with zero avail_out, it must be
@@ -428,7 +439,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
gets to the end of that block, or when it runs out of data.
The Z_BLOCK option assists in appending to or combining deflate streams.
- Also to assist in this, on return inflate() will set strm->data_type to the
+ To assist in this, on return inflate() always sets strm->data_type to the
number of unused bits in the last byte taken from strm->next_in, plus 64 if
inflate() is currently decoding the last block in the deflate stream, plus
128 if inflate() returned immediately after decoding an end-of-block code or
@@ -454,7 +465,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
this case all pending input is processed and all pending output is flushed;
avail_out must be large enough to hold all of the uncompressed data for the
operation to complete. (The size of the uncompressed data may have been
- saved by the compressor for this purpose.) The use of Z_FINISH is not
+ saved by the compressor for this purpose.) The use of Z_FINISH is not
required to perform an inflation in one step. However it may be used to
inform inflate that a faster approach can be used for the single inflate()
call. Z_FINISH also informs inflate to not maintain a sliding window if the
@@ -476,32 +487,33 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
strm->adler to the Adler-32 checksum of all output produced so far (that is,
total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
- below. At the end of the stream, inflate() checks that its computed adler32
+ below. At the end of the stream, inflate() checks that its computed Adler-32
checksum is equal to that saved by the compressor and returns Z_STREAM_END
only if the checksum is correct.
inflate() can decompress and check either zlib-wrapped or gzip-wrapped
deflate data. The header type is detected automatically, if requested when
initializing with inflateInit2(). Any information contained in the gzip
- header is not retained, so applications that need that information should
- instead use raw inflate, see inflateInit2() below, or inflateBack() and
- perform their own processing of the gzip header and trailer. When processing
+ header is not retained unless inflateGetHeader() is used. When processing
gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output
- producted so far. The CRC-32 is checked against the gzip trailer.
+ produced so far. The CRC-32 is checked against the gzip trailer, as is the
+ uncompressed length, modulo 2^32.
inflate() returns Z_OK if some progress has been made (more input processed
or more output produced), Z_STREAM_END if the end of the compressed data has
been reached and all uncompressed output has been produced, Z_NEED_DICT if a
preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
corrupted (input stream not conforming to the zlib format or incorrect check
- value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
- next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
- Z_BUF_ERROR if no progress is possible or if there was not enough room in the
- output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ value, in which case strm->msg points to a string with a more specific
+ error), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL, or the state was inadvertently written over
+ by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR
+ if no progress was possible or if there was not enough room in the output
+ buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
inflate() can be called again with more input and more output space to
continue decompressing. If Z_DATA_ERROR is returned, the application may
then call inflateSync() to look for a good compression block if a partial
- recovery of the data is desired.
+ recovery of the data is to be attempted.
*/
@@ -511,9 +523,8 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
This function discards any unprocessed input and does not flush any pending
output.
- inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
- was inconsistent. In the error case, msg may be set but then points to a
- static string (which must not be deallocated).
+ inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state
+ was inconsistent.
*/
@@ -544,16 +555,29 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
compression at the expense of memory usage. The default value is 15 if
deflateInit is used instead.
+ For the current implementation of deflate(), a windowBits value of 8 (a
+ window size of 256 bytes) is not supported. As a result, a request for 8
+ will result in 9 (a 512-byte window). In that case, providing 8 to
+ inflateInit2() will result in an error when the zlib header with 9 is
+ checked against the initialization of inflate(). The remedy is to not use 8
+ with deflateInit2() with this initialization, or at least in that case use 9
+ with inflateInit2().
+
windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
determines the window size. deflate() will then generate raw deflate data
- with no zlib header or trailer, and will not compute an adler32 check value.
+ with no zlib header or trailer, and will not compute a check value.
windowBits can also be greater than 15 for optional gzip encoding. Add
16 to windowBits to write a simple gzip header and trailer around the
compressed data instead of a zlib wrapper. The gzip header will have no
file name, no extra data, no comment, no modification time (set to zero), no
- header crc, and the operating system will be set to 255 (unknown). If a
- gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+ header crc, and the operating system will be set to the appropriate value,
+ if the operating system was determined at compile time. If a gzip stream is
+ being written, strm->adler is a CRC-32 instead of an Adler-32.
+
+ For raw deflate or gzip encoding, a request for a 256-byte window is
+ rejected as invalid, since only the zlib header provides a means of
+ transmitting the window size to the decompressor.
The memLevel parameter specifies how much memory should be allocated
for the internal compression state. memLevel=1 uses minimum memory but is
@@ -614,12 +638,12 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
addition, the current implementation of deflate will use at most the window
size minus 262 bytes of the provided dictionary.
- Upon return of this function, strm->adler is set to the adler32 value
+ Upon return of this function, strm->adler is set to the Adler-32 value
of the dictionary; the decompressor may later use this value to determine
- which dictionary has been used by the compressor. (The adler32 value
+ which dictionary has been used by the compressor. (The Adler-32 value
applies to the whole dictionary even if only a subset of the dictionary is
actually used by the compressor.) If a raw deflate was requested, then the
- adler32 value is not computed and strm->adler is not set.
+ Adler-32 value is not computed and strm->adler is not set.
deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
@@ -628,6 +652,28 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
not perform any compression: this will be done by deflate().
*/
+ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm,
+ Bytef *dictionary,
+ uInt *dictLength));
+/*
+ Returns the sliding dictionary being maintained by deflate. dictLength is
+ set to the number of bytes in the dictionary, and that many bytes are copied
+ to dictionary. dictionary must have enough space, where 32768 bytes is
+ always enough. If deflateGetDictionary() is called with dictionary equal to
+ Z_NULL, then only the dictionary length is returned, and nothing is copied.
+ Similary, if dictLength is Z_NULL, then it is not set.
+
+ deflateGetDictionary() may return a length less than the window size, even
+ when more than the window size in input has been provided. It may return up
+ to 258 bytes less in that case, due to how zlib's implementation of deflate
+ manages the sliding window and lookahead for matches, where matches can be
+ up to 258 bytes long. If the application needs the last window-size bytes of
+ input, then that would need to be saved by the application outside of zlib.
+
+ deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the
+ stream state is inconsistent.
+*/
+
ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
z_streamp source));
/*
@@ -648,10 +694,10 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
/*
- This function is equivalent to deflateEnd followed by deflateInit,
- but does not free and reallocate all the internal compression state. The
- stream will keep the same compression level and any other attributes that
- may have been set by deflateInit2.
+ This function is equivalent to deflateEnd followed by deflateInit, but
+ does not free and reallocate the internal compression state. The stream
+ will leave the compression level and any other attributes that may have been
+ set unchanged.
deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL).
@@ -662,20 +708,36 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
int strategy));
/*
Dynamically update the compression level and compression strategy. The
- interpretation of level and strategy is as in deflateInit2. This can be
+ interpretation of level and strategy is as in deflateInit2(). This can be
used to switch between compression and straight copy of the input data, or
to switch to a different kind of input data requiring a different strategy.
- If the compression level is changed, the input available so far is
- compressed with the old level (and may be flushed); the new level will take
- effect only at the next call of deflate().
-
- Before the call of deflateParams, the stream state must be set as for
- a call of deflate(), since the currently available input may have to be
- compressed and flushed. In particular, strm->avail_out must be non-zero.
-
- deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
- stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
- strm->avail_out was zero.
+ If the compression approach (which is a function of the level) or the
+ strategy is changed, and if any input has been consumed in a previous
+ deflate() call, then the input available so far is compressed with the old
+ level and strategy using deflate(strm, Z_BLOCK). There are three approaches
+ for the compression levels 0, 1..3, and 4..9 respectively. The new level
+ and strategy will take effect at the next call of deflate().
+
+ If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does
+ not have enough output space to complete, then the parameter change will not
+ take effect. In this case, deflateParams() can be called again with the
+ same parameters and more output space to try again.
+
+ In order to assure a change in the parameters on the first try, the
+ deflate stream should be flushed using deflate() with Z_BLOCK or other flush
+ request until strm.avail_out is not zero, before calling deflateParams().
+ Then no more input data should be provided before the deflateParams() call.
+ If this is done, the old level and strategy will be applied to the data
+ compressed before deflateParams(), and the new level and strategy will be
+ applied to the the data compressed after deflateParams().
+
+ deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream
+ state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if
+ there was not enough output space to complete the compression of the
+ available input data before a change in the strategy or approach. Note that
+ in the case of a Z_BUF_ERROR, the parameters are not changed. A return
+ value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be
+ retried with more output space.
*/
ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
@@ -793,7 +855,7 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
is for use with other formats that use the deflate compressed data format
such as zip. Those formats provide their own check values. If a custom
format is developed using the raw deflate format for compressed data, it is
- recommended that a check value such as an adler32 or a crc32 be applied to
+ recommended that a check value such as an Adler-32 or a CRC-32 be applied to
the uncompressed data as is done in the zlib, gzip, and zip formats. For
most applications, the zlib format should be used as is. Note that comments
above on the use in deflateInit2() applies to the magnitude of windowBits.
@@ -802,7 +864,10 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
32 to windowBits to enable zlib and gzip decoding with automatic header
detection, or add 16 to decode only the gzip format (the zlib format will
return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
- crc32 instead of an adler32.
+ CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see
+ below), inflate() will not automatically decode concatenated gzip streams.
+ inflate() will return Z_STREAM_END at the end of the gzip stream. The state
+ would need to be reset to continue decoding a subsequent gzip stream.
inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
@@ -823,7 +888,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
Initializes the decompression dictionary from the given uncompressed byte
sequence. This function must be called immediately after a call of inflate,
if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
- can be determined from the adler32 value returned by that call of inflate.
+ can be determined from the Adler-32 value returned by that call of inflate.
The compressor and decompressor must use exactly the same dictionary (see
deflateSetDictionary). For raw inflate, this function can be called at any
time to set the dictionary. If the provided dictionary is smaller than the
@@ -834,7 +899,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
- expected one (incorrect adler32 value). inflateSetDictionary does not
+ expected one (incorrect Adler-32 value). inflateSetDictionary does not
perform any decompression: this will be done by subsequent calls of
inflate().
*/
@@ -892,7 +957,7 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
/*
This function is equivalent to inflateEnd followed by inflateInit,
- but does not free and reallocate all the internal decompression state. The
+ but does not free and reallocate the internal decompression state. The
stream will keep attributes that may have been set by inflateInit2.
inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
@@ -904,7 +969,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
/*
This function is the same as inflateReset, but it also permits changing
the wrap and window size requests. The windowBits parameter is interpreted
- the same as it is for inflateInit2.
+ the same as it is for inflateInit2. If the window size is changed, then the
+ memory allocated for the window is freed, and the window will be reallocated
+ by inflate() if needed.
inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
stream state was inconsistent (such as zalloc or state being Z_NULL), or if
@@ -956,7 +1023,7 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
location in the input stream can be determined from avail_in and data_type
as noted in the description for the Z_BLOCK flush parameter for inflate.
- inflateMark returns the value noted above or -1 << 16 if the provided
+ inflateMark returns the value noted above, or -65536 if the provided
source stream state was inconsistent.
*/
@@ -1048,9 +1115,9 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
This routine would normally be used in a utility that reads zip or gzip
files and writes out uncompressed files. The utility would decode the
header and process the trailer on its own, hence this routine expects only
- the raw deflate stream to decompress. This is different from the normal
- behavior of inflate(), which expects either a zlib or gzip header and
- trailer around the deflate stream.
+ the raw deflate stream to decompress. This is different from the default
+ behavior of inflate(), which expects a zlib header and trailer around the
+ deflate stream.
inflateBack() uses two subroutines supplied by the caller that are then
called by inflateBack() for input and output. inflateBack() calls those
@@ -1059,12 +1126,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
parameters and return types are defined above in the in_func and out_func
typedefs. inflateBack() will call in(in_desc, &buf) which should return the
number of bytes of provided input, and a pointer to that input in buf. If
- there is no input available, in() must return zero--buf is ignored in that
- case--and inflateBack() will return a buffer error. inflateBack() will call
- out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
- should return zero on success, or non-zero on failure. If out() returns
- non-zero, inflateBack() will return with an error. Neither in() nor out()
- are permitted to change the contents of the window provided to
+ there is no input available, in() must return zero -- buf is ignored in that
+ case -- and inflateBack() will return a buffer error. inflateBack() will
+ call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1].
+ out() should return zero on success, or non-zero on failure. If out()
+ returns non-zero, inflateBack() will return with an error. Neither in() nor
+ out() are permitted to change the contents of the window provided to
inflateBackInit(), which is also the buffer that out() uses to write from.
The length written by out() will be at most the window size. Any non-zero
amount of input may be provided by in().
@@ -1092,7 +1159,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
using strm->next_in which will be Z_NULL only if in() returned an error. If
strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
non-zero. (in() will always be called before out(), so strm->next_in is
- assured to be defined if out() returns non-zero.) Note that inflateBack()
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
cannot return Z_OK.
*/
@@ -1114,7 +1181,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
7.6: size of z_off_t
Compiler, assembler, and debug options:
- 8: DEBUG
+ 8: ZLIB_DEBUG
9: ASMV or ASMINF -- use ASM code
10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
11: 0 (reserved)
@@ -1164,7 +1231,8 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
the byte length of the source buffer. Upon entry, destLen is the total size
of the destination buffer, which must be at least the value returned by
compressBound(sourceLen). Upon exit, destLen is the actual size of the
- compressed buffer.
+ compressed data. compress() is equivalent to compress2() with a level
+ parameter of Z_DEFAULT_COMPRESSION.
compress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
@@ -1180,7 +1248,7 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
length of the source buffer. Upon entry, destLen is the total size of the
destination buffer, which must be at least the value returned by
compressBound(sourceLen). Upon exit, destLen is the actual size of the
- compressed buffer.
+ compressed data.
compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
@@ -1203,7 +1271,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
uncompressed data. (The size of the uncompressed data must have been saved
previously by the compressor and transmitted to the decompressor by some
mechanism outside the scope of this compression library.) Upon exit, destLen
- is the actual size of the uncompressed buffer.
+ is the actual size of the uncompressed data.
uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
enough memory, Z_BUF_ERROR if there was not enough room in the output
@@ -1212,6 +1280,14 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
buffer with the uncompressed data up to that point.
*/
+ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong *sourceLen));
+/*
+ Same as uncompress, except that sourceLen is a pointer, where the
+ length of the source is *sourceLen. On return, *sourceLen is the number of
+ source bytes consumed.
+*/
+
/* gzip file access functions */
/*
@@ -1290,10 +1366,9 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
default buffer size is 8192 bytes. This function must be called after
gzopen() or gzdopen(), and before any other calls that read or write the
file. The buffer memory allocation is always deferred to the first read or
- write. Two buffers are allocated, either both of the specified size when
- writing, or one of the specified size and the other twice that size when
- reading. A larger buffer size of, for example, 64K or 128K bytes will
- noticeably increase the speed of decompression (reading).
+ write. Three times that size in buffer space is allocated. A larger buffer
+ size of, for example, 64K or 128K bytes will noticeably increase the speed
+ of decompression (reading).
The new buffer size also affects the maximum length for gzprintf().
@@ -1304,10 +1379,12 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
/*
Dynamically update the compression level or strategy. See the description
- of deflateInit2 for the meaning of these parameters.
+ of deflateInit2 for the meaning of these parameters. Previously provided
+ data is flushed before the parameter change.
- gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
- opened for writing.
+ gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not
+ opened for writing, Z_ERRNO if there is an error writing the flushed data,
+ or Z_MEM_ERROR if there is a memory allocation error.
*/
ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
@@ -1335,7 +1412,35 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
case.
gzread returns the number of uncompressed bytes actually read, less than
- len for end of file, or -1 for error.
+ len for end of file, or -1 for error. If len is too large to fit in an int,
+ then nothing is read, -1 is returned, and the error state is set to
+ Z_STREAM_ERROR.
+*/
+
+ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
+ gzFile file));
+/*
+ Read up to nitems items of size size from file to buf, otherwise operating
+ as gzread() does. This duplicates the interface of stdio's fread(), with
+ size_t request and return types. If the library defines size_t, then
+ z_size_t is identical to size_t. If not, then z_size_t is an unsigned
+ integer type that can contain a pointer.
+
+ gzfread() returns the number of full items read of size size, or zero if
+ the end of the file was reached and a full item could not be read, or if
+ there was an error. gzerror() must be consulted if zero is returned in
+ order to determine if there was an error. If the multiplication of size and
+ nitems overflows, i.e. the product does not fit in a z_size_t, then nothing
+ is read, zero is returned, and the error state is set to Z_STREAM_ERROR.
+
+ In the event that the end of file is reached and only a partial item is
+ available at the end, i.e. the remaining uncompressed data length is not a
+ multiple of size, then the final partial item is nevetheless read into buf
+ and the end-of-file flag is set. The length of the partial item read is not
+ provided, but could be inferred from the result of gztell(). This behavior
+ is the same as the behavior of fread() implementations in common libraries,
+ but it prevents the direct use of gzfread() to read a concurrently written
+ file, reseting and retrying on end-of-file, when size is not 1.
*/
ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
@@ -1346,19 +1451,33 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
error.
*/
+ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size,
+ z_size_t nitems, gzFile file));
+/*
+ gzfwrite() writes nitems items of size size from buf to file, duplicating
+ the interface of stdio's fwrite(), with size_t request and return types. If
+ the library defines size_t, then z_size_t is identical to size_t. If not,
+ then z_size_t is an unsigned integer type that can contain a pointer.
+
+ gzfwrite() returns the number of full items written of size size, or zero
+ if there was an error. If the multiplication of size and nitems overflows,
+ i.e. the product does not fit in a z_size_t, then nothing is written, zero
+ is returned, and the error state is set to Z_STREAM_ERROR.
+*/
+
ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...));
/*
Converts, formats, and writes the arguments to the compressed file under
control of the format string, as in fprintf. gzprintf returns the number of
- uncompressed bytes actually written, or 0 in case of error. The number of
- uncompressed bytes written is limited to 8191, or one less than the buffer
- size given to gzbuffer(). The caller should assure that this limit is not
- exceeded. If it is exceeded, then gzprintf() will return an error (0) with
- nothing written. In this case, there may also be a buffer overflow with
- unpredictable consequences, which is possible only if zlib was compiled with
- the insecure functions sprintf() or vsprintf() because the secure snprintf()
- or vsnprintf() functions were not available. This can be determined using
- zlibCompileFlags().
+ uncompressed bytes actually written, or a negative zlib error code in case
+ of error. The number of uncompressed bytes written is limited to 8191, or
+ one less than the buffer size given to gzbuffer(). The caller should assure
+ that this limit is not exceeded. If it is exceeded, then gzprintf() will
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+ This can be determined using zlibCompileFlags().
*/
ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
@@ -1418,7 +1537,7 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
If the flush parameter is Z_FINISH, the remaining data is written and the
gzip stream is completed in the output. If gzwrite() is called again, a new
gzip stream will be started in the output. gzread() is able to read such
- concatented gzip streams.
+ concatenated gzip streams.
gzflush should be called only when strictly necessary because it will
degrade compression if called too often.
@@ -1572,7 +1691,7 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
return the updated checksum. If buf is Z_NULL, this function returns the
required initial value for the checksum.
- An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed
much faster.
Usage example:
@@ -1585,6 +1704,12 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
if (adler != original_adler) error();
*/
+ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf,
+ z_size_t len));
+/*
+ Same as adler32(), but with a size_t length.
+*/
+
/*
ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
z_off_t len2));
@@ -1614,6 +1739,12 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
if (crc != original_crc) error();
*/
+ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf,
+ z_size_t len));
+/*
+ Same as crc32(), but with a size_t length.
+*/
+
/*
ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
@@ -1644,19 +1775,35 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
unsigned char FAR *window,
const char *version,
int stream_size));
-#define deflateInit(strm, level) \
- deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
-#define inflateInit(strm) \
- inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
-#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
- deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
- (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
-#define inflateInit2(strm, windowBits) \
- inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
- (int)sizeof(z_stream))
-#define inflateBackInit(strm, windowBits, window) \
- inflateBackInit_((strm), (windowBits), (window), \
- ZLIB_VERSION, (int)sizeof(z_stream))
+#ifdef Z_PREFIX_SET
+# define z_deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+# define z_inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+# define z_inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+ (int)sizeof(z_stream))
+# define z_inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, (int)sizeof(z_stream))
+#else
+# define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream))
+# define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream))
+# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream))
+# define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \
+ (int)sizeof(z_stream))
+# define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, (int)sizeof(z_stream))
+#endif
#ifndef Z_SOLO
@@ -1676,10 +1823,10 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
#ifdef Z_PREFIX_SET
# undef z_gzgetc
# define z_gzgetc(g) \
- ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
#else
# define gzgetc(g) \
- ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))
+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g))
#endif
/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
@@ -1737,19 +1884,16 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */
#endif /* !Z_SOLO */
-/* hack for buggy compilers */
-#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
- struct internal_state {int dummy;};
-#endif
-
/* undocumented functions */
ZEXTERN const char * ZEXPORT zError OF((int));
ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void));
ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int));
+ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp));
ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));
ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));
-#if defined(_WIN32) && !defined(Z_SOLO)
+#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO)
ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,
const char *mode));
#endif
diff --git a/erts/emulator/zlib/zlib.mk b/erts/emulator/zlib/zlib.mk
index 3f0d64d250..b51b4ec8d6 100644
--- a/erts/emulator/zlib/zlib.mk
+++ b/erts/emulator/zlib/zlib.mk
@@ -52,7 +52,7 @@ ifeq ($(TYPE),gcov)
ZLIB_CFLAGS = -O0 -fprofile-arcs -ftest-coverage $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS)
else # gcov
ifeq ($(TYPE),debug)
-ZLIB_CFLAGS = $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS)
+ZLIB_CFLAGS = -DZLIB_DEBUG=1 $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS)
else # debug
ZLIB_CFLAGS = $(subst -O2, -O3, $(CONFIGURE_CFLAGS) $(DEFS) $(THR_DEFS))
#ZLIB_CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
@@ -62,6 +62,9 @@ ZLIB_CFLAGS = $(subst -O2, -O3, $(CONFIGURE_CFLAGS) $(DEFS) $(THR_DEFS))
endif # debug
endif # gcov
+# Don't fail if _LFS64_LARGEFILE is undefined
+ZLIB_CFLAGS := $(filter-out -Werror=undef,$(ZLIB_CFLAGS))
+
ifeq ($(TARGET), win32)
$(ZLIB_LIBRARY): $(ZLIB_OBJS)
$(V_AR) -out:$@ $(ZLIB_OBJS)
diff --git a/erts/emulator/zlib/zutil.c b/erts/emulator/zlib/zutil.c
index 27a8af4a2b..a76c6b0c7e 100644
--- a/erts/emulator/zlib/zutil.c
+++ b/erts/emulator/zlib/zutil.c
@@ -1,33 +1,27 @@
/* zutil.c -- target dependent utility functions for the compression library
- * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly.
+ * Copyright (C) 1995-2017 Jean-loup Gailly
* For conditions of distribution and use, see copyright notice in zlib.h
*/
/* @(#) $Id$ */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
#include "zutil.h"
#ifndef Z_SOLO
# include "gzguts.h"
#endif
-#ifndef NO_DUMMY_DECL
-struct internal_state {int dummy;}; /* for buggy compilers */
-#endif
-
z_const char * const z_errmsg[10] = {
-"need dictionary", /* Z_NEED_DICT 2 */
-"stream end", /* Z_STREAM_END 1 */
-"", /* Z_OK 0 */
-"file error", /* Z_ERRNO (-1) */
-"stream error", /* Z_STREAM_ERROR (-2) */
-"data error", /* Z_DATA_ERROR (-3) */
-"insufficient memory", /* Z_MEM_ERROR (-4) */
-"buffer error", /* Z_BUF_ERROR (-5) */
-"incompatible version",/* Z_VERSION_ERROR (-6) */
-""};
+ (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */
+ (z_const char *)"stream end", /* Z_STREAM_END 1 */
+ (z_const char *)"", /* Z_OK 0 */
+ (z_const char *)"file error", /* Z_ERRNO (-1) */
+ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */
+ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */
+ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */
+ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */
+ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */
+ (z_const char *)""
+};
const char * ZEXPORT zlibVersion()
@@ -64,7 +58,7 @@ uLong ZEXPORT zlibCompileFlags()
case 8: flags += 2 << 6; break;
default: flags += 3 << 6;
}
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
flags += 1 << 8;
#endif
#if defined(ASMV) || defined(ASMINF)
@@ -118,8 +112,8 @@ uLong ZEXPORT zlibCompileFlags()
return flags;
}
-#ifdef DEBUG
-
+#ifdef ZLIB_DEBUG
+#include <stdlib.h>
# ifndef verbose
# define verbose 0
# endif
@@ -222,9 +216,11 @@ local ptr_table table[MAX_PTR];
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
{
- voidpf buf = opaque; /* just to make some compilers happy */
+ voidpf buf;
ulg bsize = (ulg)items*size;
+ (void)opaque;
+
/* If we allocate less than 65520 bytes, we assume that farmalloc
* will return a usable pointer which doesn't have to be normalized.
*/
@@ -247,6 +243,9 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
int n;
+
+ (void)opaque;
+
if (*(ush*)&ptr != 0) { /* object < 64K */
farfree(ptr);
return;
@@ -262,7 +261,6 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
next_ptr--;
return;
}
- ptr = opaque; /* just to make some compilers happy */
Assert(0, "zcfree: ptr not found");
}
@@ -281,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
{
- if (opaque) opaque = 0; /* to make compiler happy */
+ (void)opaque;
return _halloc((long)items, size);
}
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
{
- if (opaque) opaque = 0; /* to make compiler happy */
+ (void)opaque;
_hfree(ptr);
}
@@ -309,7 +307,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
unsigned items;
unsigned size;
{
- if (opaque) items += size - size; /* make compiler happy */
+ (void)opaque;
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
(voidpf)calloc(items, size);
}
@@ -318,8 +316,8 @@ void ZLIB_INTERNAL zcfree (opaque, ptr)
voidpf opaque;
voidpf ptr;
{
+ (void)opaque;
free(ptr);
- if (opaque) return; /* make compiler happy */
}
#endif /* MY_ZCALLOC */
diff --git a/erts/emulator/zlib/zutil.h b/erts/emulator/zlib/zutil.h
index 24ab06b1cf..b079ea6a80 100644
--- a/erts/emulator/zlib/zutil.h
+++ b/erts/emulator/zlib/zutil.h
@@ -1,5 +1,5 @@
/* zutil.h -- internal interface and configuration of the compression library
- * Copyright (C) 1995-2013 Jean-loup Gailly.
+ * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
@@ -36,7 +36,9 @@
#ifndef local
# define local static
#endif
-/* compile with -Dlocal if your debugger can't find static symbols */
+/* since "static" is used to mean two completely different things in C, we
+ define "local" for the non-static meaning of "static", for readability
+ (compile with -Dlocal if your debugger can't find static symbols) */
typedef unsigned char uch;
typedef uch FAR uchf;
@@ -98,28 +100,38 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif
#ifdef AMIGA
-# define OS_CODE 0x01
+# define OS_CODE 1
#endif
#if defined(VAXC) || defined(VMS)
-# define OS_CODE 0x02
+# define OS_CODE 2
# define F_OPEN(name, mode) \
fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
#endif
+#ifdef __370__
+# if __TARGET_LIB__ < 0x20000000
+# define OS_CODE 4
+# elif __TARGET_LIB__ < 0x40000000
+# define OS_CODE 11
+# else
+# define OS_CODE 8
+# endif
+#endif
+
#if defined(ATARI) || defined(atarist)
-# define OS_CODE 0x05
+# define OS_CODE 5
#endif
#ifdef OS2
-# define OS_CODE 0x06
+# define OS_CODE 6
# if defined(M_I86) && !defined(Z_SOLO)
# include <malloc.h>
# endif
#endif
#if defined(MACOS) || defined(TARGET_OS_MAC)
-# define OS_CODE 0x07
+# define OS_CODE 7
# ifndef Z_SOLO
# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
# include <unix.h> /* for fdopen */
@@ -131,18 +143,24 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# endif
#endif
-#ifdef TOPS20
-# define OS_CODE 0x0a
+#ifdef __acorn
+# define OS_CODE 13
#endif
-#ifdef WIN32
-# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
-# define OS_CODE 0x0b
-# endif
+#if defined(WIN32) && !defined(__CYGWIN__)
+# define OS_CODE 10
+#endif
+
+#ifdef _BEOS_
+# define OS_CODE 16
+#endif
+
+#ifdef __TOS_OS400__
+# define OS_CODE 18
#endif
-#ifdef __50SERIES /* Prime/PRIMOS */
-# define OS_CODE 0x0f
+#ifdef __APPLE__
+# define OS_CODE 19
#endif
#if defined(_BEOS_) || defined(RISCOS)
@@ -177,7 +195,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
/* common defaults */
#ifndef OS_CODE
-# define OS_CODE 0x03 /* assume Unix */
+# define OS_CODE 3 /* assume Unix */
#endif
#ifndef F_OPEN
@@ -216,7 +234,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
#endif
/* Diagnostic functions */
-#ifdef DEBUG
+#ifdef ZLIB_DEBUG
# include <stdio.h>
extern int ZLIB_INTERNAL z_verbose;
extern void ZLIB_INTERNAL z_error OF((char *m));
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index 0cb01fd4ef..ec4a4ead23 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -819,10 +819,8 @@ int main(int argc, char **argv)
case '+':
switch (argv[i][1]) {
- case '#':
case 'a':
case 'A':
- case 'b':
case 'C':
case 'e':
case 'i':
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 896e4c8e45..2e034513b0 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -264,13 +264,14 @@ if [ "x$GDB" = "x" ]; then
valversion=`valgrind --version`
valmajor=`echo $valversion | sed 's,[a-z]*\-\([0-9]*\).*,\1,'`
valminor=`echo $valversion | sed 's,[a-z]*\-[0-9]*.\([0-9]*\).*,\1,'`
+ valint=`echo "$valmajor * 1000 + $valminor" | bc`
if [ "x$VALGRIND_LOG_XML" = "x" ]; then
valgrind_xml=
log_file_prefix="--log-file="
else
export VALGRIND_LOG_XML
valgrind_xml="--xml=yes"
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
log_file_prefix="--xml-file="
else
log_file_prefix="--log-file="
@@ -279,7 +280,7 @@ if [ "x$GDB" = "x" ]; then
if [ "x$VALGRIND_LOG_DIR" = "x" ]; then
valgrind_log=
else
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log.$$"
else
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log"
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 725343d701..bfb3e1bd2c 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -43,10 +43,10 @@
#endif
#ifdef HAVE_WORKING_POSIX_OPENPT
# ifndef _XOPEN_SOURCE
- /* On OS X and BSD, we must leave _XOPEN_SOURCE undefined in order for
- * the prototype of vsyslog() to be included.
+ /* On OS X, BSD and Solaris, we must leave _XOPEN_SOURCE undefined in order
+ * for the prototype of vsyslog() to be included.
*/
-# if !(defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__))
+# if !(defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__sun))
# define _XOPEN_SOURCE 600
# endif
# endif
diff --git a/erts/include/internal/gcc/ethr_membar.h b/erts/include/internal/gcc/ethr_membar.h
index 07960ce040..5cbda5582d 100644
--- a/erts/include/internal/gcc/ethr_membar.h
+++ b/erts/include/internal/gcc/ethr_membar.h
@@ -96,7 +96,7 @@
* issue an aquire memory barrier and an __atomic
* builtin memory acess with the __ATOMIC_RELEASE
* memory model must at least issue a release memory
- * barrier. Otherwise the two can not be paired.
+ * barrier. Otherwise the two cannot be paired.
* 4. All __atomic builtins accessing memory using the
* __ATOMIC_CONSUME builtin can be used for the same
* reason __ATOMIC_ACQUIRE can be used. The ethread
diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam
new file mode 100644
index 0000000000..93f23377b5
--- /dev/null
+++ b/erts/preloaded/ebin/erl_init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 0f5f5036f0..42629bbe8e 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index 6017112dac..a74e87d19c 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index 7a4167b0e9..54557d9d18 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index c899b69a2c..3cbfd94a43 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
index 9490a56758..43604e0480 100644
--- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index 15c59de80a..960a4451d3 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index e650a6b5af..1f7fbef85a 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index 858a9dc63e..b6107f8974 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam
index 4ad1380d0b..70675f47ee 100644
--- a/erts/preloaded/ebin/prim_buffer.beam
+++ b/erts/preloaded/ebin/prim_buffer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 2ae18846bf..5aa5a7f384 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index f375c05c99..6a9528d1e2 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index c30c589d3a..23a8e8f210 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index 4923cadbdc..8483d11aed 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 07e7e97814..f3737a524e 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 4333f6643a..3c8d75b205 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -41,7 +41,7 @@ PRE_LOADED_ERL_MODULES = \
prim_inet \
zlib \
prim_zip \
- otp_ring0 \
+ erl_init \
erts_code_purger \
erlang \
erts_internal \
diff --git a/erts/preloaded/src/otp_ring0.erl b/erts/preloaded/src/erl_init.erl
index 62a60fffe2..d681f05398 100644
--- a/erts/preloaded/src/otp_ring0.erl
+++ b/erts/preloaded/src/erl_init.erl
@@ -17,15 +17,26 @@
%%
%% %CopyrightEnd%
%%
--module(otp_ring0).
+-module(erl_init).
-%% Purpose : Start up of erlang system.
+%% Initial process of an Erlang system.
-export([start/2]).
--spec start(_, term()) -> term().
-start(_Env, Argv) ->
- run(init, boot, Argv).
+%% This gets the module name given by the +i option (default 'init')
+%% and the list of command line arguments
+
+-spec start(Mod, BootArgs) -> no_return() when
+ Mod :: module(),
+ BootArgs :: [binary()].
+start(Mod, BootArgs) ->
+ %% Load the static nifs
+ zlib:on_load(),
+ erl_tracer:on_load(),
+ prim_buffer:on_load(),
+ prim_file:on_load(),
+ %% Proceed to the specified boot module
+ run(Mod, boot, BootArgs).
run(M, F, A) ->
case erlang:function_exported(M, F, 1) of
diff --git a/erts/preloaded/src/erts.app.src b/erts/preloaded/src/erts.app.src
index 1ccc4988c2..dc97b86d8c 100644
--- a/erts/preloaded/src/erts.app.src
+++ b/erts/preloaded/src/erts.app.src
@@ -26,7 +26,7 @@
erl_prim_loader,
erts_internal,
init,
- otp_ring0,
+ erl_init,
erts_code_purger,
prim_buffer,
prim_eval,
@@ -38,7 +38,7 @@
{registered, []},
{applications, []},
{env, []},
- {runtime_dependencies, ["stdlib-3.5", "kernel-6.0", "sasl-3.0.1"]}
+ {runtime_dependencies, ["stdlib-3.5", "kernel-6.1", "sasl-3.0.1"]}
]}.
%% vim: ft=erlang
diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl
index 253fcf7a1f..277e60c180 100644
--- a/erts/preloaded/src/init.erl
+++ b/erts/preloaded/src/init.erl
@@ -200,12 +200,6 @@ boot(BootArgs) ->
register(init, self()),
process_flag(trap_exit, true),
- %% Load the static nifs
- zlib:on_load(),
- erl_tracer:on_load(),
- prim_buffer:on_load(),
- prim_file:on_load(),
-
{Start0,Flags,Args} = parse_boot_args(BootArgs),
%% We don't get to profile parsing of BootArgs
case b2a(get_flag(profile_boot, Flags, false)) of
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 41ff38359c..6d85868183 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -580,15 +580,20 @@ read_link_info(Name, Opts) ->
read_info_1(Name, 0, proplist_get_value(time, Opts, local)).
read_info_1(Name, FollowLinks, TimeType) ->
- try read_info_nif(encode_path(Name), FollowLinks) of
- {error, Reason} -> {error, Reason};
- FileInfo ->
- CTime = from_posix_seconds(FileInfo#file_info.ctime, TimeType),
- MTime = from_posix_seconds(FileInfo#file_info.mtime, TimeType),
- ATime = from_posix_seconds(FileInfo#file_info.atime, TimeType),
- {ok, FileInfo#file_info{ ctime = CTime, mtime = MTime, atime = ATime }}
+ try
+ case read_info_nif(encode_path(Name), FollowLinks) of
+ {error, Reason} ->
+ {error, Reason};
+ FileInfo ->
+ CTime = from_posix_seconds(FileInfo#file_info.ctime, TimeType),
+ MTime = from_posix_seconds(FileInfo#file_info.mtime, TimeType),
+ ATime = from_posix_seconds(FileInfo#file_info.atime, TimeType),
+ {ok, FileInfo#file_info{ ctime = CTime,
+ mtime = MTime,
+ atime = ATime }}
+ end
catch
- error:badarg -> {error, badarg}
+ error:_ -> {error, badarg}
end.
write_file_info(Filename, Info) ->
@@ -781,7 +786,7 @@ altname_nif(_Path) ->
%% We know for certain that lists:reverse/2 is a BIF, so it's safe to use it
%% even though this module is preloaded.
-reverse_list(List) -> lists:reverse(List).
+reverse_list(List) -> lists:reverse(List, []).
proplist_get_value(_Key, [], Default) ->
Default;
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 2a3605260d..cc2711b540 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-export([open/3, open/4, fdopen/4, fdopen/5, close/1]).
-export([bind/3, listen/1, listen/2, peeloff/2]).
-export([connect/3, connect/4, async_connect/4]).
--export([accept/1, accept/2, async_accept/2]).
+-export([accept/1, accept/2, accept/3, async_accept/2]).
-export([shutdown/2]).
-export([send/2, send/3, sendto/4, sendmsg/3, sendfile/4]).
-export([recv/2, recv/3, async_recv/3]).
@@ -49,9 +49,15 @@
-include("inet_sctp.hrl").
-include("inet_int.hrl").
-%-define(DEBUG, 1).
+%%%-define(DEBUG, 1).
-ifdef(DEBUG).
--define(DBG_FORMAT(Format, Args), (io:format((Format), (Args)))).
+-define(
+ DBG_FORMAT(Format, Args),
+ begin
+ %% io:format((Format), (Args)),
+ erlang:display(lists:flatten(io_lib:format((Format), (Args)))),
+ ok
+ end).
-else.
-define(DBG_FORMAT(Format, Args), ok).
-endif.
@@ -150,39 +156,96 @@ shutdown_1(S, How) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
close(S) when is_port(S) ->
+ ?DBG_FORMAT("prim_inet:close(~p)~n", [S]),
case getopt(S, linger) of
{ok,{true,0}} ->
close_port(S);
- _ ->
- case subscribe(S, [subs_empty_out_q]) of
- {ok, [{subs_empty_out_q,N}]} when N > 0 ->
- close_pend_loop(S, N); %% wait for pending output to be sent
- _ ->
- close_port(S)
- end
+ {ok,{true,T}} ->
+ %% Wait for T seconds for pending output to be sent
+ %%
+ %% Note that this handling of Linger may look ok,
+ %% but sweeps some problems under the rug since
+ %% there are OS buffers that may have remaining data
+ %% after the inet driver has emptied its buffers.
+ %% But Linger for nonblocking sockets is broken
+ %% anyway on all OS:es, according to hearsay,
+ %% and is a contradiction in itself.
+ %% We have hereby done our best...
+ %%
+ Tref = erlang:start_timer(T * 1000, self(), close_port),
+ close_pend_loop(S, Tref, undefined);
+ _ -> % Regard this as {ok,{false,_}}
+ case subscribe(S, [subs_empty_out_q]) of
+ {ok, [{subs_empty_out_q,N}]} when N > 0 ->
+ %% Wait for pending output to be sent
+ DefaultT = 180000, % Arbitrary system timeout 3 min
+ Tref = erlang:start_timer(DefaultT, self(), close_port),
+ close_pend_loop(S, Tref, N);
+ _ ->
+ %% Subscribe failed or empty out q - give up or done
+ close_port(S)
+ end
end.
-close_pend_loop(S, N) ->
+close_pend_loop(S, Tref, N) ->
+ ?DBG_FORMAT("prim_inet:close_pend_loop(~p, _, ~p)~n", [S,N]),
receive
- {empty_out_q,S} ->
- close_port(S)
+ {timeout,Tref,_} -> % Linger timeout
+ ?DBG_FORMAT("prim_inet:close_pend_loop(~p, _, _) timeout~n", [S]),
+ close_port(S);
+ {empty_out_q,S} when N =/= undefined ->
+ ?DBG_FORMAT(
+ "prim_inet:close_pend_loop(~p, _, _) empty_out_q~n", [S]),
+ close_port(S, Tref)
after ?INET_CLOSE_TIMEOUT ->
case getstat(S, [send_pend]) of
{ok, [{send_pend,N1}]} ->
+ ?DBG_FORMAT(
+ "prim_inet:close_pend_loop(~p, _, _) send_pend ~p~n",
+ [S,N1]),
if
- N1 =:= N ->
- close_port(S);
- true ->
- close_pend_loop(S, N1)
+ N1 =:= 0 ->
+ %% Empty outq - done
+ close_port(S, Tref);
+ N =:= undefined ->
+ %% Within linger time - wait some more
+ close_pend_loop(S, Tref, N);
+ N1 =:= N ->
+ %% Inactivity - give up
+ close_port(S, Tref);
+ true ->
+ %% Still moving - wait some more
+ close_pend_loop(S, Tref, N)
end;
- _ ->
- close_port(S)
- end
+ _Stat ->
+ %% Failed getstat - give up
+ ?DBG_FORMAT(
+ "prim_inet:close_pend_loop(~p, _, _) getstat ~p~n",
+ [S,_Stat]),
+ close_port(S, Tref)
+ end
end.
+
+close_port(S, Tref) ->
+ ?DBG_FORMAT("prim_inet:close_port(~p, _)~n", [S]),
+ case erlang:cancel_timer(Tref) of
+ false ->
+ receive
+ {timeout,Tref,_} ->
+ ok
+ end;
+ _N ->
+ ok
+ end,
+ close_port(S).
+%%
close_port(S) ->
- catch erlang:port_close(S),
- receive {'EXIT',S,_} -> ok after 0 -> ok end.
+ ?DBG_FORMAT("prim_inet:close_port(~p)~n", [S]),
+ _Closed = (catch erlang:port_close(S)),
+ receive {'EXIT',S,_} -> ok after 0 -> ok end,
+ ?DBG_FORMAT("prim_inet:close_port(~p) ~p~n", [S,_Closed]),
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -307,7 +370,7 @@ async_connect0(S, Addr, Time) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
-%% ACCEPT(insock() [,Timeout] ) -> {ok,insock()} | {error, Reason}
+%% ACCEPT(insock() [,Timeout][,FamilyOpts] ) -> {ok,insock()} | {error, Reason}
%%
%% accept incoming connection on listen socket
%% if timeout is given:
@@ -315,6 +378,8 @@ async_connect0(S, Addr, Time) ->
%% 0 -> immediate accept (poll)
%% > 0 -> wait for timeout ms for accept if no accept then
%% return {error, timeout}
+%% FamilyOpts are address family specific options to copy from
+%% listen socket to accepted socket
%%
%% ASYNC_ACCEPT(insock(), Timeout)
%%
@@ -325,17 +390,22 @@ async_connect0(S, Addr, Time) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% For TCP sockets only.
%%
-accept(L) -> accept0(L, -1).
+accept(L) -> accept0(L, -1, []).
-accept(L, infinity) -> accept0(L, -1);
-accept(L, Time) -> accept0(L, Time).
+accept(L, infinity) -> accept0(L, -1, []);
+accept(L, FamilyOpts) when is_list(FamilyOpts) -> accept0(L, -1, FamilyOpts);
+accept(L, Time) -> accept0(L, Time, []).
-accept0(L, Time) when is_port(L), is_integer(Time) ->
+accept(L, infinity, FamilyOpts) -> accept0(L, -1, FamilyOpts);
+accept(L, Time, FamilyOpts) -> accept0(L, Time, FamilyOpts).
+
+accept0(L, Time, FamilyOpts)
+ when is_port(L), is_integer(Time), is_list(FamilyOpts) ->
case async_accept(L, Time) of
{ok, Ref} ->
receive
{inet_async, L, Ref, {ok,S}} ->
- accept_opts(L, S);
+ accept_opts(L, S, FamilyOpts);
{inet_async, L, Ref, Error} ->
Error
end;
@@ -343,25 +413,22 @@ accept0(L, Time) when is_port(L), is_integer(Time) ->
end.
%% setup options from listen socket on the connected socket
-accept_opts(L, S) ->
- case getopts(L, [active, nodelay, keepalive, delay_send, priority, tos]) of
+accept_opts(L, S, FamilyOpts) ->
+ case
+ getopts(
+ L,
+ [active, nodelay, keepalive, delay_send, priority]
+ ++ FamilyOpts)
+ of
{ok, Opts} ->
- case setopts(S, Opts) of
- ok ->
- case getopts(L, [tclass]) of
- {ok, []} ->
- {ok, S};
- {ok, TClassOpts} ->
- case setopts(S, TClassOpts) of
- ok ->
- {ok, S};
- Error -> close(S), Error
- end
- end;
- Error -> close(S), Error
- end;
- Error ->
- close(S), Error
+ case setopts(S, Opts) of
+ ok ->
+ {ok, S};
+ Error1 ->
+ close(S), Error1
+ end;
+ Error2 ->
+ close(S), Error2
end.
async_accept(L, Time) ->
@@ -420,23 +487,49 @@ peeloff(S, AssocId) ->
%% be called directly -- use "sendmsg" instead:
%%
send(S, Data, OptList) when is_port(S), is_list(OptList) ->
- ?DBG_FORMAT("prim_inet:send(~p, ~p)~n", [S,Data]),
+ ?DBG_FORMAT("prim_inet:send(~p, _, ~p)~n", [S,OptList]),
try erlang:port_command(S, Data, OptList) of
false -> % Port busy and nosuspend option passed
?DBG_FORMAT("prim_inet:send() -> {error,busy}~n", []),
{error,busy};
true ->
- receive
- {inet_reply,S,Status} ->
- ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Status]),
- Status
- end
+ send_recv_reply(S, undefined)
catch
error:_Error ->
?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []),
{error,einval}
end.
+send_recv_reply(S, Mref) ->
+ ReplyTimeout =
+ case Mref of
+ undefined ->
+ ?INET_CLOSE_TIMEOUT;
+ _ ->
+ infinity
+ end,
+ receive
+ {inet_reply,S,Status} ->
+ ?DBG_FORMAT(
+ "prim_inet:send_recv_reply(~p, _): inet_reply ~p~n",
+ [S,Status]),
+ case Mref of
+ undefined -> ok;
+ _ ->
+ demonitor(Mref, [flush]),
+ ok
+ end,
+ Status;
+ {'DOWN',Mref,_,_,_Reason} when Mref =/= undefined ->
+ ?DBG_FORMAT(
+ "prim_inet:send_recv_reply(~p, _) 'DOWN' ~p~n",
+ [S,_Reason]),
+ {error,closed}
+ after ReplyTimeout ->
+ send_recv_reply(S, monitor(port, S))
+ end.
+
+
send(S, Data) ->
send(S, Data, []).
@@ -516,13 +609,35 @@ sendfile(S, FileHandle, Offset, Length)
sendfile(S, FileHandle, Offset, Length) ->
case erlang:port_info(S, connected) of
{connected, Pid} when Pid =:= self() ->
- sendfile_1(S, FileHandle, Offset, Length);
+ Uncork = sendfile_maybe_cork(S),
+ Result = sendfile_1(S, FileHandle, Offset, Length),
+ sendfile_maybe_uncork(S, Uncork),
+ Result;
{connected, Pid} when Pid =/= self() ->
{error, not_owner};
_Other ->
{error, einval}
end.
+sendfile_maybe_cork(S) ->
+ case getprotocol(S) of
+ tcp ->
+ case getopts(S, [nopush]) of
+ {ok, [{nopush,false}]} ->
+ _ = setopts(S, [{nopush,true}]),
+ true;
+ _ ->
+ false
+ end;
+ _ -> false
+ end.
+
+sendfile_maybe_uncork(S, true) ->
+ _ = setopts(S, [{nopush,false}]),
+ ok;
+sendfile_maybe_uncork(_, false) ->
+ ok.
+
sendfile_1(S, FileHandle, Offset, 0) ->
sendfile_1(S, FileHandle, Offset, (1 bsl 63) - 1);
sendfile_1(_S, _FileHandle, Offset, Length) when
@@ -616,7 +731,16 @@ recvfrom0(S, Length, Time)
Ref = ?u16(R1,R0),
receive
% Success, UDP:
+ {inet_async, S, Ref, {ok, {[F | AddrData], AncData}}} ->
+ %% With ancillary data
+ case get_addr(F, AddrData) of
+ {{Family, _} = Addr, Data} when is_atom(Family) ->
+ {ok, {Addr, 0, AncData, Data}};
+ {{IP, Port}, Data} ->
+ {ok, {IP, Port, AncData, Data}}
+ end;
{inet_async, S, Ref, {ok, [F | AddrData]}} ->
+ %% Without ancillary data
case get_addr(F, AddrData) of
{{Family, _} = Addr, Data} when is_atom(Family) ->
{ok, {Addr, 0, Data}};
@@ -857,9 +981,9 @@ chgopts(S, Opts) when is_port(S), is_list(Opts) ->
getifaddrs(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of
- {ok, Data} ->
- {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())};
- {error,enotsup} ->
+ {ok, Data} ->
+ {ok, comp_ifaddrs(build_ifaddrs(Data))};
+ {error,enotsup} ->
case getiflist(S) of
{ok, IFs} ->
{ok, getifaddrs_ifget(S, IFs)};
@@ -868,30 +992,75 @@ getifaddrs(S) when is_port(S) ->
Err2 -> Err2
end.
-%% Restructure interface properties per interface and remove duplicates
-
-comp_ifaddrs([{If,Opts}|IfOpts], T) ->
- case ktree_is_defined(If, T) of
- true ->
- OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts),
- comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T));
- false ->
- OptSet = comp_ifaddrs_add(ktree_empty(), Opts),
- comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T))
- end;
-comp_ifaddrs([], T) ->
- [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)].
-
-comp_ifaddrs_add(OptSet, [Opt|Opts]) ->
- case ktree_is_defined(Opt, OptSet) of
- true
- when element(1, Opt) =:= flags;
- element(1, Opt) =:= hwaddr ->
- comp_ifaddrs_add(OptSet, Opts);
- _ ->
- comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts)
+%% Restructure interface properties per interface
+
+comp_ifaddrs(IfOpts) ->
+ comp_ifaddrs(IfOpts, ktree_empty()).
+%%
+comp_ifaddrs([{If,[{flags,Flags}|Opts]}|IfOpts], IfT) ->
+ case ktree_is_defined(If, IfT) of
+ true ->
+ comp_ifaddrs(
+ IfOpts,
+ ktree_update(
+ If,
+ comp_ifaddrs_flags(Flags, Opts, ktree_get(If, IfT)),
+ IfT));
+ false ->
+ comp_ifaddrs(
+ IfOpts,
+ ktree_insert(
+ If,
+ comp_ifaddrs_flags(Flags, Opts, ktree_empty()),
+ IfT))
end;
-comp_ifaddrs_add(OptSet, []) -> OptSet.
+comp_ifaddrs([], IfT) ->
+ comp_ifaddrs_2(ktree_keys(IfT), IfT).
+
+comp_ifaddrs_flags(Flags, Opts, FlagsT) ->
+ case ktree_is_defined(Flags, FlagsT) of
+ true ->
+ ktree_update(
+ Flags,
+ rev(Opts, ktree_get(Flags, FlagsT)),
+ FlagsT);
+ false ->
+ ktree_insert(Flags, rev(Opts), FlagsT)
+ end.
+
+comp_ifaddrs_2([If|Ifs], IfT) ->
+ FlagsT = ktree_get(If, IfT),
+ [{If,comp_ifaddrs_3(ktree_keys(FlagsT), FlagsT)}
+ | comp_ifaddrs_2(Ifs, IfT)];
+comp_ifaddrs_2([], _IfT) ->
+ [].
+%%
+comp_ifaddrs_3([Flags|FlagsL], FlagsT) ->
+ [{flags,Flags}|hwaddr_last(rev(ktree_get(Flags, FlagsT)))]
+ ++ hwaddr_last(comp_ifaddrs_3(FlagsL, FlagsT));
+comp_ifaddrs_3([], _FlagsT) ->
+ [].
+
+%% Place hwaddr last to look more like legacy emulation
+hwaddr_last(Opts) ->
+ hwaddr_last(Opts, Opts, []).
+%%
+hwaddr_last([{hwaddr,_} = Opt|Opts], L, R) ->
+ hwaddr_last(Opts, L, [Opt|R]);
+hwaddr_last([_|Opts], L, R) ->
+ hwaddr_last(Opts, L, R);
+hwaddr_last([], L, []) ->
+ L;
+hwaddr_last([], L, R) ->
+ rev(hwaddr_last(L, []), rev(R)).
+%%
+hwaddr_last([{hwaddr,_}|Opts], R) ->
+ hwaddr_last(Opts, R);
+hwaddr_last([Opt|Opts], R) ->
+ hwaddr_last(Opts, [Opt|R]);
+hwaddr_last([], R) ->
+ R.
+
%% Legacy emulation of getifaddrs
@@ -899,21 +1068,19 @@ getifaddrs_ifget(_, []) -> [];
getifaddrs_ifget(S, [IF|IFs]) ->
case ifget(S, IF, [flags]) of
{ok,[{flags,Flags}]=FlagsVals} ->
- BroadOpts =
- case member(broadcast, Flags) of
- true ->
- [broadaddr,hwaddr];
- false ->
- [hwaddr]
- end,
- P2POpts =
- case member(pointtopoint, Flags) of
- true ->
- [dstaddr|BroadOpts];
- false ->
- BroadOpts
- end,
- getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]);
+ GetOpts =
+ case member(pointtopoint, Flags) of
+ true ->
+ [dstaddr,hwaddr];
+ false ->
+ case member(broadcast, Flags) of
+ true ->
+ [broadaddr,hwaddr];
+ false ->
+ [hwaddr]
+ end
+ end,
+ getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|GetOpts]);
_ ->
getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr])
end.
@@ -1256,7 +1423,13 @@ enc_opt(recbuf) -> ?INET_OPT_RCVBUF;
enc_opt(priority) -> ?INET_OPT_PRIORITY;
enc_opt(tos) -> ?INET_OPT_TOS;
enc_opt(tclass) -> ?INET_OPT_TCLASS;
+enc_opt(recvtos) -> ?INET_OPT_RECVTOS;
+enc_opt(recvtclass) -> ?INET_OPT_RECVTCLASS;
+enc_opt(pktoptions) -> ?INET_OPT_PKTOPTIONS;
+enc_opt(ttl) -> ?INET_OPT_TTL;
+enc_opt(recvttl) -> ?INET_OPT_RECVTTL;
enc_opt(nodelay) -> ?TCP_OPT_NODELAY;
+enc_opt(nopush) -> ?TCP_OPT_NOPUSH;
enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF;
enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL;
enc_opt(multicast_loop) -> ?UDP_OPT_MULTICAST_LOOP;
@@ -1318,6 +1491,12 @@ dec_opt(?INET_OPT_PRIORITY) -> priority;
dec_opt(?INET_OPT_TOS) -> tos;
dec_opt(?INET_OPT_TCLASS) -> tclass;
dec_opt(?TCP_OPT_NODELAY) -> nodelay;
+dec_opt(?TCP_OPT_NOPUSH) -> nopush;
+dec_opt(?INET_OPT_RECVTOS) -> recvtos;
+dec_opt(?INET_OPT_RECVTCLASS) -> recvtclass;
+dec_opt(?INET_OPT_PKTOPTIONS) -> pktoptions;
+dec_opt(?INET_OPT_TTL) -> ttl;
+dec_opt(?INET_OPT_RECVTTL) -> recvttl;
dec_opt(?UDP_OPT_MULTICAST_IF) -> multicast_if;
dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl;
dec_opt(?UDP_OPT_MULTICAST_LOOP) -> multicast_loop;
@@ -1393,7 +1572,13 @@ type_opt_1(recbuf) -> int;
type_opt_1(priority) -> int;
type_opt_1(tos) -> int;
type_opt_1(tclass) -> int;
+type_opt_1(recvtos) -> bool;
+type_opt_1(recvtclass) -> bool;
+type_opt_1(pktoptions) -> opts;
+type_opt_1(ttl) -> int;
+type_opt_1(recvttl) -> bool;
type_opt_1(nodelay) -> bool;
+type_opt_1(nopush) -> bool;
type_opt_1(ipv6_v6only) -> bool;
%% multicast
type_opt_1(multicast_ttl) -> int;
@@ -1557,7 +1742,7 @@ type_opt_1(O) when is_atom(O) -> undefined.
%% Get. No supplied value.
type_value(get, undefined) -> false; % Undefined type
-%% These two clauses can not happen since they are only used
+%% These two clauses cannot happen since they are only used
%% in record fields - from record fields they must have a
%% value though it might be 'undefined', so record fields
%% calls type_value/3, not type_value/2.
@@ -1723,7 +1908,7 @@ type_value_2(_, _) -> false.
%% Get. No supplied value.
%%
-%% These two clauses can not happen since they are only used
+%% These two clauses cannot happen since they are only used
%% in record fields - from record fields they must have a
%% value though it might be 'undefined', so record fields
%% calls enc_value/3, not enc_value/2.
@@ -1899,6 +2084,11 @@ dec_value(binary,[L0,L1,L2,L3|List]) ->
Len = ?i32(L0,L1,L2,L3),
{X,T}=split(Len,List),
{list_to_binary(X),T};
+dec_value(opts, [L0,L1,L2,L3|List]) ->
+ Len = ?u32(L0,L1,L2,L3),
+ {X,T} = split(Len, List),
+ Opts = dec_opt_val(X),
+ {Opts,T};
dec_value(Types, List) when is_tuple(Types) ->
{L,T} = dec_value_tuple(Types, List, 1, []),
{list_to_tuple(L),T};
@@ -2467,7 +2657,7 @@ get_addrs([F|Addrs]) ->
[Addr|get_addrs(Rest)].
get_addr(?INET_AF_LOCAL, [N|Addr]) ->
- {A,Rest} = lists:split(N, Addr),
+ {A,Rest} = split(N, Addr),
{{local,iolist_to_binary(A)},Rest};
get_addr(?INET_AF_UNSPEC, Rest) ->
{{unspec,<<>>},Rest};
diff --git a/erts/test/upgrade_SUITE.erl b/erts/test/upgrade_SUITE.erl
index c32dbabe8d..f92c25bdb4 100644
--- a/erts/test/upgrade_SUITE.erl
+++ b/erts/test/upgrade_SUITE.erl
@@ -25,7 +25,7 @@
-define(upgr_sname,otp_upgrade).
-%% Applications that are excluded from this test because they can not
+%% Applications that are excluded from this test because they cannot
%% just be started in a new node with out specific configuration.
-define(start_exclude,
[cosEvent,cosEventDomain,cosFileTransfer,cosNotification,
diff --git a/erts/vsn.mk b/erts/vsn.mk
index 0abb06bdc1..01c19aff2f 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.0.3
+VSN = 10.1.1
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/Makefile b/lib/Makefile
index cdb3f3f3dc..6605c6145c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -28,7 +28,7 @@ ERTS_APPLICATIONS = stdlib sasl kernel compiler
ERLANG_APPLICATIONS = tools common_test runtime_tools inets parsetools
# These are only build if -a is given to otp_build or make is used directly
-ALL_ERLANG_APPLICATIONS = xmerl edoc erl_docgen snmp otp_mibs erl_interface \
+ALL_ERLANG_APPLICATIONS = xmerl edoc erl_docgen snmp erl_interface \
asn1 jinterface \
wx debugger reltool \
mnesia crypto os_mon syntax_tools \
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
index d5aaadb89b..797be6d4f8 100644
--- a/lib/asn1/c_src/asn1_erl_nif.c
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -949,6 +949,12 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
unsigned char *tmp_out_buff;
ERL_NIF_TERM term = 0, curr_head = 0;
+ /* Recursion depth limitation, borrow a signed int: maybe_ret */
+ maybe_ret = (int) (ErlNifSInt) ((char *)value - (char *)ib_index);
+ maybe_ret = maybe_ret < 0 ? -maybe_ret : maybe_ret;
+ if (maybe_ret >= sizeof(void *) * 8192) /* 8 k pointer words */
+ return ASN1_ERROR;
+
if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
len = in_buf[*ib_index];
} else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) {
@@ -993,7 +999,7 @@ static int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *
while (*ib_index < end_index) {
if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
- in_buf_len)) <= ASN1_ERROR
+ *ib_index + len)) <= ASN1_ERROR
)
return maybe_ret;
curr_head = enif_make_list_cell(env, term, curr_head);
diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml
index 860cf4d22d..086b5f38c6 100644
--- a/lib/asn1/doc/src/notes.xml
+++ b/lib/asn1/doc/src/notes.xml
@@ -32,6 +32,28 @@
<p>This document describes the changes made to the asn1 application.</p>
+<section><title>Asn1 5.0.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>A bug in ASN.1 BER decoding has been fixed. When
+ decoding a recursively enclosed term the length was not
+ propagated to that term decoding, so if the length of the
+ enclosed term was longer than the enclosing that error
+ was not detected.</p> <p>A hard coded C stack limitation
+ for decoding recursive ASN.1 terms has been introduced.
+ This is currently set to 8 kWords giving a nesting depth
+ of about 1000 levels. Deeper terms can not be decoded,
+ which should not be much of a real world limitation.</p>
+ <p>
+ Own Id: OTP-14440 Aux Id: ERIERL-220 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 5.0.6</title>
<section><title>Improvements and New Features</title>
@@ -47,6 +69,28 @@
</section>
+<section><title>Asn1 5.0.5.1</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>A bug in ASN.1 BER decoding has been fixed. When
+ decoding a recursively enclosed term the length was not
+ propagated to that term decoding, so if the length of the
+ enclosed term was longer than the enclosing that error
+ was not dectected</p> <p>A hard coded C stack limitation
+ for decoding recursive ASN.1 terms has been introduced.
+ This is currently set to 8 kWords giving a nesting depth
+ of about 1000 levels. Deeper terms can not be decoded,
+ which should not be much of a real world limitation.</p>
+ <p>
+ Own Id: OTP-14440 Aux Id: ERIERL-220 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Asn1 5.0.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index 321980e5e4..9ec0d93e93 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -5770,7 +5770,7 @@ format_error({missing_ocft,Component}) ->
format_error(multiple_uniqs) ->
"implementation limitation: only one UNIQUE field is allowed in CLASS";
format_error({namelist_redefinition,Name}) ->
- io_lib:format("the name '~s' can not be redefined", [Name]);
+ io_lib:format("the name '~s' cannot be redefined", [Name]);
format_error({param_bad_type, Ref}) ->
io_lib:format("'~p' is not a parameterized type", [Ref]);
format_error(param_wrong_number_of_arguments) ->
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 7b669c1c2c..5506923341 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -132,7 +132,8 @@ groups() ->
testSeq2738,
% Uses 'Constructed'
{group, [], [constructed,
- ber_decode_error]},
+ ber_decode_error,
+ otp_14440]},
testSeqSetIndefinite,
testChoiceIndefinite,
per_open_type,
@@ -736,6 +737,36 @@ ber_decode_error(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
ber_decode_error:run(Opts).
+otp_14440(_Config) ->
+ Args = " -pa \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
+ {ok,N} = slave:start(hostname(), otp_14440, Args),
+ Result = rpc:call(N, ?MODULE, otp_14440_decode, []),
+ io:format("Decode result = ~p~n", [Result]),
+ case Result of
+ {exit,{error,{asn1,{invalid_value,5}}}} ->
+ ok = slave:stop(N);
+ %% We get this if stack depth limit kicks in:
+ {exit,{error,{asn1,{unknown,_}}}} ->
+ ok = slave:stop(N);
+ _ ->
+ _ = slave:stop(N),
+ ?t:fail(Result)
+ end.
+%%
+otp_14440_decode() ->
+ Data =
+ iolist_to_binary(
+ lists:duplicate(
+ 32, list_to_binary(lists:duplicate(1024, 16#7f)))),
+ try asn1rt_nif:decode_ber_tlv(Data) of
+ Result ->
+ {unexpected_return,Result}
+ catch
+ Class:Reason ->
+ {Class,Reason}
+ end.
+
+
h323test(Config) -> test(Config, fun h323test/3).
h323test(Config, Rule, Opts) ->
Files = ["H235-SECURITY-MESSAGES", "H323-MESSAGES",
@@ -1350,7 +1381,7 @@ xref_export_all(_Config) ->
{ok,_} = xref:q(S, Def),
{ok,Unused} = xref:q(S, "X - Called - range (closure E | Called)"),
xref:stop(S),
- case Unused of
+ case Unused -- [{?MODULE,otp_14440_decode,0}] of
[] ->
ok;
[_|_] ->
@@ -1385,3 +1416,11 @@ all_called_1([F|T]) when is_atom(F) ->
L ++ all_called_1(T);
all_called_1([]) ->
[].
+
+hostname() ->
+ hostname(atom_to_list(node())).
+
+hostname([$@ | Hostname]) ->
+ list_to_atom(Hostname);
+hostname([_C | Cs]) ->
+ hostname(Cs).
diff --git a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
index ff0361f5c5..fb092f3f9c 100644
--- a/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
+++ b/lib/asn1/test/asn1_SUITE_data/IN-CS-1-Datatypes.asn
@@ -1152,7 +1152,7 @@ FilteringCriteria ::= CHOICE {
-- In case calledAddressValue is specified, the numbers to be filtered are from calledAddressValue
-- up to and including calledAddressValue + maximumNumberOfCounters-1.
--- The last two digits of calledAddressvalue can not exceed 100-maximumNumberOfCounters.
+-- The last two digits of calledAddressvalue cannot exceed 100-maximumNumberOfCounters.
FilteringTimeOut ::= CHOICE {
duration [0] Duration,
stopTime [1] DateAndTime
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 30cbca3773..970479cc44 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1 +1 @@
-ASN1_VSN = 5.0.6
+ASN1_VSN = 5.0.7
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index 4d6161d3ae..b5acdc6f95 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2017. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/common_test/doc/src/ct.xml b/lib/common_test/doc/src/ct.xml
index b51dee266b..c0380c4142 100644
--- a/lib/common_test/doc/src/ct.xml
+++ b/lib/common_test/doc/src/ct.xml
@@ -1522,7 +1522,7 @@
<v>Hours = integer()</v>
<v>Mins = integer()</v>
<v>Secs = integer()</v>
- <v>Millisecs = integer() | float()</v>
+ <v>Millisecs = integer()</v>
<v>Func = {M, F, A} | function()</v>
<v>M = atom()</v>
<v>F = atom()</v>
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index 954be0ffba..2f853d133d 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -368,7 +368,7 @@
<seealso marker="common_test#Module:end_per_testcase-2"><c>end_per_testcase</c></seealso>
instead.</p>
- <p>This function can not change the result of the test case by returning skip or fail
+ <p>This function cannot change the result of the test case by returning skip or fail
tuples, but it may insert items in <c>Config</c> that can be read in
<c>end_per_testcase/2</c> or in <c>post_end_per_testcase/5</c>.</p>
diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml
index c8005d8f79..dc18def838 100644
--- a/lib/common_test/doc/src/notes.xml
+++ b/lib/common_test/doc/src/notes.xml
@@ -33,6 +33,26 @@
<file>notes.xml</file>
</header>
+<section><title>Common_Test 1.16.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The Logger handler cth_log_redirect earlier called the
+ report callback (report_cb) before calling the logger
+ formatter. In some cases this would fail, since
+ cth_log_redirect could not handle report callbacks with
+ two arguments. This is now corrected, so only the
+ formatter will call the report callback.</p>
+ <p>
+ Own Id: OTP-15307</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Common_Test 1.16</title>
<section><title>Improvements and New Features</title>
@@ -2089,7 +2109,7 @@
ct_netconfc:close_session sometimes returned
{error,closed} because the ssh connection was closed
(from the server side) before the rpc-reply was received
- by the client. This is normal and can not be helped. It
+ by the client. This is normal and cannot be helped. It
has been corrected so the return will be 'ok' in this
case. Other error situations will still give
{error,Reason}.</p>
@@ -2103,7 +2123,7 @@
{error,{process_down,Pid,normal}} because the ssh
connection was closed (from the server side) before the
rpc-reply was received by the client. This is normal and
- can not be helped. It has been corrected so the return
+ cannot be helped. It has been corrected so the return
will be 'ok' in this situation.</p>
<p>
Own Id: OTP-10570</p>
@@ -2755,8 +2775,8 @@
The info function for <c>init/end_per_suite(Config)</c>
is <c>init/end_per_suite()</c>, and for
<c>init/end_per_group(GroupName,Config)</c> it's
- <c>init/end_per_group(GroupName)</c>. Info functions can
- not be used with <c>init/end_per_testcase(TestCase,
+ <c>init/end_per_group(GroupName)</c>. Info functions
+ cannot be used with <c>init/end_per_testcase(TestCase,
Config)</c>, since these configuration functions execute
on the test case process and will use the same properties
as the test case (i.e. properties set by the test case
@@ -3840,7 +3860,7 @@
If the Erlang runtime system was started without access
to an erlang shell (e.g. -noshell), compilation errors
would cause a crash in the Common Test application.
- Without access to a shell, Common Test can not prompt the
+ Without access to a shell, Common Test cannot prompt the
user to choose to continue or abort the test session, but
must assume that the session should proceed.</p>
<p>
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index 778ea2e9e2..bfa7b25862 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -390,11 +390,7 @@ testcases(TestDir, Suite) ->
end.
make_and_load(Dir, Suite) ->
- EnvInclude =
- case os:getenv("CT_INCLUDE_PATH") of
- false -> [];
- CtInclPath -> string:lexemes(CtInclPath, [$:,$ ,$,])
- end,
+ EnvInclude = string:lexemes(os:getenv("CT_INCLUDE_PATH", ""), [$:,$ ,$,]),
StartInclude =
case init:get_argument(include) of
{ok,[Dirs]} -> Dirs;
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 134ae0e1cc..7e98e6395f 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -1168,7 +1168,7 @@ get_all(Mod, ConfTests) ->
case code:which(Mod) of
non_existing ->
list_to_atom(atom_to_list(Mod)++
- " can not be compiled or loaded");
+ " cannot be compiled or loaded");
_ ->
list_to_atom(atom_to_list(Mod)++":all/0 is missing")
end,
diff --git a/lib/common_test/src/ct_release_test.erl b/lib/common_test/src/ct_release_test.erl
index 60d17f43dc..ac3dcab7c9 100644
--- a/lib/common_test/src/ct_release_test.erl
+++ b/lib/common_test/src/ct_release_test.erl
@@ -152,10 +152,10 @@
%% returned configuration must therefore also be returned from
%% the calling `init_per_*'.
%%
-%% If the initialization fails, e.g. if a required release can
-%% not be found, the function returns `{skip,Reason}'. In
+%% If the initialization fails, e.g. if a required release
+%% cannot be found, the function returns `{skip,Reason}'. In
%% this case the other test support functions in this mudule
-%% can not be used.
+%% cannot be used.
%%
%% Example:
%%
@@ -426,7 +426,7 @@ init_upgrade_test(Level) ->
case OldRel of
false ->
ct:log("Release ~tp is not available."
- " Upgrade on '~p' level can not be tested.",
+ " Upgrade on '~p' level cannot be tested.",
[FromVsn,Level]),
undefined;
_ ->
@@ -528,7 +528,7 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
{path,Path}]]),
%% Unpack the tar to complete the installation
- erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
+ ok = erl_tar:extract(RelName ++ ".tar.gz", [{cwd, InstallDir}, compressed]),
%% Add bin and log dirs
BinDir = filename:join([InstallDir, "bin"]),
@@ -554,11 +554,11 @@ target_system(Apps,CreateDir,InstallDir,{FromVsn,_,AllAppsVsns,Path}) ->
%% create start_erl.data, sys.config and start.src
StartErlData = filename:join([InstallDir, "releases", "start_erl.data"]),
- write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
+ ok = write_file(StartErlData, io_lib:fwrite("~s ~s~n", [ErtsVsn, FromVsn])),
SysConfig = filename:join([InstallDir, "releases", FromVsn, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
StartSrc = filename:join(ErtsBinDir,"start.src"),
- write_file(StartSrc,start_script()),
+ ok = write_file(StartSrc,start_script()),
ok = file:change_mode(StartSrc,8#0755),
%% Make start_erl executable
@@ -620,7 +620,7 @@ upgrade_system(Apps, FromRel, CreateDir, InstallDir, {_,ToVsn,_,_}) ->
[{path,[FromPath]},
{outdir,CreateDir}]]),
SysConfig = filename:join([CreateDir, "sys.config"]),
- write_file(SysConfig, "[]."),
+ ok = write_file(SysConfig, "[]."),
ok = systools(make_tar,[RelName,[{erts,code:root_dir()}]]),
@@ -858,7 +858,7 @@ subst_file(Src, Dest, Vars, Opts) ->
{ok, Bin} = file:read_file(Src),
Conts = unicode:characters_to_list(Bin),
NConts = subst(Conts, Vars),
- write_file(Dest, NConts),
+ ok = write_file(Dest, NConts),
case lists:member(preserve, Opts) of
true ->
{ok, FileInfo} = file:read_file_info(Src),
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index f9abecfd38..58a29edace 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -1085,7 +1085,7 @@ match_line(Name,Pid,Line,[Pattern|Patterns],FoundPrompt,Term,EO,RetTag) ->
end;
match_line(Name,Pid,Line,[],FoundPrompt,Term,EO,match) ->
match_line(Name,Pid,Line,EO#eo.haltpatterns,FoundPrompt,Term,EO,halt);
-%% print any terminated line that can not be matched
+%% print any terminated line that cannot be matched
match_line(Name,Pid,Line,[],_FoundPrompt,true,_EO,halt) ->
log(name_or_pid(Name,Pid)," ~ts",[Line]),
nomatch;
diff --git a/lib/common_test/src/ct_util.erl b/lib/common_test/src/ct_util.erl
index d8fd401a64..9f489e9bfb 100644
--- a/lib/common_test/src/ct_util.erl
+++ b/lib/common_test/src/ct_util.erl
@@ -192,7 +192,10 @@ do_start(Parent, Mode, LogDir, Verbosity) ->
ok
end,
- ct_default_gl:start_link(group_leader()),
+ case ct_default_gl:start_link(group_leader()) of
+ {ok, _} -> ok;
+ ignore -> ok
+ end,
{StartTime,TestLogDir} = ct_logs:init(Mode, Verbosity),
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 4980d1ee4b..86081369b9 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -124,7 +124,8 @@ start_log_handler() ->
shutdown=>2000,
type=>worker,
modules=>[?MODULE]},
- {ok,_} = supervisor:start_child(logger_sup,ChildSpec);
+ {ok,_} = supervisor:start_child(logger_sup,ChildSpec),
+ ok;
_Pid ->
ok
end,
diff --git a/lib/common_test/src/test_server_ctrl.erl b/lib/common_test/src/test_server_ctrl.erl
index 8bd6cd583a..34f2feb33c 100644
--- a/lib/common_test/src/test_server_ctrl.erl
+++ b/lib/common_test/src/test_server_ctrl.erl
@@ -1393,7 +1393,7 @@ temp_nodename([Chr|Base], Acc) ->
%%
%% Counts the test cases that are about to run and returns that number.
%% If there's a conf group in TestSpec with a repeat property, the total number
-%% of cases can not be calculated and NoOfCases = unknown.
+%% of cases cannot be calculated and NoOfCases = unknown.
count_test_cases(TopCases, SkipCases) when is_list(TopCases) ->
case collect_all_cases(TopCases, SkipCases) of
{error,_Why} = Error ->
@@ -4906,7 +4906,7 @@ collect_files(Dir, Pattern, St, Mode) ->
fullname_to_mod(Path) when is_list(Path) ->
%% If this is called with a binary, then we are probably in +fnu
%% mode and have found a beam file with name encoded as latin1. We
- %% will let this crash since it can not work to load such a module
+ %% will let this crash since it cannot work to load such a module
%% anyway. It should be removed or renamed!
list_to_atom(filename:rootname(filename:basename(Path))).
diff --git a/lib/common_test/test/ct_auto_compile_SUITE.erl b/lib/common_test/test/ct_auto_compile_SUITE.erl
index dface99b8f..f88f13c889 100644
--- a/lib/common_test/test/ct_auto_compile_SUITE.erl
+++ b/lib/common_test/test/ct_auto_compile_SUITE.erl
@@ -169,7 +169,7 @@ test_events(ac_flag) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
@@ -186,7 +186,7 @@ test_events(ac_spec) ->
{?eh,start_info,{1,1,3}},
{?eh,tc_start,{ct_framework,error_in_suite}},
{?eh,tc_done,{ct_framework,error_in_suite,
- {failed,{error,'bad_SUITE can not be compiled or loaded'}}}},
+ {failed,{error,'bad_SUITE cannot be compiled or loaded'}}}},
{?eh,tc_start,{dummy_SUITE,init_per_suite}},
{?eh,tc_done,{dummy_SUITE,init_per_suite,ok}},
{?eh,test_stats,{1,1,{1,0}}},
diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl
index 5ffc735d6a..ec5278b96d 100644
--- a/lib/common_test/test/ct_config_SUITE.erl
+++ b/lib/common_test/test/ct_config_SUITE.erl
@@ -211,18 +211,12 @@ reformat_events(Events, EH) ->
%%% Test related to 'localtime' will often fail if the test host is
%%% time warping, so let's just skip the 'dynamic' tests then.
skip_dynamic() ->
- case os:getenv("TS_EXTRA_PLATFORM_LABEL") of
- TSExtraPlatformLabel when is_list(TSExtraPlatformLabel) ->
- case string:find(TSExtraPlatformLabel,"TimeWarpingOS") of
- nomatch -> false;
- _ -> true
- end;
- _ ->
- false
+ case string:find(os:getenv("TS_EXTRA_PLATFORM_LABEL", ""), "TimeWarpingOS") of
+ nomatch -> false;
+ _ -> true
end.
-
%%%-----------------------------------------------------------------
%%% TEST EVENTS
%%%-----------------------------------------------------------------
diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
index a2fa099a8c..0a374d7404 100644
--- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
+++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl
@@ -205,7 +205,7 @@ hello_required_exists(Config) ->
SshDir = ?config(ssh_dir,Config),
{ok,_Client1} = open_configured_success(my_named_connection,SshDir),
- %% Check that same name can not be used twice
+ %% Check that same name cannot be used twice
{error,{connection_exists,_Client1}} =
ct_netconfc:open(my_named_connection,[{user_dir,SshDir}]),
@@ -385,7 +385,7 @@ timeout_get(Config) ->
%% received, the timeout message might already be sent when the timer
%% is cancelled. This test checks that the timeout message is flushed
%% from the message queue. If it isn't, the client crashes and the
-%% session can not be closed afterwards.
+%% session cannot be closed afterwards.
%% Note that we can only hope that the test case triggers the problem
%% every now and then, as it is very timing dependent...
flush_timeout_get(Config) ->
diff --git a/lib/common_test/test/test_server_SUITE.erl b/lib/common_test/test/test_server_SUITE.erl
index 05737cfac9..6e52f24025 100644
--- a/lib/common_test/test/test_server_SUITE.erl
+++ b/lib/common_test/test/test_server_SUITE.erl
@@ -260,7 +260,7 @@ translate_filename(Filename,EncodingOnTestNode) ->
end.
get_latest_run_dir(Dir) ->
- %% For the time being, filelib:wildcard can not take a binary
+ %% For the time being, filelib:wildcard cannot take a binary
%% argument, so we avoid using this here.
case file:list_dir(Dir) of
{ok,Files} ->
@@ -315,7 +315,7 @@ generate_and_run_unicode_test(Config0,Encoding) ->
DataDir = ?config(data_dir,Config0),
Suite = create_unicode_test_suite(DataDir,Encoding),
- %% We can not run this test on default node since it must be
+ %% We cannot run this test on default node since it must be
%% started with correct file name mode (+fnu/+fnl).
%% OBS: the node are stopped by end_per_testcase/2
Config1 = lists:keydelete(node,1,Config0),
diff --git a/lib/common_test/test/test_server_test_lib.erl b/lib/common_test/test/test_server_test_lib.erl
index 9ee946af0b..58b3aaee9b 100644
--- a/lib/common_test/test/test_server_test_lib.erl
+++ b/lib/common_test/test/test_server_test_lib.erl
@@ -22,7 +22,7 @@
-export([parse_suite/1]).
-export([init/2, pre_init_per_testcase/3, post_end_per_testcase/4]).
-%% for test_server_SUITE when node can not be started as slave
+%% for test_server_SUITE when node cannot be started as slave
-export([prepare_tester_node/2]).
-include("test_server_test_lib.hrl").
diff --git a/lib/common_test/test_server/ts_install.erl b/lib/common_test/test_server/ts_install.erl
index 048e5493d2..09f3da860a 100644
--- a/lib/common_test/test_server/ts_install.erl
+++ b/lib/common_test/test_server/ts_install.erl
@@ -112,12 +112,6 @@ get_vars([], name, [], Result) ->
get_vars(_, _, _, _) ->
{error, fatal_bad_conf_vars}.
-config_flags() ->
- case os:getenv("CONFIG_FLAGS") of
- false -> [];
- CF -> string:lexemes(CF, " \t\n")
- end.
-
unix_autoconf(XConf) ->
Configure = filename:absname("configure"),
Flags = proplists:get_value(crossflags,XConf,[]),
@@ -128,7 +122,7 @@ unix_autoconf(XConf) ->
erlang:system_info(threads) /= false],
Debug = [" --enable-debug-mode" ||
string:find(erlang:system_info(system_version),"debug") =/= nomatch],
- MXX_Build = [Y || Y <- config_flags(),
+ MXX_Build = [Y || Y <- string:lexemes(os:getenv("CONFIG_FLAGS", ""), " \t\n"),
Y == "--enable-m64-build"
orelse Y == "--enable-m32-build"],
Args = Host ++ Build ++ Threads ++ Debug ++ " " ++ MXX_Build,
@@ -164,7 +158,7 @@ assign_vars(FlagsStr) ->
assign_all_vars([$$ | Rest], FlagSoFar) ->
{VarName,Rest1} = get_var_name(Rest, []),
- assign_all_vars(Rest1, FlagSoFar ++ assign_var(VarName));
+ assign_all_vars(Rest1, FlagSoFar ++ os:getenv(VarName, ""));
assign_all_vars([Char | Rest], FlagSoFar) ->
assign_all_vars(Rest, FlagSoFar ++ [Char]);
assign_all_vars([], Flag) ->
@@ -177,12 +171,6 @@ get_var_name([Ch | Rest] = Str, VarR) ->
end;
get_var_name([], VarR) ->
{lists:reverse(VarR),[]}.
-
-assign_var(VarName) ->
- case os:getenv(VarName) of
- false -> "";
- Val -> Val
- end.
valid_char(Ch) when Ch >= $a, Ch =< $z -> true;
valid_char(Ch) when Ch >= $A, Ch =< $Z -> true;
@@ -280,7 +268,7 @@ add_vars(Vars0, Opts0) ->
{Opts, [{longnames, LongNames},
{platform_id, PlatformId},
{platform_filename, PlatformFilename},
- {rsh_name, get_rsh_name()},
+ {rsh_name, os:getenv("ERL_RSH", "rsh")},
{platform_label, PlatformLabel},
{ts_net_dir, Mounted},
{erl_flags, []},
@@ -301,16 +289,10 @@ get_testcase_callback() ->
end
end.
-get_rsh_name() ->
- case os:getenv("ERL_RSH") of
- false -> "rsh";
- Str -> Str
- end.
-
platform_id(Vars) ->
{Id,_,_,_} = platform(Vars),
Id.
-
+
platform(Vars) ->
Hostname = hostname(),
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 2dc1965878..fd5d4a57aa 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.16
+COMMON_TEST_VSN = 1.16.1
diff --git a/lib/compiler/doc/src/Makefile b/lib/compiler/doc/src/Makefile
index 661415899f..32f150eef8 100644
--- a/lib/compiler/doc/src/Makefile
+++ b/lib/compiler/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 1a71c83521..45e442f5c2 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -203,7 +203,8 @@
<tag><c>deterministic</c></tag>
<item>
<p>Omit the <c>options</c> and <c>source</c> tuples in
- the list returned by <c>Module:module_info(compile)</c>.
+ the list returned by <c>Module:module_info(compile)</c>, and
+ reduce the paths in stack traces to the module name alone.
This option will make it easier to achieve reproducible builds.
</p>
</item>
@@ -347,8 +348,8 @@ module.beam: module.erl \
<tag><c>{source,FileName}</c></tag>
<item>
- <p>Sets the value of the source, as returned by
- <c>module_info(compile)</c>.</p>
+ <p>Overrides the source file name as presented in
+ <c>module_info(compile)</c> and stack traces.</p>
</item>
<tag><c>{outdir,Dir}</c></tag>
@@ -415,6 +416,17 @@ module.beam: module.erl \
is not documented, and can change between releases.</p>
</item>
+ <tag><c>no_spawn_compiler_process</c></tag>
+ <item>
+ <p>By default, all code is compiled in a separate process
+ which is terminated at the end of compilation. However,
+ some tools, like Dialyzer or compilers for other BEAM languages,
+ may already manage their own worker processes and spawning
+ an extra process may slow the compilation down.
+ In such scenarios, you can pass this option to stop the
+ compiler from spawning an additional process.</p>
+ </item>
+
<tag><c>no_strict_record_tests</c></tag>
<item>
<p>This option is not recommended.</p>
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 0ec7aa54c7..5024310788 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,108 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>In rare circumstances, the matched out tail of a
+ binary could be the entire original binary. (There was
+ partial correction to this problem in version 7.2.5 of
+ the compiler application.)</p>
+ <p>
+ Own Id: OTP-15335 Aux Id: ERL-689, OTP-15219 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that prevented certain variable-sized
+ binary comprehensions from compiling.</p>
+ <p>
+ Own Id: OTP-15186 Aux Id: ERL-665 </p>
+ </item>
+ <item>
+ <p>When compiling from Core Erlang, funs created in
+ certain expressions that were only used for their
+ side-effects were subtly broken.</p>
+ <p>
+ Own Id: OTP-15188 Aux Id: ERL-658 </p>
+ </item>
+ <item>
+ <p>There could be an internal consistency failure when a
+ <c>receive</c> was nested in a
+ <c>try</c>/<c>catch</c>.</p>
+ <p>
+ Own Id: OTP-15218 Aux Id: ERL-684 </p>
+ </item>
+ <item>
+ <p>In rare circumstances, the matched out tail of a
+ binary could be the entire original binary.</p>
+ <p>
+ Own Id: OTP-15219 Aux Id: ERL-689 </p>
+ </item>
+ <item>
+ <p>When <c>is_map_key/2</c> was used in a guard together
+ with the <c>not/1</c> or <c>or/2</c> operators, the error
+ behavior could be wrong when <c>is_map_key/2</c> was
+ passed a non-map as the second argument. </p>
+ <p>In rare circumstances, compiling code that uses
+ <c>is_map_key/2</c> could cause an internal consistency
+ check failure.</p>
+ <p>
+ Own Id: OTP-15227 Aux Id: ERL-699 </p>
+ </item>
+ <item>
+ <p>The compiler could crash when compiling a function
+ with multiple receives in multiple clauses.</p>
+ <p>
+ Own Id: OTP-15235 Aux Id: ERL-703 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a regression in OTP-15204 that removed
+ <c>.beam</c> file metadata that some external build tools
+ relied on.</p>
+ <p>
+ Own Id: OTP-15292</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -297,6 +399,39 @@
</section>
+<section><title>Compiler 7.1.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fix a regression in OTP-15204 that removed
+ <c>.beam</c> file metadata that some external build tools
+ relied on.</p>
+ <p>
+ Own Id: OTP-15292</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.1.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed an issue where files compiled with the
+ <c>+deterministic</c> option differed if they were
+ compiled in a different directory but were otherwise
+ identical.</p>
+ <p>
+ Own Id: OTP-15204 Aux Id: ERL-679 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile
index 2408c76b48..d475e5a19a 100644
--- a/lib/compiler/src/Makefile
+++ b/lib/compiler/src/Makefile
@@ -50,9 +50,7 @@ MODULES = \
beam_asm \
beam_block \
beam_bs \
- beam_bsm \
beam_clean \
- beam_dead \
beam_dict \
beam_disasm \
beam_except \
@@ -61,12 +59,19 @@ MODULES = \
beam_listing \
beam_opcodes \
beam_peep \
- beam_receive \
- beam_reorder \
- beam_record \
- beam_split \
+ beam_ssa \
+ beam_ssa_bsm \
+ beam_ssa_codegen \
+ beam_ssa_dead \
+ beam_ssa_funs \
+ beam_ssa_lint \
+ beam_ssa_opt \
+ beam_ssa_pp \
+ beam_ssa_pre_codegen \
+ beam_ssa_recv \
+ beam_ssa_type \
+ beam_kernel_to_ssa \
beam_trim \
- beam_type \
beam_utils \
beam_validator \
beam_z \
@@ -90,7 +95,6 @@ MODULES = \
sys_core_fold_lists \
sys_core_inline \
sys_pre_attributes \
- v3_codegen \
v3_core \
v3_kernel \
v3_kernel_pp
@@ -99,6 +103,7 @@ BEAM_H = $(wildcard ../priv/beam_h/*.h)
HRL_FILES= \
beam_disasm.hrl \
+ beam_ssa.hrl \
core_parse.hrl \
v3_kernel.hrl
@@ -185,7 +190,17 @@ release_docs_spec:
# ----------------------------------------------------
$(EBIN)/beam_disasm.beam: $(EGEN)/beam_opcodes.hrl beam_disasm.hrl
-$(EBIN)/beam_listing.beam: core_parse.hrl v3_kernel.hrl
+$(EBIN)/beam_listing.beam: core_parse.hrl v3_kernel.hrl beam_ssa.hrl
+$(EBIN)/beam_kernel_to_ssa.beam: v3_kernel.hrl beam_ssa.hrl
+$(EBIN)/beam_ssa.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_codegen.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_dead.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_lint.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_opt.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_pp.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_pre_codegen.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_recv.beam: beam_ssa.hrl
+$(EBIN)/beam_ssa_type.beam: beam_ssa.hrl
$(EBIN)/cerl.beam: core_parse.hrl
$(EBIN)/compile.beam: core_parse.hrl ../../stdlib/include/erl_compile.hrl
$(EBIN)/core_lib.beam: core_parse.hrl
@@ -197,7 +212,6 @@ $(EBIN)/sys_core_dsetel.beam: core_parse.hrl
$(EBIN)/sys_core_fold.beam: core_parse.hrl
$(EBIN)/sys_core_fold_lists.beam: core_parse.hrl
$(EBIN)/sys_core_inline.beam: core_parse.hrl
-$(EBIN)/v3_codegen.beam: v3_kernel.hrl
$(EBIN)/v3_core.beam: core_parse.hrl
$(EBIN)/v3_kernel.beam: core_parse.hrl v3_kernel.hrl
$(EBIN)/v3_kernel_pp.beam: v3_kernel.hrl
diff --git a/lib/compiler/src/beam_a.erl b/lib/compiler/src/beam_a.erl
index 6fd4ace540..dd2537a699 100644
--- a/lib/compiler/src/beam_a.erl
+++ b/lib/compiler/src/beam_a.erl
@@ -39,14 +39,29 @@ function({function,Name,Arity,CLabel,Is0}) ->
%% Remove unusued labels for cleanliness and to help
%% optimization passes and HiPE.
- Is = beam_jump:remove_unused_labels(Is1),
- {function,Name,Arity,CLabel,Is}
+ Is2 = beam_jump:remove_unused_labels(Is1),
+
+ %% Some optimization passes can't handle consecutive labels.
+ %% Coalesce multiple consecutive labels.
+ Is = coalesce_consecutive_labels(Is2, [], []),
+
+ {function,Name,Arity,CLabel,Is}
catch
Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
erlang:raise(Class, Error, Stack)
end.
+rename_instrs([{test,is_eq_exact,_,[Dst,Src]}=Test,
+ {move,Src,Dst}|Is]) ->
+ %% The move instruction is not needed.
+ rename_instrs([Test|Is]);
+rename_instrs([{test,is_eq_exact,_,[Same,Same]}|Is]) ->
+ %% Same literal or same register. Will always succeed.
+ rename_instrs(Is);
+rename_instrs([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_},{label,Fail}|Is]) ->
+ %% This instruction sequence does nothing.
+ rename_instrs(Is);
rename_instrs([{apply_last,A,N}|Is]) ->
[{apply,A},{deallocate,N},return|rename_instrs(Is)];
rename_instrs([{call_last,A,F,N}|Is]) ->
@@ -113,6 +128,8 @@ rename_instr({put_map_exact,Fail,S,D,R,L}) ->
{put_map,Fail,exact,S,D,R,L};
rename_instr({test,has_map_fields,Fail,Src,{list,List}}) ->
{test,has_map_fields,Fail,[Src|List]};
+rename_instr({test,is_nil,Fail,[Src]}) ->
+ {test,is_eq_exact,Fail,[Src,nil]};
rename_instr({select_val=I,Reg,Fail,{list,List}}) ->
{select,I,Reg,Fail,List};
rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
@@ -120,3 +137,11 @@ rename_instr({select_tuple_arity=I,Reg,Fail,{list,List}}) ->
rename_instr(send) ->
{call_ext,2,send};
rename_instr(I) -> I.
+
+coalesce_consecutive_labels([{label,L}=Lbl,{label,Alias}|Is], Replace, Acc) ->
+ coalesce_consecutive_labels([Lbl|Is], [{Alias,L}|Replace], Acc);
+coalesce_consecutive_labels([I|Is], Replace, Acc) ->
+ coalesce_consecutive_labels(Is, Replace, [I|Acc]);
+coalesce_consecutive_labels([], Replace, Acc) ->
+ D = maps:from_list(Replace),
+ beam_utils:replace_labels(Acc, [], D, fun(L) -> L end).
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index fe43163455..9d8d5b2b0c 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -17,39 +17,24 @@
%%
%% %CopyrightEnd%
%%
-%% Purpose : Partitions assembly instructions into basic blocks and
-%% optimizes them.
+%% Purpose: Partition BEAM instructions into basic blocks.
-module(beam_block).
-export([module/2]).
--import(lists, [reverse/1,reverse/2,member/2]).
+-import(lists, [reverse/1,splitwith/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc}, Opts) ->
- Blockify = not member(no_blockify, Opts),
- Fs = [function(F, Blockify) || F <- Fs0],
+module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
+ Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-function({function,Name,Arity,CLabel,Is0}, Blockify) ->
+function({function,Name,Arity,CLabel,Is0}) ->
try
- %% Collect basic blocks and optimize them.
- Is1 = case Blockify of
- false -> Is0;
- true -> blockify(Is0)
- end,
- Is2 = embed_lines(Is1),
- Is3 = local_cse(Is2),
- Is4 = beam_utils:anno_defs(Is3),
- Is5 = move_allocates(Is4),
- Is6 = beam_utils:live_opt(Is5),
- Is7 = opt_blocks(Is6),
- Is8 = beam_utils:delete_annos(Is7),
- Is = opt_allocs(Is8),
-
- %% Done.
+ Is1 = blockify(Is0),
+ Is = embed_lines(Is1),
{function,Name,Arity,CLabel,Is}
catch
Class:Error:Stack ->
@@ -64,9 +49,6 @@ function({function,Name,Arity,CLabel,Is0}, Blockify) ->
blockify(Is) ->
blockify(Is, []).
-blockify([{loop_rec,{f,Fail},{x,0}},{loop_rec_end,_Lbl},{label,Fail}|Is], Acc) ->
- %% Useless instruction sequence.
- blockify(Is, Acc);
blockify([I|Is0]=IsAll, Acc) ->
case collect(I) of
error -> blockify(Is0, [I|Acc]);
@@ -80,12 +62,10 @@ collect_block(Is) ->
collect_block(Is, []).
collect_block([{allocate,N,R}|Is0], Acc) ->
- {Inits,Is} = lists:splitwith(fun ({init,{y,_}}) -> true;
- (_) -> false
- end, Is0),
+ {Inits,Is} = splitwith(fun ({init,{y,_}}) -> true;
+ (_) -> false
+ end, Is0),
collect_block(Is, [{set,[],[],{alloc,R,{nozero,N,0,Inits}}}|Acc]);
-collect_block([{allocate_zero,Ns,R},{test_heap,Nh,R}|Is], Acc) ->
- collect_block(Is, [{set,[],[],{alloc,R,{zero,Ns,Nh,[]}}}|Acc]);
collect_block([I|Is]=Is0, Acc) ->
case collect(I) of
error -> {reverse(Acc),Is0};
@@ -100,23 +80,20 @@ collect({allocate_heap,Ns,Nh,R}) -> {set,[],[],{alloc,R,{nozero,Ns,Nh,[]}}};
collect({allocate_heap_zero,Ns,Nh,R}) -> {set,[],[],{alloc,R,{zero,Ns,Nh,[]}}};
collect({init,D}) -> {set,[D],[],init};
collect({test_heap,N,R}) -> {set,[],[],{alloc,R,{nozero,nostack,N,[]}}};
-collect({bif,N,F,As,D}) -> {set,[D],As,{bif,N,F}};
-collect({gc_bif,N,F,R,As,D}) -> {set,[D],As,{alloc,R,{gc_bif,N,F}}};
+collect({bif,N,{f,0},As,D}) -> {set,[D],As,{bif,N,{f,0}}};
+collect({gc_bif,N,{f,0},R,As,D}) -> {set,[D],As,{alloc,R,{gc_bif,N,{f,0}}}};
collect({move,S,D}) -> {set,[D],[S],move};
collect({put_list,S1,S2,D}) -> {set,[D],[S1,S2],put_list};
collect({put_tuple,A,D}) -> {set,[D],[],{put_tuple,A}};
collect({put,S}) -> {set,[],[S],put};
+collect({put_tuple2,D,{list,Els}}) -> {set,[D],Els,put_tuple2};
collect({get_tuple_element,S,I,D}) -> {set,[D],[S],{get_tuple_element,I}};
collect({set_tuple_element,S,D,I}) -> {set,[],[S,D],{set_tuple_element,I}};
collect({get_hd,S,D}) -> {set,[D],[S],get_hd};
collect({get_tl,S,D}) -> {set,[D],[S],get_tl};
collect(remove_message) -> {set,[],[],remove_message};
-collect({put_map,F,Op,S,D,R,{list,Puts}}) ->
- {set,[D],[S|Puts],{alloc,R,{put_map,Op,F}}};
-collect({'catch'=Op,R,L}) ->
- {set,[R],[],{try_catch,Op,L}};
-collect({'try'=Op,R,L}) ->
- {set,[R],[],{try_catch,Op,L}};
+collect({put_map,{f,0},Op,S,D,R,{list,Puts}}) ->
+ {set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,0}}}};
collect(fclearerror) -> {set,[],[],fclearerror};
collect({fcheckerror,{f,0}}) -> {set,[],[],fcheckerror};
collect({fmove,S,D}) -> {set,[D],[S],fmove};
@@ -137,557 +114,6 @@ embed_lines([{block,B2},{line,_}=Line,{block,B1}|T], Acc) ->
embed_lines([{block,B1},{line,_}=Line|T], Acc) ->
B = {block,[{set,[],[],Line}|B1]},
embed_lines([B|T], Acc);
-embed_lines([{block,B2},{block,B1}|T], Acc) ->
- %% This can only happen when beam_block is run for
- %% the second time.
- B = {block,B1++B2},
- embed_lines([B|T], Acc);
embed_lines([I|Is], Acc) ->
embed_lines(Is, [I|Acc]);
embed_lines([], Acc) -> Acc.
-
-opt_blocks([{block,Bl0}|Is]) ->
- %% The live annotation at the beginning is not useful.
- [{'%anno',_}|Bl] = Bl0,
- [{block,opt_block(Bl)}|opt_blocks(Is)];
-opt_blocks([I|Is]) ->
- [I|opt_blocks(Is)];
-opt_blocks([]) -> [].
-
-opt_block(Is0) ->
- find_fixpoint(fun(Is) ->
- opt_tuple_element(opt(Is))
- end, Is0).
-
-find_fixpoint(OptFun, Is0) ->
- case OptFun(Is0) of
- Is0 -> Is0;
- Is1 -> find_fixpoint(OptFun, Is1)
- end.
-
-%% move_allocates(Is0) -> Is
-%% Move allocate instructions upwards in the instruction stream
-%% (within the same block), in the hope of getting more possibilities
-%% for optimizing away moves later.
-%%
-%% For example, we can transform the following instructions:
-%%
-%% get_tuple_element x(1) Element => x(2)
-%% allocate_zero StackSize 3 %% x(0), x(1), x(2) are live
-%%
-%% to the following instructions:
-%%
-%% allocate_zero StackSize 2 %% x(0) and x(1) are live
-%% get_tuple_element x(1) Element => x(2)
-%%
-%% NOTE: Since the beam_reorder pass has been run, it is no longer
-%% safe to assume that if x(N) is initialized, then all lower-numbered
-%% x registers are also initialized.
-%%
-%% For example, we must be careful when transforming the following
-%% instructions:
-%%
-%% get_tuple_element x(0) Element => x(1)
-%% allocate_zero StackSize 3 %x(0), x(1), x(2) are live
-%%
-%% to the following instructions:
-%%
-%% allocate_zero StackSize 3
-%% get_tuple_element x(0) Element => x(1)
-%%
-%% The transformation is safe if and only if x(1) has been
-%% initialized previously. We will use the annotations added by
-%% beam_utils:anno_defs/1 to determine whether x(a) has been
-%% initialized.
-
-move_allocates([{block,Bl0}|Is]) ->
- Bl = move_allocates_1(reverse(Bl0), []),
- [{block,Bl}|move_allocates(Is)];
-move_allocates([I|Is]) ->
- [I|move_allocates(Is)];
-move_allocates([]) -> [].
-
-move_allocates_1([{'%anno',_}|Is], Acc) ->
- move_allocates_1(Is, Acc);
-move_allocates_1([I|Is], [{set,[],[],{alloc,Live0,Info0}}|Acc]=Acc0) ->
- case alloc_may_pass(I) of
- false ->
- move_allocates_1(Is, [I|Acc0]);
- true ->
- case alloc_live_regs(I, Is, Live0) of
- not_possible ->
- move_allocates_1(Is, [I|Acc0]);
- Live when is_integer(Live) ->
- Info = safe_info(Info0),
- A = {set,[],[],{alloc,Live,Info}},
- move_allocates_1(Is, [A,I|Acc])
- end
- end;
-move_allocates_1([I|Is], Acc) ->
- move_allocates_1(Is, [I|Acc]);
-move_allocates_1([], Acc) -> Acc.
-
-alloc_may_pass({set,_,[{fr,_}],fmove}) -> false;
-alloc_may_pass({set,_,_,{alloc,_,_}}) -> false;
-alloc_may_pass({set,_,_,{set_tuple_element,_}}) -> false;
-alloc_may_pass({set,_,_,put_list}) -> false;
-alloc_may_pass({set,_,_,put}) -> false;
-alloc_may_pass({set,_,_,_}) -> true.
-
-safe_info({nozero,Stack,Heap,_}) ->
- %% nozero is not safe if the allocation instruction is moved
- %% upwards past an instruction that may throw an exception
- %% (such as element/2).
- {zero,Stack,Heap,[]};
-safe_info(Info) -> Info.
-
-%% opt([Instruction]) -> [Instruction]
-%% Optimize the instruction stream inside a basic block.
-
-opt([{set,[X],[X],move}|Is]) -> opt(Is);
-opt([{set,[Dst],_,move},{set,[Dst],[Src],move}=I|Is]) when Dst =/= Src ->
- opt([I|Is]);
-opt([{set,[{x,0}],[S1],move}=I1,{set,[D2],[{x,0}],move}|Is]) ->
- opt([I1,{set,[D2],[S1],move}|Is]);
-opt([{set,[{x,0}],[S1],move}=I1,{set,[D2],[S2],move}|Is0]) when S1 =/= D2 ->
- %% Place move S x0 at the end of move sequences so that
- %% loader can merge with the following instruction
- {Ds,Is} = opt_moves([D2], Is0),
- [{set,Ds,[S2],move}|opt([I1|Is])];
-opt([{set,_,_,{line,_}}=Line1,
- {set,[D1],[{integer,Idx1},Reg],{bif,element,{f,0}}}=I1,
- {set,_,_,{line,_}}=Line2,
- {set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is])
- when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
- opt([Line2,I2,Line1,I1|Is]);
-opt([{set,[D1],[{integer,Idx1},Reg],{bif,element,{f,L}}}=I1,
- {set,[D2],[{integer,Idx2},Reg],{bif,element,{f,L}}}=I2|Is])
- when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
- opt([I2,I1|Is]);
-opt([{set,Hd0,Cons,get_hd}=GetHd,
- {set,Tl0,Cons,get_tl}=GetTl|Is0]) ->
- case {opt_moves(Hd0, [GetTl|Is0]),opt_moves(Tl0, [GetHd|Is0])} of
- {{Hd0,Is},{Tl0,_}} ->
- [GetHd|opt(Is)];
- {{Hd,Is},{Tl0,_}} ->
- [{set,Hd,Cons,get_hd}|opt(Is)];
- {{_,_},{Tl,Is}} ->
- [{set,Tl,Cons,get_tl}|opt(Is)]
- end;
-opt([{set,Ds0,Ss,Op}|Is0]) ->
- {Ds,Is} = opt_moves(Ds0, Is0),
- [{set,Ds,Ss,Op}|opt(Is)];
-opt([{'%anno',_}=I|Is]) ->
- [I|opt(Is)];
-opt([]) -> [].
-
-%% opt_moves([Dest], [Instruction]) -> {[Dest],[Instruction]}
-%% For each Dest, does the optimization described in opt_move/2.
-
-opt_moves([], Is0) -> {[],Is0};
-opt_moves([D0]=Ds, Is0) ->
- case opt_move(D0, Is0) of
- not_possible -> {Ds,Is0};
- {D1,Is} -> {[D1],Is}
- end.
-
-%% opt_move(Dest, [Instruction]) -> {UpdatedDest,[Instruction]} | not_possible
-%% If there is a {move,Dest,FinalDest} instruction
-%% in the instruction stream, remove the move instruction
-%% and let FinalDest be the destination.
-
-opt_move(Dest, Is) ->
- opt_move_1(Dest, Is, []).
-
-opt_move_1(R, [{set,[D],[R],move}|Is0], Acc) ->
- %% Provided that the source register is killed by instructions
- %% that follow, the optimization is safe.
- case eliminate_use_of_from_reg(Is0, R, D) of
- {yes,Is} -> opt_move_rev(D, Acc, Is);
- no -> not_possible
- end;
-opt_move_1(_R, [{set,_,_,{alloc,_,_}}|_], _) ->
- %% The optimization is either not possible or not safe.
- %%
- %% If R is an X register killed by allocation, the optimization is
- %% not safe. On the other hand, if the X register is killed, there
- %% will not follow a 'move' instruction with this X register as
- %% the source.
- %%
- %% If R is a Y register, the optimization is still not safe
- %% because the new target register is an X register that cannot
- %% safely pass the alloc instruction.
- not_possible;
-opt_move_1(R, [{set,_,_,_}=I|Is], Acc) ->
- %% If the source register is either killed or used by this
- %% instruction, the optimimization is not possible.
- case is_killed_or_used(R, I) of
- true -> not_possible;
- false -> opt_move_1(R, Is, [I|Acc])
- end;
-opt_move_1(_, _, _) ->
- not_possible.
-
-%% opt_tuple_element([Instruction]) -> [Instruction]
-%% If possible, move get_tuple_element instructions forward
-%% in the instruction stream to a move instruction, eliminating
-%% the move instruction. Example:
-%%
-%% get_tuple_element Tuple Pos Dst1
-%% ...
-%% move Dst1 Dst2
-%%
-%% This code may be possible to rewrite to:
-%%
-%% %%(Moved get_tuple_element instruction)
-%% ...
-%% get_tuple_element Tuple Pos Dst2
-%%
-
-opt_tuple_element([{set,[D],[S],{get_tuple_element,_}}=I|Is0]) ->
- case opt_tuple_element_1(Is0, I, {S,D}, []) of
- no ->
- [I|opt_tuple_element(Is0)];
- {yes,Is} ->
- opt_tuple_element(Is)
- end;
-opt_tuple_element([I|Is]) ->
- [I|opt_tuple_element(Is)];
-opt_tuple_element([]) -> [].
-
-opt_tuple_element_1([{set,_,_,{alloc,_,_}}|_], _, _, _) ->
- no;
-opt_tuple_element_1([{set,_,_,{try_catch,_,_}}|_], _, _, _) ->
- no;
-opt_tuple_element_1([{set,[D],[S],move}|Is0], I0, {_,S}, Acc) ->
- case eliminate_use_of_from_reg(Is0, S, D) of
- no ->
- no;
- {yes,Is1} ->
- {set,[S],Ss,Op} = I0,
- I = {set,[D],Ss,Op},
- case opt_move_rev(S, Acc, [I|Is1]) of
- not_possible ->
- %% Not safe because the move of the
- %% get_tuple_element instruction would cause the
- %% result of a previous instruction to be ignored.
- no;
- {_,Is} ->
- {yes,Is}
- end
- end;
-opt_tuple_element_1([{set,Ds,Ss,_}=I|Is], MovedI, {S,D}=Regs, Acc) ->
- case member(S, Ds) orelse member(D, Ss) of
- true ->
- no;
- false ->
- opt_tuple_element_1(Is, MovedI, Regs, [I|Acc])
- end;
-opt_tuple_element_1(_, _, _, _) -> no.
-
-%% Reverse the instructions, while checking that there are no
-%% instructions that would interfere with using the new destination
-%% register (D).
-
-opt_move_rev(D, [I|Is], Acc) ->
- case is_killed_or_used(D, I) of
- true -> not_possible;
- false -> opt_move_rev(D, Is, [I|Acc])
- end;
-opt_move_rev(D, [], Acc) -> {D,Acc}.
-
-%% is_killed_or_used(Register, {set,_,_,_}) -> bool()
-%% Test whether the register is used by the instruction.
-
-is_killed_or_used(R, {set,Ss,Ds,_}) ->
- member(R, Ds) orelse member(R, Ss).
-
-%% eliminate_use_of_from_reg([Instruction], FromRegister, ToRegister, Acc) ->
-%% {yes,Is} | no
-%% Eliminate any use of FromRegister in the instruction sequence
-%% by replacing uses of FromRegister with ToRegister. If FromRegister
-%% is referenced by an allocation instruction, return 'no' to indicate
-%% that FromRegister is still used and that the optimization is not
-%% possible.
-
-eliminate_use_of_from_reg(Is, From, To) ->
- try
- eliminate_use_of_from_reg(Is, From, To, [])
- catch
- throw:not_possible ->
- no
- end.
-
-eliminate_use_of_from_reg([{set,_,_,{alloc,Live,_}}|_]=Is0, {x,X}, _, Acc) ->
- if
- X < Live ->
- no;
- true ->
- {yes,reverse(Acc, Is0)}
- end;
-eliminate_use_of_from_reg([{set,Ds,Ss0,Op}=I0|Is], From, To, Acc) ->
- ensure_safe_tuple(I0, To),
- I = case member(From, Ss0) of
- true ->
- Ss = [case S of
- From -> To;
- _ -> S
- end || S <- Ss0],
- {set,Ds,Ss,Op};
- false ->
- I0
- end,
- case member(From, Ds) of
- true ->
- {yes,reverse(Acc, [I|Is])};
- false ->
- case member(To, Ds) of
- true ->
- case beam_utils:is_killed_block(From, Is) of
- true ->
- {yes,reverse(Acc, [I|Is])};
- false ->
- no
- end;
- false ->
- eliminate_use_of_from_reg(Is, From, To, [I|Acc])
- end
- end;
-eliminate_use_of_from_reg([I]=Is, From, _To, Acc) ->
- case beam_utils:is_killed_block(From, [I]) of
- true ->
- {yes,reverse(Acc, Is)};
- false ->
- no
- end.
-
-ensure_safe_tuple({set,[To],[],{put_tuple,_}}, To) ->
- throw(not_possible);
-ensure_safe_tuple(_, _) -> ok.
-
-%% opt_allocs(Instructions) -> Instructions. Optimize allocate
-%% instructions inside blocks. If safe, replace an allocate_zero
-%% instruction with the slightly cheaper allocate instruction.
-
-opt_allocs(Is) ->
- D = beam_utils:index_labels(Is),
- opt_allocs_1(Is, D).
-
-opt_allocs_1([{block,Bl0}|Is], D) ->
- Bl = opt_alloc(Bl0, {D,Is}),
- [{block,Bl}|opt_allocs_1(Is, D)];
-opt_allocs_1([I|Is], D) ->
- [I|opt_allocs_1(Is, D)];
-opt_allocs_1([], _) -> [].
-
-%% opt_alloc(Instructions) -> Instructions'
-%% Optimises all allocate instructions.
-
-opt_alloc([{set,[],[],{alloc,Live0,Info0}},
- {set,[],[],{alloc,Live,Info}}|Is], D) ->
- Live = Live0, %Assertion.
- Alloc = combine_alloc(Info0, Info),
- I = {set,[],[],{alloc,Live,Alloc}},
- opt_alloc([I|Is], D);
-opt_alloc([{set,[],[],{alloc,R,{_,Ns,Nh,[]}}}|Is], D) ->
- [{set,[],[],opt_alloc(Is, D, Ns, Nh, R)}|Is];
-opt_alloc([I|Is], D) -> [I|opt_alloc(Is, D)];
-opt_alloc([], _) -> [].
-
-combine_alloc({_,Ns,Nh1,Init}, {_,nostack,Nh2,[]}) ->
- {zero,Ns,beam_utils:combine_heap_needs(Nh1, Nh2),Init}.
-
-%% opt_alloc(Instructions, FrameSize, HeapNeed, LivingRegs) -> [Instr]
-%% Generates the optimal sequence of instructions for
-%% allocating and initalizing the stack frame and needed heap.
-
-opt_alloc(_Is, _D, nostack, Nh, LivingRegs) ->
- {alloc,LivingRegs,{nozero,nostack,Nh,[]}};
-opt_alloc(Bl, {D,OuterIs}, Ns, Nh, LivingRegs) ->
- Is = [{block,Bl}|OuterIs],
- InitRegs = init_yregs(Ns, Is, D),
- case count_ones(InitRegs) of
- N when N*2 > Ns ->
- {alloc,LivingRegs,{nozero,Ns,Nh,gen_init(Ns, InitRegs)}};
- _ ->
- {alloc,LivingRegs,{zero,Ns,Nh,[]}}
- end.
-
-gen_init(Fs, Regs) -> gen_init(Fs, Regs, 0, []).
-
-gen_init(SameFs, _Regs, SameFs, Acc) -> reverse(Acc);
-gen_init(Fs, Regs, Y, Acc) when Regs band 1 =:= 0 ->
- gen_init(Fs, Regs bsr 1, Y+1, [{init,{y,Y}}|Acc]);
-gen_init(Fs, Regs, Y, Acc) ->
- gen_init(Fs, Regs bsr 1, Y+1, Acc).
-
-init_yregs(Y, Is, D) when Y >= 0 ->
- case beam_utils:is_killed({y,Y}, Is, D) of
- true ->
- (1 bsl Y) bor init_yregs(Y-1, Is, D);
- false ->
- init_yregs(Y-1, Is, D)
- end;
-init_yregs(_, _, _) -> 0.
-
-count_ones(Bits) -> count_ones(Bits, 0).
-count_ones(0, Acc) -> Acc;
-count_ones(Bits, Acc) ->
- count_ones(Bits bsr 1, Acc + (Bits band 1)).
-
-%% Calculate the new number of live registers when we move an allocate
-%% instruction upwards, passing a 'set' instruction.
-
-alloc_live_regs({set,Ds,Ss,_}, Is, Regs0) ->
- Rset = x_live(Ss, x_dead(Ds, (1 bsl Regs0)-1)),
- Live = live_regs(0, Rset),
- case ensure_contiguous(Rset, Live) of
- not_possible ->
- %% Liveness information (looking forward in the
- %% instruction stream) can't prove that moving this
- %% allocation instruction is safe. Now use the annotation
- %% of defined registers at the beginning of the current
- %% block to see whether moving would be safe.
- Def0 = defined_regs(Is, 0),
- Def = Def0 band ((1 bsl Live) - 1),
- ensure_contiguous(Rset bor Def, Live);
- Live ->
- %% Safe based on liveness information.
- Live
- end.
-
-live_regs(N, 0) ->
- N;
-live_regs(N, Regs) ->
- live_regs(N+1, Regs bsr 1).
-
-ensure_contiguous(Regs, Live) ->
- case (1 bsl Live) - 1 of
- Regs -> Live;
- _ -> not_possible
- end.
-
-x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
-x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
-x_dead([], Regs) -> Regs.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
-
-%% defined_regs(ReversedInstructions) -> RegBitmap.
-%% Given a reversed instruction stream, determine the
-%% the registers that are defined.
-
-defined_regs([{'%anno',{def,Def}}|_], Regs) ->
- Def bor Regs;
-defined_regs([{set,Ds,_,{alloc,Live,_}}|_], Regs) ->
- x_live(Ds, Regs bor ((1 bsl Live) - 1));
-defined_regs([{set,Ds,_,_}|Is], Regs) ->
- defined_regs(Is, x_live(Ds, Regs)).
-
-%%%
-%%% Do local common sub expression elimination (CSE) in each block.
-%%%
-
-local_cse([{block,Bl0}|Is]) ->
- Bl = cse_block(Bl0, orddict:new(), []),
- [{block,Bl}|local_cse(Is)];
-local_cse([I|Is]) ->
- [I|local_cse(Is)];
-local_cse([]) -> [].
-
-cse_block([I|Is], Es0, Acc0) ->
- Es1 = cse_clear(I, Es0),
- case cse_expr(I) of
- none ->
- %% Instruction is not suitable for CSE.
- cse_block(Is, Es1, [I|Acc0]);
- {ok,D,Expr} ->
- %% Suitable instruction. First update the dictionary of
- %% suitable expressions for the next iteration.
- Es = cse_add(D, Expr, Es1),
-
- %% Search for a previous identical expression.
- case cse_find(Expr, Es0) of
- error ->
- %% Nothing found
- cse_block(Is, Es, [I|Acc0]);
- Src ->
- %% Use the previously calculated result.
- %% Also eliminate any line instruction.
- Move = {set,[D],[Src],move},
- case Acc0 of
- [{set,_,_,{line,_}}|Acc] ->
- cse_block(Is, Es, [Move|Acc]);
- [_|_] ->
- cse_block(Is, Es, [Move|Acc0])
- end
- end
- end;
-cse_block([], _, Acc) ->
- reverse(Acc).
-
-%% cse_find(Expr, Expressions) -> error | Register.
-%% Find a previously evaluated expression whose result can be reused,
-%% or return 'error' if no such expression is found.
-
-cse_find(Expr, Es) ->
- case orddict:find(Expr, Es) of
- {ok,{Src,_}} -> Src;
- error -> error
- end.
-
-cse_expr({set,[D],Ss,{bif,N,_}}) ->
- case D of
- {fr,_} ->
- %% There are too many things that can go wrong.
- none;
- _ ->
- {ok,D,{{bif,N},Ss}}
- end;
-cse_expr({set,[D],Ss,{alloc,_,{gc_bif,N,_}}}) ->
- {ok,D,{{gc_bif,N},Ss}};
-cse_expr({set,[D],Ss,put_list}) ->
- {ok,D,{put_list,Ss}};
-cse_expr(_) -> none.
-
-%% cse_clear(Instr, Expressions0) -> Expressions.
-%% Remove all previous expressions that will become
-%% invalid when this instruction is executed. Basically,
-%% an expression is no longer safe to reuse when the
-%% register it has been stored to has been modified, killed,
-%% or if any of the source operands have changed.
-
-cse_clear({set,Ds,_,{alloc,Live,_}}, Es) ->
- cse_clear_1(Es, Live, Ds);
-cse_clear({set,Ds,_,_}, Es) ->
- cse_clear_1(Es, all, Ds).
-
-cse_clear_1(Es, Live, Ds0) ->
- Ds = ordsets:from_list(Ds0),
- [E || E <- Es, cse_is_safe(E, Live, Ds)].
-
-cse_is_safe({_,{Dst,Interfering}}, Live, Ds) ->
- ordsets:is_disjoint(Interfering, Ds) andalso
- case Dst of
- {x,X} ->
- X < Live;
- _ ->
- true
- end.
-
-%% cse_add(Dest, Expr, Expressions0) -> Expressions.
-%% Provided that it is safe, add a new expression to the dictionary
-%% of already evaluated expressions.
-
-cse_add(D, {_,Ss}=Expr, Es) ->
- case member(D, Ss) of
- false ->
- Interfering = ordsets:from_list([D|Ss]),
- orddict:store(Expr, {D,Interfering}, Es);
- true ->
- %% Unsafe because the instruction overwrites one of
- %% source operands.
- Es
- end.
diff --git a/lib/compiler/src/beam_bs.erl b/lib/compiler/src/beam_bs.erl
index 5f1b9ed488..15d8d687fc 100644
--- a/lib/compiler/src/beam_bs.erl
+++ b/lib/compiler/src/beam_bs.erl
@@ -17,26 +17,24 @@
%%
%% %CopyrightEnd%
%%
-%% Purpose : Partitions assembly instructions into basic blocks and
-%% optimizes them.
+%% Purpose: Peephole optimization of binary syntax instructions.
-module(beam_bs).
-export([module/2]).
--import(lists, [mapfoldl/3,reverse/1]).
+-import(lists, [reverse/1]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
- {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
+module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
+ Fs = [function(F) || F <- Fs0],
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-function({function,Name,Arity,CLabel,Is0}, Lc0) ->
+function({function,Name,Arity,CLabel,Is0}) ->
try
- Is1 = bs_put_opt(Is0),
- {Is,Lc} = bsm_opt(Is1, Lc0),
- {{function,Name,Arity,CLabel,Is},Lc}
+ Is = bs_opt(Is0),
+ {function,Name,Arity,CLabel,Is}
catch
Class:Error:Stack ->
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
@@ -44,16 +42,25 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) ->
end.
%%%
-%%% Evaluation of constant bit fields.
+%%% Evaluate construction of constant bit fields.
+%%% Combine bs_skip_bits2 and bs_test_tail2 instructions.
%%%
-bs_put_opt([{bs_put,_,_,_}=I|Is0]) ->
+bs_opt([{bs_put,_,_,_}=I|Is0]) ->
{BsPuts0,Is} = collect_bs_puts(Is0, [I]),
BsPuts = opt_bs_puts(BsPuts0),
- BsPuts ++ bs_put_opt(Is);
-bs_put_opt([I|Is]) ->
- [I|bs_put_opt(Is)];
-bs_put_opt([]) -> [].
+ BsPuts ++ bs_opt(Is);
+bs_opt([{test,bs_skip_bits2,F,[Ctx,{integer,I},Unit,_Flags]},
+ {test,bs_test_tail2,F,[Ctx,Bits]}|Is]) ->
+ [{test,bs_test_tail2,F,[Ctx,Bits+I*Unit]}|bs_opt(Is)];
+bs_opt([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,Flags]},
+ {test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,_]}|Is]) ->
+ I = {test,bs_skip_bits2,F,
+ [Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]},
+ bs_opt([I|Is]);
+bs_opt([I|Is]) ->
+ [I|bs_opt(Is)];
+bs_opt([]) -> [].
collect_bs_puts([{bs_put,_,_,_}=I|Is], Acc) ->
collect_bs_puts(Is, [I|Acc]);
@@ -174,107 +181,3 @@ bs_split_int_1(N, ByteSz, Sz, Fail, Acc) when Sz > 0 ->
[{integer,ByteSz},{integer,N band Mask}]},
bs_split_int_1(N bsr ByteSz, 8, Sz-ByteSz, Fail, [I|Acc]);
bs_split_int_1(_, _, _, _, Acc) -> Acc.
-
-%%%
-%%% Optimization of bit syntax matching: get rid
-%%% of redundant bs_restore2/2 instructions across select_val
-%%% instructions, as well as a few other simple peep-hole
-%%% optimizations.
-%%%
-
-bsm_opt(Is0, Lc0) ->
- {Is1,D0,Lc} = bsm_scan(Is0, [], Lc0, []),
- Is2 = case D0 of
- [] ->
- %% No bit syntax matching in this function.
- Is1;
- [_|_] ->
- %% Optimize the bit syntax matching.
- D = gb_trees:from_orddict(orddict:from_list(D0)),
- bsm_reroute(Is1, D, none, [])
- end,
- Is = beam_clean:bs_clean_saves(Is2),
- {bsm_opt_2(Is, []),Lc}.
-
-bsm_scan([{label,L}=Lbl,{bs_restore2,_,Save}=R|Is], D0, Lc, Acc0) ->
- D = [{{L,Save},Lc}|D0],
- Acc = [{label,Lc},R,Lbl|Acc0],
- bsm_scan(Is, D, Lc+1, Acc);
-bsm_scan([I|Is], D, Lc, Acc) ->
- bsm_scan(Is, D, Lc, [I|Acc]);
-bsm_scan([], D, Lc, Acc) ->
- {reverse(Acc),D,Lc}.
-
-bsm_reroute([{bs_save2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{bs_restore2,Reg,Save}=I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, {Reg,Save}, [I|Acc]);
-bsm_reroute([{label,_}=I|Is], D, S, Acc) ->
- bsm_reroute(Is, D, S, [I|Acc]);
-bsm_reroute([{select,select_val,Reg,F0,Lbls0}|Is], D, {_,Save}=S, Acc0) ->
- [F|Lbls] = bsm_subst_labels([F0|Lbls0], Save, D),
- Acc = [{select,select_val,Reg,F,Lbls}|Acc0],
- bsm_reroute(Is, D, S, Acc);
-bsm_reroute([{test,TestOp,F0,TestArgs}=I|Is], D, {_,Save}=S, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,TestArgs}|Acc0],
- case bsm_not_bs_test(I) of
- true ->
- %% The test instruction will not update the bit offset for
- %% the binary being matched. Therefore the save position
- %% can be kept.
- bsm_reroute(Is, D, S, Acc);
- false ->
- %% The test instruction might update the bit offset. Kill
- %% our remembered Save position.
- bsm_reroute(Is, D, none, Acc)
- end;
-bsm_reroute([{test,TestOp,F0,Live,TestArgs,Dst}|Is], D, {_,Save}, Acc0) ->
- F = bsm_subst_label(F0, Save, D),
- Acc = [{test,TestOp,F,Live,TestArgs,Dst}|Acc0],
- %% The test instruction will update the bit offset. Kill our
- %% remembered Save position.
- bsm_reroute(Is, D, none, Acc);
-bsm_reroute([{block,[{set,[],[],{alloc,_,_}}]}=Bl,
- {bs_context_to_binary,_}=I|Is], D, S, Acc) ->
- %% To help further bit syntax optimizations.
- bsm_reroute([I,Bl|Is], D, S, Acc);
-bsm_reroute([I|Is], D, _, Acc) ->
- bsm_reroute(Is, D, none, [I|Acc]);
-bsm_reroute([], _, _, Acc) -> reverse(Acc).
-
-bsm_opt_2([{test,bs_test_tail2,F,[Ctx,Bits]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I},Unit,_Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_test_tail2,F,[Ctx,Bits+I*Unit]}|Acc]);
-bsm_opt_2([{test,bs_skip_bits2,F,[Ctx,{integer,I1},Unit1,_]}|Is],
- [{test,bs_skip_bits2,F,[Ctx,{integer,I2},Unit2,Flags]}|Acc]) ->
- bsm_opt_2(Is, [{test,bs_skip_bits2,F,
- [Ctx,{integer,I1*Unit1+I2*Unit2},1,Flags]}|Acc]);
-bsm_opt_2([I|Is], Acc) ->
- bsm_opt_2(Is, [I|Acc]);
-bsm_opt_2([], Acc) -> reverse(Acc).
-
-%% bsm_not_bs_test({test,Name,_,Operands}) -> true|false.
-%% Test whether is the test is a "safe", i.e. does not move the
-%% bit offset for a binary.
-%%
-%% 'true' means that the test is safe, 'false' that we don't know or
-%% that the test moves the offset (e.g. bs_get_integer2).
-
-bsm_not_bs_test({test,bs_test_tail2,_,[_,_]}) -> true;
-bsm_not_bs_test(Test) -> beam_utils:is_pure_test(Test).
-
-bsm_subst_labels(Fs, Save, D) ->
- bsm_subst_labels_1(Fs, Save, D, []).
-
-bsm_subst_labels_1([F|Fs], Save, D, Acc) ->
- bsm_subst_labels_1(Fs, Save, D, [bsm_subst_label(F, Save, D)|Acc]);
-bsm_subst_labels_1([], _, _, Acc) ->
- reverse(Acc).
-
-bsm_subst_label({f,Lbl0}=F, Save, D) ->
- case gb_trees:lookup({Lbl0,Save}, D) of
- {value,Lbl} -> {f,Lbl};
- none -> F
- end;
-bsm_subst_label(Other, _, _) -> Other.
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
deleted file mode 100644
index 1c8e0e9854..0000000000
--- a/lib/compiler/src/beam_bsm.erl
+++ /dev/null
@@ -1,708 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_bsm).
--export([module/2,format_error/1]).
-
--import(lists, [member/2,foldl/3,reverse/1,sort/1,all/2]).
-
-%%%
-%%% We optimize bit syntax matching where the tail end of a binary is
-%%% matched out and immediately passed on to a bs_start_match2 instruction,
-%%% such as in this code sequence:
-%%%
-%%% func_info ...
-%%% L1 test bs_start_match2 {f,...} {x,0} Live SavePositions {x,0}
-%%% . . .
-%%% test bs_get_binary2 {f,...} {x,0} all 1 Flags {x,0}
-%%% . . .
-%%% call_only 2 L1
-%%%
-%%% The sequence can be optimized simply by removing the bs_get_binary2
-%%% instruction. Another example:
-%%%
-%%% func_info ...
-%%% L1 test bs_start_match2 {f,...} {x,0} Live SavePositions {x,0}
-%%% . . .
-%%% test bs_get_binary2 {f,...} {x,0} all 8 Flags {x,1}
-%%% . . .
-%%% move {x,1} {x,0}
-%%% call_only 2 L1
-%%%
-%%% In this case, the bs_get_binary2 instruction must be replaced by
-%%%
-%%% test bs_unit {x,1} 8
-%%%
-%%% to ensure that the match fail if the length of the binary in bits
-%%% is not evenly divisible by 8.
-%%%
-%%% Note that the bs_start_match2 instruction doesn't need to be in the same
-%%% function as the caller. It can be in the beginning of any function, or
-%%% follow the bs_get_binary2 instruction in the same function. The important
-%%% thing is that the match context register is not copied or built into
-%%% data structures or passed to BIFs.
-%%%
-
--type label() :: beam_asm:label().
--type func_info() :: {beam_asm:reg(),boolean()}.
-
--record(btb,
- {f :: gb_trees:tree(label(), func_info()),
- index :: beam_utils:code_index(), %{Label,Code} index (for liveness).
- ok_br=gb_sets:empty() :: gb_sets:set(label()), %Labels that are OK.
- must_not_save=false :: boolean(), %Must not save position when
- % optimizing (reaches
- % bs_context_to_binary).
- must_save=false :: boolean() %Must save position when optimizing.
- }).
-
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, Opts) ->
- FIndex = btb_index(Fs0),
- Fs = [function(F, FIndex) || F <- Fs0],
- Code = {Mod,Exp,Attr,Fs,Lc},
- case proplists:get_bool(bin_opt_info, Opts) of
- true ->
- {ok,Code,collect_warnings(Fs)};
- false ->
- {ok,Code}
- end.
-
--spec format_error('bin_opt' | {'no_bin_opt', term()}) -> nonempty_string().
-
-format_error(bin_opt) ->
- "OPTIMIZED: creation of sub binary delayed";
-format_error({no_bin_opt,Reason}) ->
- lists:flatten(["NOT OPTIMIZED: "|format_error_1(Reason)]).
-
-%%%
-%%% Local functions.
-%%%
-
-function({function,Name,Arity,Entry,Is}, FIndex) ->
- try
- Index = beam_utils:index_labels(Is),
- D = #btb{f=FIndex,index=Index},
- {function,Name,Arity,Entry,btb_opt_1(Is, D, [])}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-btb_opt_1([{test,bs_get_binary2,F,_,[Reg,{atom,all},U,Fs],Reg}=I0|Is], D, Acc0) ->
- case btb_reaches_match(Is, [Reg], D) of
- {error,Reason} ->
- Comment = btb_comment_no_opt(Reason, Fs),
- btb_opt_1(Is, D, [Comment,I0|Acc0]);
- {ok,MustSave} ->
- Comment = btb_comment_opt(Fs),
- Acc1 = btb_gen_save(MustSave, Reg, [Comment|Acc0]),
- Acc = case U of
- 1 -> Acc1;
- _ -> [{test,bs_test_unit,F,[Reg,U]}|Acc1]
- end,
- btb_opt_1(Is, D, Acc)
- end;
-btb_opt_1([{test,bs_get_binary2,F,_,[Ctx,{atom,all},U,Fs],Dst}=I0|Is0], D, Acc0) ->
- case btb_reaches_match(Is0, [Ctx,Dst], D) of
- {error,Reason} ->
- Comment = btb_comment_no_opt(Reason, Fs),
- btb_opt_1(Is0, D, [Comment,I0|Acc0]);
- {ok,MustSave} when U =:= 1 ->
- Comment = btb_comment_opt(Fs),
- Acc = btb_gen_save(MustSave, Ctx, [Comment|Acc0]),
- Is = prepend_move(Ctx, Dst, Is0),
- btb_opt_1(Is, D, Acc);
- {ok,MustSave} ->
- Comment = btb_comment_opt(Fs),
- Acc1 = btb_gen_save(MustSave, Ctx, [Comment|Acc0]),
- Acc = [{test,bs_test_unit,F,[Ctx,U]}|Acc1],
- Is = prepend_move(Ctx, Dst, Is0),
- btb_opt_1(Is, D, Acc)
- end;
-btb_opt_1([I|Is], D, Acc) ->
- %%io:format("~p\n", [I]),
- btb_opt_1(Is, D, [I|Acc]);
-btb_opt_1([], _, Acc) ->
- reverse(Acc).
-
-btb_gen_save(true, Reg, Acc) ->
- [{bs_save2,Reg,{atom,start}}|Acc];
-btb_gen_save(false, _, Acc) -> Acc.
-
-prepend_move(Ctx, Dst, [{block,Bl0}|Is]) ->
- Bl = [{set,[Dst],[Ctx],move}|Bl0],
- [{block,Bl}|Is];
-prepend_move(Ctx, Dst, Is) ->
- [{move,Ctx,Dst}|Is].
-
-%% btb_reaches_match([Instruction], [Register], D) ->
-%% {ok,MustSave}|{error,Reason}
-%%
-%% The list of Registers should be a list of registers referencing a
-%% match context. The Register may contain one element if the
-%% bs_get_binary2 instruction looks like
-%%
-%% test bs_get_binary2 {f,...} Ctx all _ _ Ctx
-%%
-%% or two elements if the instruction looks like
-%%
-%% test bs_get_binary2 {f,...} Ctx all _ _ Dst
-%%
-%% This function determines whether the bs_get_binary2 instruction
-%% can be omitted (retaining the match context instead of creating
-%% a sub binary).
-%%
-%% The rule is that the match context ultimately must end up at a
-%% bs_start_match2 instruction and nowhere else. That it, it must not
-%% be passed to BIFs, or copied or put into data structures. There
-%% must only be one copy alive when the match context reaches the
-%% bs_start_match2 instruction.
-%%
-%% At a branch, we must follow all branches and make sure that the above
-%% rule is followed (or that the branch kills the match context).
-%%
-%% The MustSave return value will be true if control may end up at
-%% bs_context_to_binary instruction. Since that instruction uses the
-%% saved start position, we must use "bs_save2 Ctx start" to
-%% update the saved start position. An additional complication is that
-%% "bs_save2 Ctx start" must not be used if Dst and Ctx are
-%% different registers and both registers may be passed to
-%% a bs_context_to_binary instruction.
-%%
-
-btb_reaches_match(Is, RegList, D) ->
- try
- Regs = btb_regs_from_list(RegList),
- #btb{must_not_save=MustNotSave,must_save=MustSave} =
- btb_reaches_match_1(Is, Regs, D),
- case MustNotSave andalso MustSave of
- true -> btb_error(must_and_must_not_save);
- false -> {ok,MustSave}
- end
- catch
- throw:{error,_}=Error -> Error
- end.
-
-btb_reaches_match_1(Is, Regs, D) ->
- case btb_are_registers_empty(Regs) of
- false ->
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% The context was killed, which is OK.
- D
- end.
-
-btb_reaches_match_2([{block,Bl}|Is], Regs0, D) ->
- Regs = btb_reaches_match_block(Bl, Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{call,Arity,{f,Lbl}}|Is], Regs0, D) ->
- case is_tail_call(Is) of
- true ->
- Regs1 = btb_kill_not_live(Arity, Regs0),
- Regs = btb_kill_yregs(Regs1),
- btb_tail_call(Lbl, Regs, D);
- false ->
- btb_call(Arity, Lbl, Regs0, Is, D)
- end;
-btb_reaches_match_2([{apply,Arity}|Is], Regs, D) ->
- btb_call(Arity+2, apply, Regs, Is, D);
-btb_reaches_match_2([{call_fun,Live}=I|Is], Regs, D) ->
- btb_ensure_not_used([{x,Live}], I, Regs),
- btb_call(Live, I, Regs, Is, D);
-btb_reaches_match_2([{make_fun2,_,_,_,Live}|Is], Regs, D) ->
- btb_call(Live, make_fun2, Regs, Is, D);
-btb_reaches_match_2([{call_ext,Arity,Func}=I|Is], Regs0, D) ->
- %% Allow us scanning beyond the call in case the match
- %% context is saved on the stack.
- case beam_jump:is_exit_instruction(I) of
- false ->
- btb_call(Arity, Func, Regs0, Is, D);
- true ->
- Regs = btb_kill_not_live(Arity, Regs0),
- btb_tail_call(Func, Regs, D)
- end;
-btb_reaches_match_2([{kill,Y}|Is], Regs, D) ->
- btb_reaches_match_1(Is, btb_kill([Y], Regs), D);
-btb_reaches_match_2([{deallocate,_}|Is], Regs0, D) ->
- Regs = btb_kill_yregs(Regs0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([return=I|_], Regs0, D) ->
- btb_ensure_not_used([{x,0}], I, Regs0),
- D;
-btb_reaches_match_2([{gc_bif,_,{f,F},Live,Ss,Dst}=I|Is], Regs0, D0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs1 = btb_kill_not_live(Live, Regs0),
- Regs = btb_kill([Dst], Regs1),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bif,_,{f,F},Ss,Dst}=I|Is], Regs0, D0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs = btb_kill([Dst], Regs0),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{get_map_elements,{f,F},Src,{list,Ls}}=I|Is], Regs0, D0) ->
- {Ss,Ds} = beam_utils:split_even(Ls),
- btb_ensure_not_used([Src|Ss], I, Regs0),
- Regs = btb_kill(Ds, Regs0),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Ctx,_],Ctx}=I|Is],
- Regs0, D0) ->
- CtxRegs = btb_context_regs(Regs0),
- case member(Ctx, CtxRegs) of
- false ->
- %% This bs_start_match2 instruction does not use "our"
- %% match state. Therefore we can continue the search
- %% for another bs_start_match2 instruction.
- D = btb_follow_branch(F, Regs0, D0),
- Regs = btb_kill_not_live(Live, Regs0),
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% OK. This instruction will use "our" match state,
- %% but we must make sure that all other copies of the
- %% match state are killed in the code that follows
- %% the instruction. (We know that the fail branch cannot
- %% be taken in this case.)
- OtherCtxRegs = CtxRegs -- [Ctx],
- case btb_are_all_unused(OtherCtxRegs, Is, D0) of
- false -> btb_error({OtherCtxRegs,not_all_unused_after,I});
- true -> D0
- end
- end;
-btb_reaches_match_2([{test,bs_start_match2,{f,F},Live,[Bin,_],Ctx}|Is],
- Regs0, D0) ->
- CtxRegs = btb_context_regs(Regs0),
- case member(Bin, CtxRegs) orelse member(Ctx, CtxRegs) of
- false ->
- %% This bs_start_match2 does not reference any copy of the
- %% match state. Therefore it can safely be passed on the
- %% way to another (perhaps more suitable) bs_start_match2
- %% instruction.
- D = btb_follow_branch(F, Regs0, D0),
- Regs = btb_kill_not_live(Live, Regs0),
- btb_reaches_match_2(Is, Regs, D);
- true ->
- %% This variant of the bs_start_match2 instruction does
- %% not accept a match state as source.
- btb_error(unsuitable_bs_start_match)
- end;
-btb_reaches_match_2([{test,_,{f,F},Ss}=I|Is], Regs, D0) ->
- btb_ensure_not_used(Ss, I, Regs),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{test,_,{f,F},_,Ss,_}=I|Is], Regs, D0) ->
- btb_ensure_not_used(Ss, I, Regs),
- D = btb_follow_branch(F, Regs, D0),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{select,_,Src,{f,F},Conds}=I|Is], Regs, D0) ->
- btb_ensure_not_used([Src], I, Regs),
- D1 = btb_follow_branch(F, Regs, D0),
- D = btb_follow_branches(Conds, Regs, D1),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{jump,{f,Lbl}}|_], Regs, #btb{index=Li}=D) ->
- Is = fetch_code_at(Lbl, Li),
- btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{label,_}|Is], Regs, D) ->
- btb_reaches_match_2(Is, Regs, D);
-btb_reaches_match_2([{bs_init,{f,0},_,_,Ss,Dst}=I|Is], Regs, D) ->
- btb_ensure_not_used(Ss, I, Regs),
- btb_reaches_match_1(Is, btb_kill([Dst], Regs), D);
-btb_reaches_match_2([{bs_put,{f,0},_,Ss}=I|Is], Regs, D) ->
- btb_ensure_not_used(Ss, I, Regs),
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([{bs_restore2,Src,_}=I|Is], Regs0, D) ->
- case btb_contains_context(Src, Regs0) of
- false ->
- btb_reaches_match_1(Is, Regs0, D);
- true ->
- %% Check that all other copies of the context registers
- %% are unused by the following instructions.
- Regs = btb_kill([Src], Regs0),
- CtxRegs = btb_context_regs(Regs),
- case btb_are_all_unused(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_unused_after,I});
- true -> D#btb{must_not_save=true}
- end
- end;
-btb_reaches_match_2([{bs_context_to_binary,Src}=I|Is], Regs0, D) ->
- case btb_contains_context(Src, Regs0) of
- false ->
- btb_reaches_match_1(Is, Regs0, D);
- true ->
- %% Check that all other copies of the context registers
- %% are unused by the following instructions.
- Regs = btb_kill([Src], Regs0),
- CtxRegs = btb_context_regs(Regs),
- case btb_are_all_unused(CtxRegs, Is, D) of
- false -> btb_error({CtxRegs,not_all_unused_after,I});
- true -> D#btb{must_not_save=true}
- end
- end;
-btb_reaches_match_2([{badmatch,Src}=I|_], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- D;
-btb_reaches_match_2([{case_end,Src}=I|_], Regs, D) ->
- btb_ensure_not_used([Src], I, Regs),
- D;
-btb_reaches_match_2([if_end|_], _Regs, D) ->
- D;
-btb_reaches_match_2([{func_info,_,_,Arity}=I|_], Regs0, D) ->
- Regs = btb_kill_yregs(btb_kill_not_live(Arity, Regs0)),
- case btb_context_regs(Regs) of
- [] -> D;
- _ -> {binary_used_in,I}
- end;
-btb_reaches_match_2([{line,_}|Is], Regs, D) ->
- btb_reaches_match_1(Is, Regs, D);
-btb_reaches_match_2([I|_], Regs, _) ->
- btb_error({btb_context_regs(Regs),I,not_handled}).
-
-is_tail_call([{deallocate,_}|_]) -> true;
-is_tail_call([return|_]) -> true;
-is_tail_call(_) -> false.
-
-btb_call(Arity, Lbl, Regs0, Is, D0) ->
- Regs = btb_kill_not_live(Arity, Regs0),
- case btb_are_x_registers_empty(Regs) of
- false ->
- %% There is a match context in one of the x registers.
- %% First handle the call as if it were a tail call.
- D = btb_tail_call(Lbl, Regs, D0),
-
- %% No problem so far (the called function can handle a
- %% match context). Now we must make sure that we don't
- %% have any copies of the match context tucked away in an
- %% y register.
- RegList = btb_context_regs(Regs),
- case [R || {y,_}=R <- RegList] of
- [] ->
- D;
- [_|_] ->
- btb_error({multiple_uses,RegList})
- end;
- true ->
- %% No match context in any x register. It could have been
- %% saved to an y register, so continue to scan the code following
- %% the call.
- btb_reaches_match_1(Is, Regs, D0)
- end.
-
-btb_tail_call(Lbl, Regs, #btb{f=Ftree,must_save=MustSave0}=D) ->
- %% Ignore any y registers here.
- case [R || {x,_}=R <- btb_context_regs(Regs)] of
- [] ->
- D;
- [{x,_}=Reg] ->
- case gb_trees:lookup(Lbl, Ftree) of
- {value,{Reg,MustSave}} ->
- D#btb{must_save=MustSave0 or MustSave};
- _ when is_integer(Lbl) ->
- btb_error({{label,Lbl},no_suitable_bs_start_match});
- _ ->
- btb_error({binary_used_in,Lbl})
- end;
- [_|_] when not is_integer(Lbl) ->
- btb_error({binary_used_in,Lbl});
- [_|_]=RegList ->
- btb_error({multiple_uses,RegList})
- end.
-
-%% btb_follow_branches([Cond], Regs, D) -> D'
-%% Recursively follow all the branches.
-
-btb_follow_branches([{f,Lbl}|T], Regs, D0) ->
- D = btb_follow_branch(Lbl, Regs, D0),
- btb_follow_branches(T, Regs, D);
-btb_follow_branches([_|T], Regs, D) ->
- btb_follow_branches(T, Regs, D);
-btb_follow_branches([], _, D) -> D.
-
-%% btb_follow_branch(Lbl, Regs, D) -> D'
-%% Recursively follow the branch.
-
-btb_follow_branch(0, _Regs, D) -> D;
-btb_follow_branch(Lbl, Regs, #btb{ok_br=Br0,index=Li}=D) ->
- Key = {Lbl,Regs},
- case gb_sets:is_member(Key, Br0) of
- true ->
- %% We have already followed this branch and it was OK.
- D;
- false ->
- %% New branch. Try it.
- Is = fetch_code_at(Lbl, Li),
- #btb{ok_br=Br,must_not_save=MustNotSave,must_save=MustSave} =
- btb_reaches_match_1(Is, Regs, D),
-
- %% Since we got back, this branch is OK.
- D#btb{ok_br=gb_sets:insert(Key, Br),must_not_save=MustNotSave,
- must_save=MustSave}
- end.
-
-btb_reaches_match_block([{set,Ds,Ss,{alloc,Live,_}}=I|Is], Regs0) ->
- %% An allocation instruction or a GC bif. We'll kill all registers
- %% if any copy of the context is used as the source to the BIF.
- btb_ensure_not_used(Ss, I, Regs0),
- Regs1 = btb_kill_not_live(Live, Regs0),
- Regs = btb_kill(Ds, Regs1),
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([{set,[Dst]=Ds,[Src],move}|Is], Regs0) ->
- Regs1 = btb_kill(Ds, Regs0),
- Regs = case btb_contains_context(Src, Regs1) of
- false -> Regs1;
- true -> btb_set_context(Dst, Regs1)
- end,
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([{set,Ds,Ss,_}=I|Is], Regs0) ->
- btb_ensure_not_used(Ss, I, Regs0),
- Regs = btb_kill(Ds, Regs0),
- btb_reaches_match_block(Is, Regs);
-btb_reaches_match_block([], Regs) ->
- Regs.
-
-%% btb_are_all_killed([Register], [Instruction], D) -> true|false
-%% Test whether all of the register are unused in the instruction stream.
-
-btb_are_all_unused(RegList, Is, #btb{index=Li}) ->
- all(fun(R) ->
- beam_utils:is_not_used(R, Is, Li)
- end, RegList).
-
-%% btp_regs_from_list([Register]) -> RegisterSet.
-%% Create a register set from a list of registers.
-
-btb_regs_from_list(L) ->
- foldl(fun(R, Regs) ->
- btb_set_context(R, Regs)
- end, {0,0}, L).
-
-%% btb_set_context(Register, RegisterSet) -> RegisterSet'
-%% Update RegisterSet to indicate that Register contains the matching context.
-
-btb_set_context({x,N}, {Xregs,Yregs}) ->
- {Xregs bor (1 bsl N),Yregs};
-btb_set_context({y,N}, {Xregs,Yregs}) ->
- {Xregs,Yregs bor (1 bsl N)}.
-
-%% btb_ensure_not_used([Register], Instruction, RegisterSet) -> ok
-%% If any register in RegisterSet (the register(s) known to contain
-%% the match context) is used in the list of registers, generate an error.
-
-btb_ensure_not_used(Rs, I, Regs) ->
- case lists:any(fun(R) -> btb_contains_context(R, Regs) end, Rs) of
- true -> btb_error({binary_used_in,I});
- false -> ok
- end.
-
-%% btb_kill([Register], RegisterSet) -> RegisterSet'
-%% Kill all registers mentioned in the list of registers.
-
-btb_kill([{x,N}|Rs], {Xregs,Yregs}) ->
- btb_kill(Rs, {Xregs band (bnot (1 bsl N)),Yregs});
-btb_kill([{y,N}|Rs], {Xregs,Yregs}) ->
- btb_kill(Rs, {Xregs,Yregs band (bnot (1 bsl N))});
-btb_kill([{fr,_}|Rs], Regs) ->
- btb_kill(Rs, Regs);
-btb_kill([], Regs) -> Regs.
-
-%% btb_kill_not_live(Live, RegisterSet) -> RegisterSet'
-%% Kill all registers indicated not live by Live.
-
-btb_kill_not_live(Live, {Xregs,Yregs}) ->
- {Xregs band ((1 bsl Live)-1),Yregs}.
-
-%% btb_kill(Regs0) -> Regs
-%% Kill all y registers.
-
-btb_kill_yregs({Xregs,_}) -> {Xregs,0}.
-
-%% btb_are_registers_empty(RegisterSet) -> true|false
-%% Test whether the register set is empty.
-
-btb_are_registers_empty({0,0}) -> true;
-btb_are_registers_empty({_,_}) -> false.
-
-%% btb_are_x_registers_empty(Regs) -> true|false
-%% Test whether the x registers are empty.
-
-btb_are_x_registers_empty({0,_}) -> true;
-btb_are_x_registers_empty({_,_}) -> false.
-
-%% btb_contains_context(Register, RegisterSet) -> true|false
-%% Test whether Register contains the context.
-
-btb_contains_context({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
-btb_contains_context({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
-btb_contains_context(_, _) -> false.
-
-%% btb_context_regs(RegisterSet) -> [Register]
-%% Convert the register set to an explicit list of registers.
-btb_context_regs({Xregs,Yregs}) ->
- btb_context_regs_1(Xregs, 0, x, btb_context_regs_1(Yregs, 0, y, [])).
-
-btb_context_regs_1(0, _, _, Acc) ->
- Acc;
-btb_context_regs_1(Regs, N, Tag, Acc) when (Regs band 1) =:= 1 ->
- btb_context_regs_1(Regs bsr 1, N+1, Tag, [{Tag,N}|Acc]);
-btb_context_regs_1(Regs, N, Tag, Acc) ->
- btb_context_regs_1(Regs bsr 1, N+1, Tag, Acc).
-
-%% btb_index([Function]) -> GbTree({EntryLabel,{Register,MustSave}})
-%% Build an index of functions that accept a match context instead of
-%% a binary. MustSave is true if the function may pass the match
-%% context to the bs_context_to_binary instruction (in which case
-%% the current position in the binary must have saved into the
-%% start position using "bs_save_2 Ctx start").
-
-btb_index(Fs) ->
- btb_index_1(Fs, []).
-
-btb_index_1([{function,_,_,Entry,Is0}|Fs], Acc0) ->
- Is = drop_to_label(Is0, Entry),
- Acc = btb_index_2(Is, Entry, false, Acc0),
- btb_index_1(Fs, Acc);
-btb_index_1([], Acc) -> gb_trees:from_orddict(sort(Acc)).
-
-btb_index_2([{test,bs_start_match2,{f,_},_,[Reg,_],Reg}|_],
- Entry, MustSave, Acc) ->
- [{Entry,{Reg,MustSave}}|Acc];
-btb_index_2(Is0, Entry, _, Acc) ->
- try btb_index_find_start_match(Is0) of
- Is -> btb_index_2(Is, Entry, true, Acc)
- catch
- throw:none -> Acc
- end.
-
-drop_to_label([{label,L}|Is], L) -> Is;
-drop_to_label([_|Is], L) -> drop_to_label(Is, L).
-
-btb_index_find_start_match([{test,_,{f,F},_},{bs_context_to_binary,_}|Is]) ->
- btb_index_find_label(Is, F);
-btb_index_find_start_match(_) ->
- throw(none).
-
-btb_index_find_label([{label,L}|Is], L) -> Is;
-btb_index_find_label([_|Is], L) -> btb_index_find_label(Is, L).
-
-btb_error(Error) ->
- throw({error,Error}).
-
-fetch_code_at(Lbl, Li) ->
- case beam_utils:code_at(Lbl, Li) of
- Is when is_list(Is) -> Is
- end.
-
-%%%
-%%% Compilation information warnings.
-%%%
-
-btb_comment_opt({field_flags,[{anno,A}|_]}) ->
- {'%',{bin_opt,A}};
-btb_comment_opt(_) ->
- {'%',{bin_opt,[]}}.
-
-btb_comment_no_opt(Reason, {field_flags,[{anno,A}|_]}) ->
- {'%',{no_bin_opt,Reason,A}};
-btb_comment_no_opt(Reason, _) ->
- {'%',{no_bin_opt,Reason,[]}}.
-
-collect_warnings(Fs) ->
- D = warning_index_functions(Fs),
- foldl(fun(F, A) -> collect_warnings_fun(F, D, A) end, [], Fs).
-
-collect_warnings_fun({function,_,_,_,Is}, D, A) ->
- collect_warnings_instr(Is, D, A).
-
-collect_warnings_instr([{'%',{bin_opt,Where}}|Is], D, Acc0) ->
- Acc = add_warning(bin_opt, Where, Acc0),
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([{'%',{no_bin_opt,Reason0,Where}}|Is], D, Acc0) ->
- Reason = warning_translate_label(Reason0, D),
- Acc = add_warning({no_bin_opt,Reason}, Where, Acc0),
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([_|Is], D, Acc) ->
- collect_warnings_instr(Is, D, Acc);
-collect_warnings_instr([], _, Acc) -> Acc.
-
-add_warning(Term, Anno, Ws) ->
- Line = get_line(Anno),
- File = get_file(Anno),
- [{File,[{Line,?MODULE,Term}]}|Ws].
-
-warning_translate_label(Term, D) when is_tuple(Term) ->
- case element(1, Term) of
- {label,F} ->
- FA = gb_trees:get(F, D),
- setelement(1, Term, FA);
- _ -> Term
- end;
-warning_translate_label(Term, _) -> Term.
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|T]) -> get_line(T);
-get_line([]) -> none.
-
-get_file([{file,File}|_]) -> File;
-get_file([_|T]) -> get_file(T);
-get_file([]) -> "no_file". % should not happen
-
-warning_index_functions(Fs) ->
- D = [{Entry,{F,A}} || {function,F,A,Entry,_} <- Fs],
- gb_trees:from_orddict(sort(D)).
-
-format_error_1({binary_used_in,{extfunc,M,F,A}}) ->
- [io_lib:format("sub binary used by ~p:~p/~p", [M,F,A])|
- case {M,F,A} of
- {erlang,split_binary,2} ->
- "; SUGGEST using binary matching instead of split_binary/2";
- _ ->
- ""
- end];
-format_error_1({binary_used_in,_}) ->
- "sub binary is used or returned";
-format_error_1({multiple_uses,_}) ->
- "sub binary is matched or used in more than one place";
-format_error_1(unsuitable_bs_start_match) ->
- "the binary matching instruction that follows in the same function "
- "have problems that prevent delayed sub binary optimization "
- "(probably indicated by INFO warnings)";
-format_error_1({{F,A},no_suitable_bs_start_match}) ->
- io_lib:format("called function ~p/~p does not begin with a suitable "
- "binary matching instruction", [F,A]);
-format_error_1(must_and_must_not_save) ->
- "different control paths use different positions in the binary";
-format_error_1({_,I,not_handled}) ->
- case I of
- {'catch',_,_} ->
- "the compiler currently does not attempt the delayed sub binary "
- "optimization when catch is used";
- {'try',_,_} ->
- "the compiler currently does not attempt the delayed sub binary "
- "optimization when try/catch is used";
- _ ->
- io_lib:format("compiler limitation: instruction ~p prevents "
- "delayed sub binary optimization", [I])
- end;
-format_error_1(Term) ->
- io_lib:format("~w", [Term]).
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index 207f1c4deb..7299654476 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -22,34 +22,21 @@
-module(beam_clean).
-export([module/2]).
--export([bs_clean_saves/1]).
-export([clean_labels/1]).
--import(lists, [foldl/3,reverse/1]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
module({Mod,Exp,Attr,Fs0,_}, Opts) ->
Order = [Lbl || {function,_,_,Lbl,_} <- Fs0],
- All = foldl(fun({function,_,_,Lbl,_}=Func,D) -> dict:store(Lbl, Func, D) end,
- dict:new(), Fs0),
+ All = maps:from_list([{Lbl,Func} || {function,_,_,Lbl,_}=Func <- Fs0]),
WorkList = rootset(Fs0, Exp, Attr),
- Used = find_all_used(WorkList, All, sets:from_list(WorkList)),
+ Used = find_all_used(WorkList, All, cerl_sets:from_list(WorkList)),
Fs1 = remove_unused(Order, Used, All),
{Fs2,Lc} = clean_labels(Fs1),
- Fs3 = bs_fix(Fs2),
- Fs = maybe_remove_lines(Fs3, Opts),
+ Fs = maybe_remove_lines(Fs2, Opts),
{ok,{Mod,Exp,Attr,Fs,Lc}}.
-%% Remove all bs_save2/2 instructions not referenced by a bs_restore2/2.
-
--spec bs_clean_saves([beam_utils:instruction()]) ->
- [beam_utils:instruction()].
-
-bs_clean_saves(Is) ->
- Needed = bs_restores(Is, []),
- bs_clean_saves_1(Is, gb_sets:from_list(Needed), []).
-
%% Determine the rootset, i.e. exported functions and
%% the on_load function (if any).
@@ -66,16 +53,16 @@ rootset(Fs, Root0, Attr) ->
%% Remove the unused functions.
remove_unused([F|Fs], Used, All) ->
- case sets:is_element(F, Used) of
+ case cerl_sets:is_element(F, Used) of
false -> remove_unused(Fs, Used, All);
- true -> [dict:fetch(F, All)|remove_unused(Fs, Used, All)]
+ true -> [map_get(F, All)|remove_unused(Fs, Used, All)]
end;
remove_unused([], _, _) -> [].
-
+
%% Find all used functions.
find_all_used([F|Fs0], All, Used0) ->
- {function,_,_,_,Code} = dict:fetch(F, All),
+ {function,_,_,_,Code} = map_get(F, All),
{Fs,Used} = update_work_list(Code, {Fs0,Used0}),
find_all_used(Fs, All, Used);
find_all_used([], _All, Used) -> Used.
@@ -89,20 +76,16 @@ update_work_list([_|Is], Sets) ->
update_work_list([], Sets) -> Sets.
add_to_work_list(F, {Fs,Used}=Sets) ->
- case sets:is_element(F, Used) of
+ case cerl_sets:is_element(F, Used) of
true -> Sets;
- false -> {[F|Fs],sets:add_element(F, Used)}
+ false -> {[F|Fs],cerl_sets:add_element(F, Used)}
end.
%%%
%%% Coalesce adjacent labels. Renumber all labels to eliminate gaps.
-%%% This cleanup will slightly reduce file size and slightly speed up loading.
-%%%
-%%% We also expand is_record/3 to a sequence of instructions. It is done
-%%% here merely because this module will always be called even if optimization
-%%% is turned off. We don't want to do the expansion in beam_asm because we
-%%% want to see the expanded code in a .S file.
+%%% This cleanup will slightly reduce file size and slightly speed up
+%%% loading.
%%%
-type label() :: beam_asm:label().
@@ -127,45 +110,6 @@ function_renumber([{function,Name,Arity,_Entry,Asm0}|Fs], St0, Acc) ->
function_renumber(Fs, St, [{function,Name,Arity,St#st.entry,Asm}|Acc]);
function_renumber([], St, Acc) -> {Acc,St}.
-renumber_labels([{bif,is_record,{f,_},
- [Term,{atom,Tag}=TagAtom,{integer,Arity}],Dst}|Is0], Acc, St) ->
- ContLabel = 900000000+2*St#st.lc,
- FailLabel = ContLabel+1,
- Fail = {f,FailLabel},
- Tmp = Dst,
- Is = case is_record_tuple(Term, Tag, Arity) of
- yes ->
- [{move,{atom,true},Dst}|Is0];
- no ->
- [{move,{atom,false},Dst}|Is0];
- maybe ->
- [{test,is_tuple,Fail,[Term]},
- {test,test_arity,Fail,[Term,Arity]},
- {get_tuple_element,Term,0,Tmp},
- {test,is_eq_exact,Fail,[Tmp,TagAtom]},
- {move,{atom,true},Dst},
- {jump,{f,ContLabel}},
- {label,FailLabel},
- {move,{atom,false},Dst},
- {jump,{f,ContLabel}}, %Improves optimization by beam_dead.
- {label,ContLabel}|Is0]
- end,
- renumber_labels(Is, Acc, St);
-renumber_labels([{test,is_record,{f,_}=Fail,
- [Term,{atom,Tag}=TagAtom,{integer,Arity}]}|Is0], Acc, St) ->
- Tmp = {x,1022},
- Is = case is_record_tuple(Term, Tag, Arity) of
- yes ->
- Is0;
- no ->
- [{jump,Fail}|Is0];
- maybe ->
- [{test,is_tuple,Fail,[Term]},
- {test,test_arity,Fail,[Term,Arity]},
- {get_tuple_element,Term,0,Tmp},
- {test,is_eq_exact,Fail,[Tmp,TagAtom]}|Is0]
- end,
- renumber_labels(Is, Acc, St);
renumber_labels([{label,Old}|Is], [{label,New}|_]=Acc, #st{lmap=D0}=St) ->
D = [{Old,New}|D0],
renumber_labels(Is, Acc, St#st{lmap=D});
@@ -179,12 +123,6 @@ renumber_labels([I|Is], Acc, St0) ->
renumber_labels(Is, [I|Acc], St0);
renumber_labels([], Acc, St) -> {Acc,St}.
-is_record_tuple({x,_}, _, _) -> maybe;
-is_record_tuple({y,_}, _, _) -> maybe;
-is_record_tuple({literal,Tuple}, Tag, Arity)
- when element(1, Tuple) =:= Tag, tuple_size(Tuple) =:= Arity -> yes;
-is_record_tuple(_, _, _) -> no.
-
function_replace([{function,Name,Arity,Entry,Asm0}|Fs], Dict, Acc) ->
Asm = try
Fb = fun(Old) -> throw({error,{undefined_label,Old}}) end,
@@ -199,100 +137,6 @@ function_replace([{function,Name,Arity,Entry,Asm0}|Fs], Dict, Acc) ->
function_replace([], _, Acc) -> Acc.
%%%
-%%% Final fixup of bs_start_match2/5,bs_save2/bs_restore2 instructions for
-%%% new bit syntax matching (introduced in R11B).
-%%%
-%%% Pass 1: Scan the code, looking for bs_restore2/2 instructions.
-%%%
-%%% Pass 2: Update bs_save2/2 and bs_restore/2 instructions. Remove
-%%% any bs_save2/2 instruction whose save position are never referenced
-%%% by any bs_restore2/2 instruction.
-%%%
-%%% Note this module can be invoked several times, so we must be careful
-%%% not to touch instructions that have already been fixed up.
-%%%
-
-bs_fix(Fs) ->
- bs_fix(Fs, []).
-
-bs_fix([{function,Name,Arity,Entry,Asm0}|Fs], Acc) ->
- Asm = bs_function(Asm0),
- bs_fix(Fs, [{function,Name,Arity,Entry,Asm}|Acc]);
-bs_fix([], Acc) -> reverse(Acc).
-
-bs_function(Is) ->
- Dict0 = bs_restores(Is, []),
- S0 = sofs:relation(Dict0, [{context,save_point}]),
- S1 = sofs:relation_to_family(S0),
- S = sofs:to_external(S1),
- Dict = make_save_point_dict(S, []),
- bs_replace(Is, Dict, []).
-
-make_save_point_dict([{Ctx,Pts}|T], Acc0) ->
- Acc = make_save_point_dict_1(Pts, Ctx, 0, Acc0),
- make_save_point_dict(T, Acc);
-make_save_point_dict([], Acc) ->
- gb_trees:from_orddict(ordsets:from_list(Acc)).
-
-make_save_point_dict_1([H|T], Ctx, I, Acc) ->
- make_save_point_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
-make_save_point_dict_1([], Ctx, I, Acc) ->
- [{Ctx,I}|Acc].
-
-%% Pass 1.
-bs_restores([{bs_restore2,_,{Same,Same}}|Is], Dict) ->
- %% This save point is special. No explicit save is needed.
- bs_restores(Is, Dict);
-bs_restores([{bs_restore2,_,{atom,start}}|Is], Dict) ->
- %% This instruction can occur if "compilation"
- %% started from a .S file.
- bs_restores(Is, Dict);
-bs_restores([{bs_restore2,_,{_,_}=SavePoint}|Is], Dict) ->
- bs_restores(Is, [SavePoint|Dict]);
-bs_restores([_|Is], Dict) ->
- bs_restores(Is, Dict);
-bs_restores([], Dict) -> Dict.
-
-%% Pass 2.
-bs_replace([{test,bs_start_match2,F,Live,[Src,{context,Ctx}],CtxR}|T], Dict, Acc) ->
- Slots = case gb_trees:lookup(Ctx, Dict) of
- {value,Slots0} -> Slots0;
- none -> 0
- end,
- I = {test,bs_start_match2,F,Live,[Src,Slots],CtxR},
- bs_replace(T, Dict, [I|Acc]);
-bs_replace([{bs_save2,CtxR,{_,_}=SavePoint}|T], Dict, Acc) ->
- case gb_trees:lookup(SavePoint, Dict) of
- {value,N} ->
- bs_replace(T, Dict, [{bs_save2,CtxR,N}|Acc]);
- none ->
- bs_replace(T, Dict, Acc)
- end;
-bs_replace([{bs_restore2,_,{atom,start}}=I|T], Dict, Acc) ->
- %% This instruction can occur if "compilation"
- %% started from a .S file.
- bs_replace(T, Dict, [I|Acc]);
-bs_replace([{bs_restore2,CtxR,{Same,Same}}|T], Dict, Acc) ->
- %% This save point refers to the point in the binary where the match
- %% started. It has a special name.
- bs_replace(T, Dict, [{bs_restore2,CtxR,{atom,start}}|Acc]);
-bs_replace([{bs_restore2,CtxR,{_,_}=SavePoint}|T], Dict, Acc) ->
- N = gb_trees:get(SavePoint, Dict),
- bs_replace(T, Dict, [{bs_restore2,CtxR,N}|Acc]);
-bs_replace([I|Is], Dict, Acc) ->
- bs_replace(Is, Dict, [I|Acc]);
-bs_replace([], _, Acc) -> reverse(Acc).
-
-bs_clean_saves_1([{bs_save2,_,{_,_}=SavePoint}=I|Is], Needed, Acc) ->
- case gb_sets:is_member(SavePoint, Needed) of
- false -> bs_clean_saves_1(Is, Needed, Acc);
- true -> bs_clean_saves_1(Is, Needed, [I|Acc])
- end;
-bs_clean_saves_1([I|Is], Needed, Acc) ->
- bs_clean_saves_1(Is, Needed, [I|Acc]);
-bs_clean_saves_1([], _, Acc) -> reverse(Acc).
-
-%%%
%%% Remove line instructions if requested.
%%%
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
deleted file mode 100644
index efad082152..0000000000
--- a/lib/compiler/src/beam_dead.erl
+++ /dev/null
@@ -1,971 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_dead).
-
--export([module/2]).
-
-%%% Dead code is code that is executed but has no effect. This
-%%% optimization pass either removes dead code or jumps around it,
-%%% potentially making it unreachable and a target for the
-%%% the beam_jump pass.
-
--import(lists, [mapfoldl/3,reverse/1]).
-
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,_}, _Opts) ->
- {Fs1,Lc1} = beam_clean:clean_labels(Fs0),
- {Fs,Lc} = mapfoldl(fun function/2, Lc1, Fs1),
- %%{Fs,Lc} = {Fs1,Lc1},
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}, Lc0) ->
- try
- Is1 = beam_jump:remove_unused_labels(Is0),
-
- %% Initialize label information with the code
- %% for the func_info label. Without it, a register
- %% may seem to be live when it is not.
- [{label,L}|FiIs] = Is1,
- D0 = beam_utils:empty_label_index(),
- D = beam_utils:index_label(L, FiIs, D0),
-
- %% Optimize away dead code.
- {Is2,Lc} = forward(Is1, Lc0),
- Is3 = backward(Is2, D),
- Is = move_move_into_block(Is3, []),
- {{function,Name,Arity,CLabel,Is},Lc}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% 'move' instructions outside of blocks may thwart the jump optimizer.
-%% Move them back into the block.
-
-move_move_into_block([{block,Bl0},{move,S,D}|Is], Acc) ->
- Bl = Bl0 ++ [{set,[D],[S],move}],
- move_move_into_block([{block,Bl}|Is], Acc);
-move_move_into_block([{move,S,D}|Is], Acc) ->
- Bl = [{set,[D],[S],move}],
- move_move_into_block([{block,Bl}|Is], Acc);
-move_move_into_block([I|Is], Acc) ->
- move_move_into_block(Is, [I|Acc]);
-move_move_into_block([], Acc) -> reverse(Acc).
-
-%%%
-%%% Scan instructions in execution order and remove redundant 'move'
-%%% instructions. 'move' instructions are redundant if we know that
-%%% the register already contains the value being assigned, as in the
-%%% following code:
-%%%
-%%% test is_eq_exact SomeLabel Src Dst
-%%% move Src Dst
-%%%
-%%% or in:
-%%%
-%%% test is_nil SomeLabel Dst
-%%% move nil Dst
-%%%
-%%% or in:
-%%%
-%%% select_val Register FailLabel [... Literal => L1...]
-%%% .
-%%% .
-%%% .
-%%% L1: move Literal Register
-%%%
-%%% Also add extra labels to help the second backward pass.
-%%%
-
-forward(Is, Lc) ->
- forward(Is, #{}, Lc, []).
-
-forward([{move,_,_}=Move|[{label,L}|_]=Is], D, Lc, Acc) ->
- %% move/2 followed by jump/1 is optimized by backward/3.
- forward([Move,{jump,{f,L}}|Is], D, Lc, Acc);
-forward([{bif,_,_,_,_}=Bif|[{label,L}|_]=Is], D, Lc, Acc) ->
- %% bif/4 followed by jump/1 is optimized by backward/3.
- forward([Bif,{jump,{f,L}}|Is], D, Lc, Acc);
-forward([{block,[]}|Is], D, Lc, Acc) ->
- %% Empty blocks can prevent optimizations.
- forward(Is, D, Lc, Acc);
-forward([{select,select_val,Reg,_,List}=I|Is], D0, Lc, Acc) ->
- D = update_value_dict(List, Reg, D0),
- forward(Is, D, Lc, [I|Acc]);
-forward([{label,Lbl}=LblI,{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk|Is], D, Lc, Acc) ->
- %% Assumption: The target labels in a select_val/3 instruction
- %% cannot be reached in any other way than through the select_val/3
- %% instruction (i.e. there can be no fallthrough to such label and
- %% it cannot be referenced by, for example, a jump/1 instruction).
- Key = {Lbl,Dst},
- Block = case D of
- #{Key := Lit} -> {block,BlkIs}; %Safe to remove move instruction.
- _ -> Blk %Must keep move instruction.
- end,
- forward([Block|Is], D, Lc, [LblI|Acc]);
-forward([{label,Lbl}=LblI|[{move,Lit,Dst}|Is1]=Is0], D, Lc, Acc) ->
- %% Assumption: The target labels in a select_val/3 instruction
- %% cannot be reached in any other way than through the select_val/3
- %% instruction (i.e. there can be no fallthrough to such label and
- %% it cannot be referenced by, for example, a jump/1 instruction).
- Is = case maps:find({Lbl,Dst}, D) of
- {ok,Lit} -> Is1; %Safe to remove move instruction.
- _ -> Is0 %Keep move instruction.
- end,
- forward(Is, D, Lc, [LblI|Acc]);
-forward([{test,is_eq_exact,_,[Same,Same]}|Is], D, Lc, Acc) ->
- forward(Is, D, Lc, Acc);
-forward([{test,is_eq_exact,_,[Dst,Src]}=I,
- {block,[{set,[Dst],[Src],move}|Bl]}|Is], D, Lc, Acc) ->
- forward([I,{block,Bl}|Is], D, Lc, Acc);
-forward([{test,is_nil,_,[Dst]}=I,
- {block,[{set,[Dst],[nil],move}|Bl]}|Is], D, Lc, Acc) ->
- forward([I,{block,Bl}|Is], D, Lc, Acc);
-forward([{test,is_eq_exact,_,[Dst,Src]}=I,{move,Src,Dst}|Is], D, Lc, Acc) ->
- forward([I|Is], D, Lc, Acc);
-forward([{test,is_nil,_,[Dst]}=I,{move,nil,Dst}|Is], D, Lc, Acc) ->
- forward([I|Is], D, Lc, Acc);
-forward([{test,_,_,_}=I|Is]=Is0, D, Lc, Acc) ->
- %% Help the second, backward pass to by inserting labels after
- %% relational operators so that they can be skipped if they are
- %% known to be true.
- case useful_to_insert_label(Is0) of
- false -> forward(Is, D, Lc, [I|Acc]);
- true -> forward(Is, D, Lc+1, [{label,Lc},I|Acc])
- end;
-forward([I|Is], D, Lc, Acc) ->
- forward(Is, D, Lc, [I|Acc]);
-forward([], _, Lc, Acc) -> {Acc,Lc}.
-
-update_value_dict([Lit,{f,Lbl}|T], Reg, D0) ->
- Key = {Lbl,Reg},
- D = case D0 of
- #{Key := inconsistent} -> D0;
- #{Key := _} -> D0#{Key := inconsistent};
- _ -> D0#{Key => Lit}
- end,
- update_value_dict(T, Reg, D);
-update_value_dict([], _, D) -> D.
-
-useful_to_insert_label([_,{label,_}|_]) ->
- false;
-useful_to_insert_label([{test,Op,_,_}|_]) ->
- case Op of
- is_lt -> true;
- is_ge -> true;
- is_eq_exact -> true;
- is_ne_exact -> true;
- _ -> false
- end.
-
-%%%
-%%% Scan instructions in reverse execution order and try to
-%%% shortcut branch instructions.
-%%%
-%%% For example, in this code:
-%%%
-%%% move Literal Register
-%%% jump L1
-%%% .
-%%% .
-%%% .
-%%% L1: test is_{integer,atom} FailLabel Register
-%%% select_val {x,0} FailLabel [... Literal => L2...]
-%%% .
-%%% .
-%%% .
-%%% L2: ...
-%%%
-%%% the 'selectval' instruction will always transfer control to L2,
-%%% so we can just as well jump to L2 directly by rewriting the
-%%% first part of the sequence like this:
-%%%
-%%% move Literal Register
-%%% jump L2
-%%%
-%%% If register Register is killed at label L2, we can remove the
-%%% 'move' instruction, leaving just the 'jump' instruction:
-%%%
-%%% jump L2
-%%%
-%%% These transformations may leave parts of the code unreachable.
-%%% The beam_jump pass will remove the unreachable code.
-
-backward(Is, D) ->
- backward(Is, D, []).
-
-backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
- [{bif,tuple_size,Fail,[Reg],Dst}|Is]=Is0], D, Acc) ->
- %% Provided that Dst is killed following this sequence,
- %% we can rewrite the instructions like this:
- %%
- %% bif tuple_size Fail Reg Dst ==> is_tuple Fail Reg
- %% is_eq_exact Fail Dst Integer test_arity Fail Reg Integer
- %%
- %% (still two instructions, but they they will be combined to
- %% one by the loader).
- case beam_utils:is_killed(Dst, Acc, D) andalso (Arity bsr 32) =:= 0 of
- false ->
- %% Not safe because the register Dst is not killed
- %% (probably cannot not happen in practice) or the arity
- %% does not fit in 32 bits (the loader will fail to load
- %% the module). We must move the first instruction to the
- %% accumulator to avoid an infinite loop.
- backward(Is0, D, [I|Acc]);
- true ->
- %% Safe.
- backward([{test,test_arity,Fail,[Reg,Arity]},
- {test,is_tuple,Fail,[Reg]}|Is], D, Acc)
- end;
-backward([{label,Lbl}=L|Is], D, Acc) ->
- backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
-backward([{select,select_val,Reg,{f,Fail0},List0}|Is], D, Acc) ->
- List1 = shortcut_select_list(List0, Reg, D, []),
- Fail1 = shortcut_label(Fail0, D),
- Fail = shortcut_bs_test(Fail1, Is, D),
- List = prune_redundant(List1, Fail),
- case List of
- [] ->
- Jump = {jump,{f,Fail}},
- backward([Jump|Is], D, Acc);
- [V,F] ->
- Test = {test,is_eq_exact,{f,Fail},[Reg,V]},
- Jump = {jump,F},
- backward([Jump,Test|Is], D, Acc);
- [{atom,B1},F,{atom,B2},F] when B1 =:= not B2 ->
- Test = {test,is_boolean,{f,Fail},[Reg]},
- Jump = {jump,F},
- backward([Jump,Test|Is], D, Acc);
- [_|_] ->
- Sel = {select,select_val,Reg,{f,Fail},List},
- backward(Is, D, [Sel|Acc])
- end;
-backward([{jump,{f,To0}},{move,Src,Reg}=Move|Is], D, Acc) ->
- To = shortcut_select_label(To0, Reg, Src, D),
- Jump = {jump,{f,To}},
- case is_killed_at(Reg, To, D) of
- false -> backward([Move|Is], D, [Jump|Acc]);
- true -> backward([Jump|Is], D, Acc)
- end;
-backward([{jump,{f,To}}=J|[{bif,Op,{f,BifFail},Ops,Reg}|Is]=Is0], D, Acc) ->
- try replace_comp_op(To, Reg, Op, Ops, D) of
- {Test,Jump} ->
- backward([Jump,Test|Is], D, Acc)
- catch
- throw:not_possible ->
- case To =:= BifFail of
- true ->
- %% The bif instruction is redundant. See the comment
- %% in the next clause for why there is no need to
- %% test for liveness of Reg at label To.
- backward([J|Is], D, Acc);
- false ->
- backward(Is0, D, [J|Acc])
- end
- end;
-backward([{jump,{f,To}}=J|[{gc_bif,_,{f,To},_,_,_Dst}|Is]], D, Acc) ->
- %% The gc_bif instruction is redundant, since either the gc_bif
- %% instruction itself or the jump instruction will transfer control
- %% to label To. Note that a gc_bif instruction does not assign its
- %% destination register if the failure branch is taken; therefore,
- %% the code at label To is not allowed to assume that the destination
- %% register is initialized, and it is therefore no need to test
- %% for liveness of the destination register at label To.
- backward([J|Is], D, Acc);
-backward([{test,bs_start_match2,F,Live,[Src,_]=Args,Ctxt}|Is], D, Acc0) ->
- {f,To0} = F,
- case test_bs_literal(F, Ctxt, D, Acc0) of
- {none,Acc} ->
- %% Ctxt killed immediately after bs_start_match2.
- To = shortcut_bs_context_to_binary(To0, Src, D),
- I = {test,is_bitstr,{f,To},[Src]},
- backward(Is, D, [I|Acc]);
- {Literal,Acc} ->
- %% Ctxt killed after matching a literal.
- To = shortcut_bs_context_to_binary(To0, Src, D),
- Eq = {test,is_eq_exact,{f,To},[Src,{literal,Literal}]},
- backward(Is, D, [Eq|Acc]);
- not_killed ->
- %% Ctxt not killed. Not much to do.
- To = shortcut_bs_start_match(To0, Src, D),
- I = {test,bs_start_match2,{f,To},Live,Args,Ctxt},
- backward(Is, D, [I|Acc0])
- end;
-backward([{test,Op,{f,To0},Ops0}|Is], D, Acc) ->
- To1 = shortcut_bs_test(To0, Is, D),
- To2 = shortcut_label(To1, D),
- To3 = shortcut_rel_op(To2, Op, Ops0, D),
-
- %% Try to shortcut a repeated test:
- %%
- %% test Op {f,Fail1} Operands test Op {f,Fail2} Operands
- %% . . . ==> ...
- %% Fail1: test Op {f,Fail2} Operands Fail1: test Op {f,Fail2} Operands
- %%
- To = case beam_utils:code_at(To3, D) of
- [{test,Op,{f,To4},Ops}|_] ->
- case equal_ops(Ops0, Ops) of
- true -> To4;
- false -> To3
- end;
- _Code ->
- To3
- end,
- I = case Op of
- is_eq_exact -> combine_eqs(To, Ops0, D, Acc);
- _ -> {test,Op,{f,To},Ops0}
- end,
- case {I,Acc} of
- {{test,is_atom,Fail,Ops0},[{test,is_boolean,Fail,Ops0}|_]} ->
- %% An is_atom test before an is_boolean test (with the
- %% same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,is_atom,Fail,[R]},
- [{test,is_eq_exact,Fail,[R,{atom,_}]}|_]} ->
- %% An is_atom test before a comparison with an atom (with
- %% the same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,is_integer,Fail,[R]},
- [{test,is_eq_exact,Fail,[R,{integer,_}]}|_]} ->
- %% An is_integer test before a comparison with an integer
- %% (with the same failure label) is redundant.
- backward(Is, D, Acc);
- {{test,_,_,_},_} ->
- %% Still a test instruction. Done.
- backward(Is, D, [I|Acc]);
- {_,_} ->
- %% Rewritten to a select_val. Rescan.
- backward([I|Is], D, Acc)
- end;
-backward([{test,Op,{f,To0},Live,Ops0,Dst}|Is], D, Acc) ->
- To1 = shortcut_bs_test(To0, Is, D),
- To2 = shortcut_label(To1, D),
- %% Try to shortcut a repeated test:
- %%
- %% test Op {f,Fail1} _ Ops _ test Op {f,Fail2} _ Ops _
- %% . . . ==> ...
- %% Fail1: test Op {f,Fail2} _ Ops _ Fail1: test Op {f,Fail2} _ Ops _
- %%
- To = case beam_utils:code_at(To2, D) of
- [{test,Op,{f,To3},_,Ops,_}|_] ->
- case equal_ops(Ops0, Ops) of
- true -> To3;
- false -> To2
- end;
- _Code ->
- To2
- end,
- I = {test,Op,{f,To},Live,Ops0,Dst},
- backward(Is, D, [I|Acc]);
-backward([{kill,_}=I|Is], D, [{line,_},Exit|_]=Acc) ->
- case beam_jump:is_exit_instruction(Exit) of
- false -> backward(Is, D, [I|Acc]);
- true -> backward(Is, D, Acc)
- end;
-backward([{bif,'or',{f,To0},[Dst,{atom,false}],Dst}=I|Is], D,
- [{test,is_eq_exact,{f,To},[Dst,{atom,true}]}|_]=Acc) ->
- case shortcut_label(To0, D) of
- To ->
- backward(Is, D, Acc);
- _ ->
- backward(Is, D, [I|Acc])
- end;
-backward([{bif,map_get,{f,FF},[Key,Map],_}=I0,
- {test,has_map_fields,{f,FT}=F,[Map|Keys0]}=I1|Is], D, Acc) when FF =/= 0 ->
- case shortcut_label(FF, D) of
- FT ->
- case lists:delete(Key, Keys0) of
- [] ->
- backward([I0|Is], D, Acc);
- Keys ->
- Test = {test,has_map_fields,F,[Map|Keys]},
- backward([Test|Is], D, [I0|Acc])
- end;
- _ ->
- backward([I1|Is], D, [I0|Acc])
- end;
-backward([{bif,map_get,{f,FF},[_,Map],_}=I0,
- {test,is_map,{f,FT},[Map]}=I1|Is], D, Acc) when FF =/= 0 ->
- case shortcut_label(FF, D) of
- FT -> backward([I0|Is], D, Acc);
- _ -> backward([I1|Is], D, [I0|Acc])
- end;
-backward([I|Is], D, Acc) ->
- backward(Is, D, [I|Acc]);
-backward([], _D, Acc) -> Acc.
-
-equal_ops([{field_flags,FlA0}|T0], [{field_flags,FlB0}|T1]) ->
- FlA = lists:keydelete(anno, 1, FlA0),
- FlB = lists:keydelete(anno, 1, FlB0),
- FlA =:= FlB andalso equal_ops(T0, T1);
-equal_ops([Op|T0], [Op|T1]) ->
- equal_ops(T0, T1);
-equal_ops([], []) -> true;
-equal_ops(_, _) -> false.
-
-shortcut_select_list([Lit,{f,To0}|T], Reg, D, Acc) ->
- To = shortcut_select_label(To0, Reg, Lit, D),
- shortcut_select_list(T, Reg, D, [{f,To},Lit|Acc]);
-shortcut_select_list([], _, _, Acc) -> reverse(Acc).
-
-shortcut_label(0, _) ->
- 0;
-shortcut_label(To0, D) ->
- case beam_utils:code_at(To0, D) of
- [{jump,{f,To}}|_] -> shortcut_label(To, D);
- _ -> To0
- end.
-
-shortcut_select_label(To, Reg, Lit, D) ->
- shortcut_rel_op(To, is_ne_exact, [Reg,Lit], D).
-
-prune_redundant([_,{f,Fail}|T], Fail) ->
- prune_redundant(T, Fail);
-prune_redundant([V,F|T], Fail) ->
- [V,F|prune_redundant(T, Fail)];
-prune_redundant([], _) -> [].
-
-%% Replace a comparison operator with a test instruction and a jump.
-%% For example, if we have this code:
-%%
-%% bif '=:=' Fail Src1 Src2 {x,0}
-%% jump L1
-%% .
-%% .
-%% .
-%% L1: select_val {x,0} FailLabel [... true => L2..., ...false => L3...]
-%%
-%% the first two instructions can be replaced with
-%%
-%% test is_eq_exact L3 Src1 Src2
-%% jump L2
-%%
-%% provided that {x,0} is killed at both L2 and L3.
-
-replace_comp_op(To, Reg, Op, Ops, D) ->
- False = comp_op_find_shortcut(To, Reg, {atom,false}, D),
- True = comp_op_find_shortcut(To, Reg, {atom,true}, D),
- {bif_to_test(Op, Ops, False),{jump,{f,True}}}.
-
-comp_op_find_shortcut(To0, Reg, Val, D) ->
- case shortcut_select_label(To0, Reg, Val, D) of
- To0 ->
- not_possible();
- To ->
- case is_killed_at(Reg, To, D) of
- false -> not_possible();
- true -> To
- end
- end.
-
-bif_to_test(Name, Args, Fail) ->
- try
- beam_utils:bif_to_test(Name, Args, {f,Fail})
- catch
- error:_ -> not_possible()
- end.
-
-not_possible() -> throw(not_possible).
-
-%% combine_eqs(To, Operands, Acc) -> Instruction.
-%% Combine two is_eq_exact instructions or (an is_eq_exact
-%% instruction and a select_val instruction) to a select_val
-%% instruction if possible.
-%%
-%% Example:
-%%
-%% is_eq_exact F1 Reg Lit1 select_val Reg F2 [ Lit1 L1
-%% L1: . Lit2 L2 ]
-%% .
-%% . ==>
-%% .
-%% F1: is_eq_exact F2 Reg Lit2 F1: is_eq_exact F2 Reg Lit2
-%% L2: .... L2:
-%%
-combine_eqs(To, [Reg,{Type,_}=Lit1]=Ops, D, Acc)
- when Type =:= atom; Type =:= integer ->
- Next = case Acc of
- [{label,Lbl}|_] -> Lbl;
- [{jump,{f,Lbl}}|_] -> Lbl
- end,
- case beam_utils:code_at(To, D) of
- [{test,is_eq_exact,{f,F2},[Reg,{Type,_}=Lit2]},
- {label,L2}|_] when Lit1 =/= Lit2 ->
- {select,select_val,Reg,{f,F2},[Lit1,{f,Next},Lit2,{f,L2}]};
- [{test,is_eq_exact,{f,F2},[Reg,{Type,_}=Lit2]},
- {jump,{f,L2}}|_] when Lit1 =/= Lit2 ->
- {select,select_val,Reg,{f,F2},[Lit1,{f,Next},Lit2,{f,L2}]};
- [{select,select_val,Reg,{f,F2},[{Type,_}|_]=List0}|_] ->
- List = remove_from_list(Lit1, List0),
- {select,select_val,Reg,{f,F2},[Lit1,{f,Next}|List]};
- _Is ->
- {test,is_eq_exact,{f,To},Ops}
- end;
-combine_eqs(To, Ops, _D, _Acc) ->
- {test,is_eq_exact,{f,To},Ops}.
-
-remove_from_list(Lit, [Lit,{f,_}|T]) ->
- T;
-remove_from_list(Lit, [Val,{f,_}=Fail|T]) ->
- [Val,Fail|remove_from_list(Lit, T)];
-remove_from_list(_, []) -> [].
-
-
-test_bs_literal(F, Ctxt, D,
- [{test,bs_match_string,F,[Ctxt,Bs]},
- {test,bs_test_tail2,F,[Ctxt,0]}|Acc]) ->
- test_bs_literal_1(Ctxt, Acc, D, Bs);
-test_bs_literal(F, Ctxt, D, [{test,bs_test_tail2,F,[Ctxt,0]}|Acc]) ->
- test_bs_literal_1(Ctxt, Acc, D, <<>>);
-test_bs_literal(_, Ctxt, D, Acc) ->
- test_bs_literal_1(Ctxt, Acc, D, none).
-
-test_bs_literal_1(Ctxt, Is, D, Literal) ->
- case beam_utils:is_killed(Ctxt, Is, D) of
- true -> {Literal,Is};
- false -> not_killed
- end.
-
-%% shortcut_bs_test(TargetLabel, ReversedInstructions, D) -> TargetLabel'
-%% Try to shortcut the failure label for bit syntax matching.
-
-shortcut_bs_test(To, Is, D) ->
- shortcut_bs_test_1(beam_utils:code_at(To, D), Is, To, D).
-
-shortcut_bs_test_1([{bs_restore2,Reg,SavePoint},
- {label,_},
- {test,bs_test_tail2,{f,To},[_,TailBits]}|_],
- PrevIs, To0, D) ->
- case count_bits_matched(PrevIs, {Reg,SavePoint}, 0) of
- Bits when Bits > TailBits ->
- %% This instruction will fail. We know because a restore has been
- %% done from the previous point SavePoint in the binary, and we
- %% also know that the binary contains at least Bits bits from
- %% SavePoint.
- %%
- %% Since we will skip a bs_restore2 if we shortcut to label To,
- %% we must now make sure that code at To does not depend on
- %% the position in the context in any way.
- case shortcut_bs_pos_used(To, Reg, D) of
- false -> To;
- true -> To0
- end;
- _Bits ->
- To0
- end;
-shortcut_bs_test_1([_|_], _, To, _) -> To.
-
-%% counts_bits_matched(ReversedInstructions, SavePoint, Bits) -> Bits'
-%% Given a reversed instruction stream, determine the minimum number
-%% of bits that will be matched by bit syntax instructions up to the
-%% given save point.
-
-count_bits_matched([{test,bs_get_utf8,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+8);
-count_bits_matched([{test,bs_get_utf16,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+16);
-count_bits_matched([{test,bs_get_utf32,{f,_},_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+32);
-count_bits_matched([{test,_,_,_,[_,Sz,U,{field_flags,_}],_}|Is], SavePoint, Bits) ->
- case Sz of
- {integer,N} -> count_bits_matched(Is, SavePoint, Bits+N*U);
- _ -> count_bits_matched(Is, SavePoint, Bits)
- end;
-count_bits_matched([{test,bs_match_string,_,[_,Bs]}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits+bit_size(Bs));
-count_bits_matched([{test,_,_,_}|Is], SavePoint, Bits) ->
- count_bits_matched(Is, SavePoint, Bits);
-count_bits_matched([{bs_save2,Reg,SavePoint}|_], {Reg,SavePoint}, Bits) ->
- %% The save point we are looking for - we are done.
- Bits;
-count_bits_matched([_|_], _, Bits) -> Bits.
-
-shortcut_bs_pos_used(To, Reg, D) ->
- shortcut_bs_pos_used_1(beam_utils:code_at(To, D), Reg, D).
-
-shortcut_bs_pos_used_1([{bs_context_to_binary,Reg}|_], Reg, _) ->
- false;
-shortcut_bs_pos_used_1(Is, Reg, D) ->
- not beam_utils:is_killed(Reg, Is, D).
-
-%% shortcut_bs_start_match(TargetLabel, Reg) -> TargetLabel
-%% A failing bs_start_match2 instruction means that the source (Reg)
-%% cannot be a binary. That means that it is safe to skip
-%% bs_context_to_binary instructions operating on Reg, and
-%% bs_start_match2 instructions operating on Reg.
-
-shortcut_bs_start_match(To, Reg, D) ->
- shortcut_bs_start_match_1(beam_utils:code_at(To, D), Reg, To, D).
-
-shortcut_bs_start_match_1([{bs_context_to_binary,Reg}|Is], Reg, To, D) ->
- shortcut_bs_start_match_1(Is, Reg, To, D);
-shortcut_bs_start_match_1([{jump,{f,To}}|_], Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_start_match_1(Code, Reg, To, D);
-shortcut_bs_start_match_1([{test,bs_start_match2,{f,To},_,[Reg|_],_}|_],
- Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_start_match_1(Code, Reg, To, D);
-shortcut_bs_start_match_1(_, _, To, _) ->
- To.
-
-%% shortcut_bs_context_to_binary(TargetLabel, Reg) -> TargetLabel
-%% If a bs_start_match2 instruction has been eliminated, the
-%% bs_context_to_binary instruction can be eliminated too.
-
-shortcut_bs_context_to_binary(To, Reg, D) ->
- shortcut_bs_ctb_1(beam_utils:code_at(To, D), Reg, To, D).
-
-shortcut_bs_ctb_1([{bs_context_to_binary,Reg}|Is], Reg, To, D) ->
- shortcut_bs_ctb_1(Is, Reg, To, D);
-shortcut_bs_ctb_1([{jump,{f,To}}|_], Reg, _, D) ->
- Code = beam_utils:code_at(To, D),
- shortcut_bs_ctb_1(Code, Reg, To, D);
-shortcut_bs_ctb_1(_, _, To, _) ->
- To.
-
-%% shortcut_rel_op(FailLabel, Operator, [Operand], D) -> FailLabel'
-%% Try to shortcut the given test instruction. Example:
-%%
-%% is_ge L1 {x,0} 48
-%% .
-%% .
-%% .
-%% L1: is_ge L2 {x,0} 65
-%%
-%% The first test instruction can be rewritten to "is_ge L2 {x,0} 48"
-%% since the instruction at L1 will also fail.
-%%
-%% If there are instructions between L1 and the other test instruction
-%% it may still be possible to do the shortcut. For example:
-%%
-%% L1: is_eq_exact L3 {x,0} 92
-%% is_ge L2 {x,0} 65
-%%
-%% Since the first test instruction failed, we know that {x,0} must
-%% be less than 48; therefore, we know that {x,0} cannot be equal to
-%% 92 and the jump to L3 cannot happen.
-
-shortcut_rel_op(To, Op, Ops, D) ->
- case normalize_op({test,Op,{f,To},Ops}) of
- {{NormOp,A,B},_} ->
- Normalized = {negate_op(NormOp),A,B},
- shortcut_rel_op_fp(To, Normalized, D);
- {_,_} ->
- To;
- error ->
- To
- end.
-
-shortcut_rel_op_fp(To0, Normalized, D) ->
- Code = beam_utils:code_at(To0, D),
- case shortcut_any_label(Code, Normalized) of
- error ->
- To0;
- To ->
- shortcut_rel_op_fp(To, Normalized, D)
- end.
-
-%% shortcut_any_label([Instruction], PrevCondition) -> FailLabel | error
-%% Using PrevCondition (a previous condition known to be true),
-%% try to shortcut to another failure label.
-
-shortcut_any_label([{jump,{f,Lbl}}|_], _Prev) ->
- Lbl;
-shortcut_any_label([{label,Lbl}|_], _Prev) ->
- Lbl;
-shortcut_any_label([{select,select_val,R,{f,Fail},L}|_], Prev) ->
- shortcut_selectval(L, R, Fail, Prev);
-shortcut_any_label([I|Is], Prev) ->
- case normalize_op(I) of
- error ->
- error;
- {Normalized,Fail} ->
- %% We have a relational operator.
- case will_succeed(Prev, Normalized) of
- no ->
- %% This test instruction will always branch
- %% to Fail.
- Fail;
- yes ->
- %% This test instruction will never branch,
- %% so we will look at the next instruction.
- shortcut_any_label(Is, Prev);
- maybe ->
- %% May or may not branch. From now on, we can only
- %% shortcut to the this specific failure label
- %% Fail.
- shortcut_specific_label(Is, Fail, Prev)
- end
- end.
-
-%% shortcut_specific_label([Instruction], FailLabel, PrevCondition) ->
-%% FailLabel | error
-%% We have previously encountered a test instruction that may or
-%% may not branch to FailLabel. Therefore we are only allowed
-%% to do the shortcut to the same fail label (FailLabel).
-
-shortcut_specific_label([{label,_}|Is], Fail, Prev) ->
- shortcut_specific_label(Is, Fail, Prev);
-shortcut_specific_label([{select,select_val,R,{f,F},L}|_], Fail, Prev) ->
- case shortcut_selectval(L, R, F, Prev) of
- Fail -> Fail;
- _ -> error
- end;
-shortcut_specific_label([I|Is], Fail, Prev) ->
- case normalize_op(I) of
- error ->
- error;
- {Normalized,Fail} ->
- case will_succeed(Prev, Normalized) of
- no ->
- %% Will branch to FailLabel.
- Fail;
- yes ->
- %% Will definitely never branch.
- shortcut_specific_label(Is, Fail, Prev);
- maybe ->
- %% May branch, but still OK since it will branch
- %% to FailLabel.
- shortcut_specific_label(Is, Fail, Prev)
- end;
- {Normalized,_} ->
- %% This test instruction will branch to a different
- %% fail label, if it branches at all.
- case will_succeed(Prev, Normalized) of
- yes ->
- %% Still OK, since the branch will never be
- %% taken.
- shortcut_specific_label(Is, Fail, Prev);
- no ->
- %% Give up. The branch will definitely be taken
- %% to a different fail label.
- error;
- maybe ->
- %% Give up. If the branch is taken, it will be
- %% to a different fail label.
- error
- end
- end.
-
-
-%% shortcut_selectval(List, Reg, Fail, PrevCond) -> FailLabel | error
-%% Try to shortcut a selectval instruction. A selectval instruction
-%% is equivalent to the following instruction sequence:
-%%
-%% is_ne_exact L1 Reg Value1
-%% .
-%% .
-%% .
-%% is_ne_exact LN Reg ValueN
-%% jump DefaultFailLabel
-%%
-shortcut_selectval([Val,{f,Lbl}|T], R, Fail, Prev) ->
- case will_succeed(Prev, {'=/=',R,get_literal(Val)}) of
- yes -> shortcut_selectval(T, R, Fail, Prev);
- no -> Lbl;
- maybe -> error
- end;
-shortcut_selectval([], _, Fail, _) -> Fail.
-
-%% will_succeed(PrevCondition, Condition) -> yes | no | maybe
-%% PrevCondition is a condition known to be true. This function
-%% will tell whether Condition will succeed.
-
-will_succeed({Op1,Reg,A}, {Op2,Reg,B}) ->
- will_succeed_1(Op1, A, Op2, B);
-will_succeed({'=:=',Reg,{literal,A}}, {TypeTest,Reg}) ->
- case erlang:TypeTest(A) of
- false -> no;
- true -> yes
- end;
-will_succeed({_,_,_}, maybe) ->
- maybe;
-will_succeed({_,_,_}, Test) when is_tuple(Test) ->
- maybe.
-
-will_succeed_1('=:=', A, '<', B) ->
- if
- B =< A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '=<', B) ->
- if
- B < A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '=:=', B) ->
- if
- A =:= B -> yes;
- true -> no
- end;
-will_succeed_1('=:=', A, '=/=', B) ->
- if
- A =:= B -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '>=', B) ->
- if
- B > A -> no;
- true -> yes
- end;
-will_succeed_1('=:=', A, '>', B) ->
- if
- B >= A -> no;
- true -> yes
- end;
-
-will_succeed_1('=/=', A, '=/=', B) when A =:= B -> yes;
-will_succeed_1('=/=', A, '=:=', B) when A =:= B -> no;
-
-will_succeed_1('<', A, '=:=', B) when B >= A -> no;
-will_succeed_1('<', A, '=/=', B) when B >= A -> yes;
-will_succeed_1('<', A, '<', B) when B >= A -> yes;
-will_succeed_1('<', A, '=<', B) when B > A -> yes;
-will_succeed_1('<', A, '>=', B) when B > A -> no;
-will_succeed_1('<', A, '>', B) when B >= A -> no;
-
-will_succeed_1('=<', A, '=:=', B) when B > A -> no;
-will_succeed_1('=<', A, '=/=', B) when B > A -> yes;
-will_succeed_1('=<', A, '<', B) when B > A -> yes;
-will_succeed_1('=<', A, '=<', B) when B >= A -> yes;
-will_succeed_1('=<', A, '>=', B) when B > A -> no;
-will_succeed_1('=<', A, '>', B) when B >= A -> no;
-
-will_succeed_1('>=', A, '=:=', B) when B < A -> no;
-will_succeed_1('>=', A, '=/=', B) when B < A -> yes;
-will_succeed_1('>=', A, '<', B) when B =< A -> no;
-will_succeed_1('>=', A, '=<', B) when B < A -> no;
-will_succeed_1('>=', A, '>=', B) when B =< A -> yes;
-will_succeed_1('>=', A, '>', B) when B < A -> yes;
-
-will_succeed_1('>', A, '=:=', B) when B =< A -> no;
-will_succeed_1('>', A, '=/=', B) when B =< A -> yes;
-will_succeed_1('>', A, '<', B) when B =< A -> no;
-will_succeed_1('>', A, '=<', B) when B < A -> no;
-will_succeed_1('>', A, '>=', B) when B =< A -> yes;
-will_succeed_1('>', A, '>', B) when B < A -> yes;
-
-will_succeed_1(_, _, _, _) -> maybe.
-
-%% normalize_op(Instruction) -> {Normalized,FailLabel} | error
-%% Normalized = {Operator,Register,Literal} |
-%% {TypeTest,Register} |
-%% maybe
-%% Operation = '<' | '=<' | '=:=' | '=/=' | '>=' | '>'
-%% TypeTest = is_atom | is_integer ...
-%% Literal = {literal,Term}
-%%
-%% Normalize a relational operator to facilitate further
-%% comparisons between operators. Always make the register
-%% operand the first operand. Thus the following instruction:
-%%
-%% {test,is_ge,{f,99},{integer,13},{x,0}}
-%%
-%% will be normalized to:
-%%
-%% {'=<',{x,0},{literal,13}}
-%%
-%% NOTE: Bit syntax test instructions are scary. They may change the
-%% state of match contexts and update registers, so we don't dare
-%% mess with them.
-
-normalize_op({test,is_ge,{f,Fail},Ops}) ->
- normalize_op_1('>=', Ops, Fail);
-normalize_op({test,is_lt,{f,Fail},Ops}) ->
- normalize_op_1('<', Ops, Fail);
-normalize_op({test,is_eq_exact,{f,Fail},Ops}) ->
- normalize_op_1('=:=', Ops, Fail);
-normalize_op({test,is_ne_exact,{f,Fail},Ops}) ->
- normalize_op_1('=/=', Ops, Fail);
-normalize_op({test,is_nil,{f,Fail},[R]}) ->
- normalize_op_1('=:=', [R,nil], Fail);
-normalize_op({test,Op,{f,Fail},[R]}) ->
- case erl_internal:new_type_test(Op, 1) of
- true -> {{Op,R},Fail};
- false -> {maybe,Fail}
- end;
-normalize_op({test,_,{f,Fail},_}=I) ->
- case beam_utils:is_pure_test(I) of
- true -> {maybe,Fail};
- false -> error
- end;
-normalize_op(_) ->
- error.
-
-normalize_op_1(Op, [Op1,Op2], Fail) ->
- case {get_literal(Op1),get_literal(Op2)} of
- {error,error} ->
- %% Both operands are registers.
- {maybe,Fail};
- {error,Lit} ->
- {{Op,Op1,Lit},Fail};
- {Lit,error} ->
- {{turn_op(Op),Op2,Lit},Fail};
- {_,_} ->
- %% Both operands are literals. Can probably only
- %% happen if the Core Erlang optimizations passes were
- %% turned off, so don't bother trying to do something
- %% smart here.
- {maybe,Fail}
- end.
-
-turn_op('<') -> '>';
-turn_op('>=') -> '=<';
-turn_op('=:='=Op) -> Op;
-turn_op('=/='=Op) -> Op.
-
-negate_op('>=') -> '<';
-negate_op('<') -> '>=';
-negate_op('=<') -> '>';
-negate_op('>') -> '=<';
-negate_op('=:=') -> '=/=';
-negate_op('=/=') -> '=:='.
-
-get_literal({atom,Val}) ->
- {literal,Val};
-get_literal({integer,Val}) ->
- {literal,Val};
-get_literal({float,Val}) ->
- {literal,Val};
-get_literal(nil) ->
- {literal,[]};
-get_literal({literal,_}=Lit) ->
- Lit;
-get_literal({_,_}) -> error.
-
-
-%%%
-%%% Removing stores to Y registers is not always safe
-%%% if there is an instruction that causes an exception
-%%% within a catch. In practice, there are few or no
-%%% opportunities for removing stores to Y registers anyway
-%%% if sys_core_fold has been run.
-%%%
-
-is_killed_at({x,_}=Reg, Lbl, D) ->
- beam_utils:is_killed_at(Reg, Lbl, D);
-is_killed_at({y,_}, _, _) ->
- false.
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 6cee9acae4..7d048716e4 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -373,6 +373,8 @@ disasm_instr(B, Bs, Atoms, Literals) ->
disasm_map_inst(get_map_elements, Arity, Bs, Atoms, Literals);
has_map_fields ->
disasm_map_inst(has_map_fields, Arity, Bs, Atoms, Literals);
+ put_tuple2 ->
+ disasm_put_tuple2(Bs, Atoms, Literals);
_ ->
try decode_n_args(Arity, Bs, Atoms, Literals) of
{Args, RestBs} ->
@@ -413,6 +415,14 @@ disasm_map_inst(Inst, Arity, Bs0, Atoms, Literals) ->
{List, RestBs} = decode_n_args(Len, Bs2, Atoms, Literals),
{{Inst, Args ++ [{Z,U,List}]}, RestBs}.
+disasm_put_tuple2(Bs, Atoms, Literals) ->
+ {X, Bs1} = decode_arg(Bs, Atoms, Literals),
+ {Z, Bs2} = decode_arg(Bs1, Atoms, Literals),
+ {U, Bs3} = decode_arg(Bs2, Atoms, Literals),
+ {u, Len} = U,
+ {List, RestBs} = decode_n_args(Len, Bs3, Atoms, Literals),
+ {{put_tuple2, [X,{Z,U,List}]}, RestBs}.
+
%%-----------------------------------------------------------------------
%% decode_arg([Byte]) -> {Arg, [Byte]}
%%
@@ -1095,6 +1105,23 @@ resolve_inst({get_hd,[Src,Dst]},_,_,_) ->
resolve_inst({get_tl,[Src,Dst]},_,_,_) ->
{get_tl,Src,Dst};
+%% OTP 22
+resolve_inst({bs_start_match3,[Fail,Bin,Live,Dst]},_,_,_) ->
+ {bs_start_match3,Fail,Bin,Live,Dst};
+resolve_inst({bs_get_tail,[Src,Dst,Live]},_,_,_) ->
+ {bs_get_tail,Src,Dst,Live};
+resolve_inst({bs_get_position,[Src,Dst,Live]},_,_,_) ->
+ {bs_get_position,Src,Dst,Live};
+resolve_inst({bs_set_position,[Src,Dst]},_,_,_) ->
+ {bs_set_position,Src,Dst};
+
+%%
+%% OTP 22.
+%%
+resolve_inst({put_tuple2,[Dst,{{z,1},{u,_},List0}]},_,_,_) ->
+ List = resolve_args(List0),
+ {put_tuple2,Dst,{list,List}};
+
%%
%% Catches instructions that are not yet handled.
%%
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index 05c0f4fbc7..98831d87a7 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -31,7 +31,7 @@
%%% erlang:error(function_clause, Args) => jump FuncInfoLabel
%%%
--import(lists, [reverse/1]).
+-import(lists, [reverse/1,seq/2]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
@@ -113,14 +113,7 @@ dig_out_block([{set,[{x,0}],[{atom,if_clause}],move}]) ->
{yes,if_end,[]};
dig_out_block([{set,[{x,0}],[{literal,{Exc,Value}}],move}|Is]) ->
translate_exception(Exc, {literal,Value}, Is, 0);
-dig_out_block([{set,[{x,0}],[Tuple],move},
- {set,[],[Value],put},
- {set,[],[{atom,Exc}],put},
- {set,[Tuple],[],{put_tuple,2}}|Is]) ->
- translate_exception(Exc, Value, Is, 3);
-dig_out_block([{set,[],[Value],put},
- {set,[],[{atom,Exc}],put},
- {set,[{x,0}],[],{put_tuple,2}}|Is]) ->
+dig_out_block([{set,[{x,0}],[{atom,Exc},Value],put_tuple2}|Is]) ->
translate_exception(Exc, Value, Is, 3);
dig_out_block(_) -> no.
@@ -138,23 +131,46 @@ fix_block(Is, Words) ->
reverse(fix_block_1(Is, Words)).
fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words) ->
- Needed = Needed0 - Words,
- true = Needed >= 0, %Assertion.
- [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is];
+ case Needed0 - Words of
+ 0 ->
+ Is;
+ Needed ->
+ true = Needed >= 0, %Assertion.
+ [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is]
+ end;
fix_block_1([I|Is], Words) ->
[I|fix_block_1(Is, Words)].
dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) ->
- case dig_out_fc(Bl, Live-1, nil) of
- no ->
- no;
- yes ->
- {yes,{function_clause,Live}}
- end;
+ Regs = maps:from_list([{{x,X},{arg,X}} || X <- seq(0, Live-1)]),
+ dig_out_fc(Bl, Regs);
dig_out_block_fc(_) -> no.
-dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) ->
- dig_out_fc(Is, Reg-1, Dst);
-dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) ->
- yes;
-dig_out_fc(_, _, _) -> no.
+dig_out_fc([{set,[Dst],[Hd,Tl],put_list}|Is], Regs0) ->
+ Regs = Regs0#{Dst=>{cons,get_reg(Hd, Regs0),get_reg(Tl, Regs0)}},
+ dig_out_fc(Is, Regs);
+dig_out_fc([{set,[Dst],[Src],move}|Is], Regs0) ->
+ Regs = Regs0#{Dst=>get_reg(Src, Regs0)},
+ dig_out_fc(Is, Regs);
+dig_out_fc([{set,_,_,_}|_], _Regs) ->
+ %% Unknown instruction. It is not a function_clause error.
+ no;
+dig_out_fc([], Regs) ->
+ case Regs of
+ #{{x,0}:={atom,function_clause},{x,1}:=Args} ->
+ dig_out_fc_1(Args, 0);
+ #{} ->
+ no
+ end.
+
+dig_out_fc_1({cons,{arg,I},T}, I) ->
+ dig_out_fc_1(T, I+1);
+dig_out_fc_1(nil, I) ->
+ {yes,{function_clause,I}};
+dig_out_fc_1(_, _) -> no.
+
+get_reg(R, Regs) ->
+ case Regs of
+ #{R:=Val} -> Val;
+ #{} -> R
+ end.
diff --git a/lib/compiler/src/beam_flatten.erl b/lib/compiler/src/beam_flatten.erl
index 20bd23a912..3e6bc1b1ed 100644
--- a/lib/compiler/src/beam_flatten.erl
+++ b/lib/compiler/src/beam_flatten.erl
@@ -32,8 +32,7 @@ module({Mod,Exp,Attr,Fs,Lc}, _Opt) ->
{ok,{Mod,Exp,Attr,[function(F) || F <- Fs],Lc}}.
function({function,Name,Arity,CLabel,Is0}) ->
- Is1 = block(Is0),
- Is = opt(Is1),
+ Is = block(Is0),
{function,Name,Arity,CLabel,Is}.
block(Is) ->
@@ -44,18 +43,11 @@ block([I|Is], Acc) -> block(Is, [I|Acc]);
block([], Acc) -> reverse(Acc).
norm_block([{set,[],[],{alloc,R,Alloc}}|Is], Acc0) ->
- case insert_alloc_in_bs_init(Acc0, Alloc) of
- impossible ->
- norm_block(Is, reverse(norm_allocate(Alloc, R), Acc0));
- Acc ->
- norm_block(Is, Acc)
- end;
-norm_block([{set,[D1],[S],get_hd},{set,[D2],[S],get_tl}|Is], Acc) ->
- I = {get_list,S,D1,D2},
- norm_block(Is, [I|Acc]);
-norm_block([I|Is], Acc) -> norm_block(Is, [norm(I)|Acc]);
+ norm_block(Is, reverse(norm_allocate(Alloc, R), Acc0));
+norm_block([I|Is], Acc) ->
+ norm_block(Is, [norm(I)|Acc]);
norm_block([], Acc) -> Acc.
-
+
norm({set,[D],As,{bif,N,F}}) -> {bif,N,F,As,D};
norm({set,[D],As,{alloc,R,{gc_bif,N,F}}}) -> {gc_bif,N,F,R,As,D};
norm({set,[D],[],init}) -> {init,D};
@@ -63,6 +55,7 @@ norm({set,[D],[S],move}) -> {move,S,D};
norm({set,[D],[S],fmove}) -> {fmove,S,D};
norm({set,[D],[S],fconv}) -> {fconv,S,D};
norm({set,[D],[S1,S2],put_list}) -> {put_list,S1,S2,D};
+norm({set,[D],Els,put_tuple2}) -> {put_tuple2,D,{list,Els}};
norm({set,[D],[],{put_tuple,A}}) -> {put_tuple,A,D};
norm({set,[],[S],put}) -> {put,S};
norm({set,[D],[S],{get_tuple_element,I}}) -> {get_tuple_element,S,I,D};
@@ -88,57 +81,3 @@ norm_allocate({nozero,Ns,0,Inits}, Regs) ->
[{allocate,Ns,Regs}|Inits];
norm_allocate({nozero,Ns,Nh,Inits}, Regs) ->
[{allocate_heap,Ns,Nh,Regs}|Inits].
-
-%% insert_alloc_in_bs_init(ReverseInstructionStream, AllocationInfo) ->
-%% impossible | ReverseInstructionStream'
-%% A bs_init/6 instruction should not be followed by a test heap instruction.
-%% Given the AllocationInfo from a test heap instruction, merge the
-%% allocation amounts into the previous bs_init/6 instruction (if any).
-%%
-insert_alloc_in_bs_init([{bs_put,_,_,_}=I|Is], Alloc) ->
- %% The instruction sequence ends with an bs_put/4 instruction.
- %% We'll need to search backwards for the bs_init/6 instruction.
- insert_alloc_1(Is, Alloc, [I]);
-insert_alloc_in_bs_init(_, _) -> impossible.
-
-insert_alloc_1([{bs_init=Op,Fail,Info0,Live,Ss,Dst}|Is],
- {_,nostack,Ws2,[]}, Acc) when is_integer(Live) ->
- %% The number of extra heap words is always in the second position
- %% in the Info tuple.
- Ws1 = element(2, Info0),
- Al = beam_utils:combine_heap_needs(Ws1, Ws2),
- Info = setelement(2, Info0, Al),
- I = {Op,Fail,Info,Live,Ss,Dst},
- reverse(Acc, [I|Is]);
-insert_alloc_1([{bs_put,_,_,_}=I|Is], Alloc, Acc) ->
- insert_alloc_1(Is, Alloc, [I|Acc]).
-
-%% opt(Is0) -> Is
-%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
-%% any kill up to the next call instruction. (To give the loader
-%% an opportunity to combine the 'move' and the 'call' instructions.)
-%%
-opt(Is) ->
- opt_1(Is, []).
-
-opt_1([{move,_,{x,0}}=I|Is0], Acc0) ->
- case move_past_kill(Is0, I, Acc0) of
- impossible -> opt_1(Is0, [I|Acc0]);
- {Is,Acc} -> opt_1(Is, Acc)
- end;
-opt_1([I|Is], Acc) ->
- opt_1(Is, [I|Acc]);
-opt_1([], Acc) -> reverse(Acc).
-
-move_past_kill([{kill,Src}|_], {move,Src,_}, _) ->
- impossible;
-move_past_kill([{kill,_}=I|Is], Move, Acc) ->
- move_past_kill(Is, Move, [I|Acc]);
-move_past_kill([{trim,N,_}=I|Is], {move,Src,Dst}=Move, Acc) ->
- case Src of
- {y,Y} when Y < N-> impossible;
- {y,Y} -> {Is,[{move,{y,Y-N},Dst},I|Acc]};
- _ -> {Is,[Move,I|Acc]}
- end;
-move_past_kill(Is, Move, Acc) ->
- {Is,[Move|Acc]}.
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 43084ad588..d694bd2a5b 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -22,7 +22,7 @@
-module(beam_jump).
-export([module/2,
- is_unreachable_after/1,is_exit_instruction/1,
+ is_exit_instruction/1,
remove_unused_labels/1]).
%%% The following optimisations are done:
@@ -128,27 +128,120 @@
%%% on the program state.
%%%
--import(lists, [reverse/1,reverse/2,foldl/3]).
+-import(lists, [foldl/3,mapfoldl/3,reverse/1,reverse/2]).
-type instruction() :: beam_utils:instruction().
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
+module({Mod,Exp,Attr,Fs0,Lc0}, _Opt) ->
+ {Fs,Lc} = mapfoldl(fun function/2, Lc0, Fs0),
{ok,{Mod,Exp,Attr,Fs,Lc}}.
%% function(Function) -> Function'
%% Optimize jumps and branches.
%%
%% NOTE: This function assumes that there are no labels inside blocks.
-function({function,Name,Arity,CLabel,Asm0}) ->
- Asm1 = share(Asm0),
- Asm2 = move(Asm1),
- Asm3 = opt(Asm2, CLabel),
- Asm = remove_unused_labels(Asm3),
- {function,Name,Arity,CLabel,Asm}.
+function({function,Name,Arity,CLabel,Asm0}, Lc0) ->
+ Asm1 = eliminate_moves(Asm0),
+ {Asm2,Lc} = insert_labels(Asm1, Lc0, []),
+ Asm3 = share(Asm2),
+ Asm4 = move(Asm3),
+ Asm5 = opt(Asm4, CLabel),
+ Asm = remove_unused_labels(Asm5),
+ {{function,Name,Arity,CLabel,Asm},Lc}.
+
+%%%
+%%% Scan instructions in execution order and remove redundant 'move'
+%%% instructions. 'move' instructions are redundant if we know that
+%%% the register already contains the value being assigned, as in the
+%%% following code:
+%%%
+%%% select_val Register FailLabel [... Literal => L1...]
+%%% .
+%%% .
+%%% .
+%%% L1: move Literal Register
+%%%
+
+eliminate_moves(Is) ->
+ eliminate_moves(Is, #{}, []).
+
+eliminate_moves([{select,select_val,Reg,_,List}=I|Is], D0, Acc) ->
+ D = update_value_dict(List, Reg, D0),
+ eliminate_moves(Is, D, [I|Acc]);
+eliminate_moves([{label,Lbl},{block,[{set,[Dst],[Lit],move}|BlkIs]}=Blk0|Is],
+ D, Acc0) ->
+ Acc = [{label,Lbl}|Acc0],
+ case already_has_value(Lit, Lbl, Dst, D) andalso
+ no_fallthrough(Acc0) of
+ true ->
+ %% Remove redundant 'move' instruction.
+ Blk = {block,BlkIs},
+ eliminate_moves([Blk|Is], D, Acc);
+ false ->
+ %% Keep 'move' instruction.
+ eliminate_moves([Blk0|Is], D, Acc)
+ end;
+eliminate_moves([{block,[]}|Is], D, Acc) ->
+ %% Empty blocks can prevent further jump optimizations.
+ eliminate_moves(Is, D, Acc);
+eliminate_moves([I|Is], D0, Acc) ->
+ D = update_unsafe_labels(I, D0),
+ eliminate_moves(Is, D, [I|Acc]);
+eliminate_moves([], _, Acc) -> reverse(Acc).
+
+no_fallthrough([I|_]) ->
+ is_unreachable_after(I).
+
+already_has_value(Lit, Lbl, Reg, D) ->
+ case D of
+ #{Lbl:={Reg,Lit}} ->
+ true;
+ #{} ->
+ false
+ end.
+
+update_value_dict([Lit,{f,Lbl}|T], Reg, D0) ->
+ D = case D0 of
+ #{Lbl:=unsafe} -> D0;
+ #{Lbl:={Reg,Lit}} -> D0;
+ #{Lbl:=_} -> D0#{Lbl:=unsafe};
+ #{} -> D0#{Lbl=>{Reg,Lit}}
+ end,
+ update_value_dict(T, Reg, D);
+update_value_dict([], _, D) -> D.
+
+update_unsafe_labels(I, D) ->
+ Ls = instr_labels(I),
+ update_unsafe_labels_1(Ls, D).
+
+update_unsafe_labels_1([L|Ls], D) ->
+ update_unsafe_labels_1(Ls, D#{L=>unsafe});
+update_unsafe_labels_1([], D) -> D.
+
+%%%
+%%% It seems to be useful to insert extra labels after certain
+%%% test instructions. This used to be done by beam_dead.
+%%%
+
+insert_labels([{test,Op,_,_}=I|Is], Lc, Acc) ->
+ Useful = case Op of
+ is_lt -> true;
+ is_ge -> true;
+ is_eq_exact -> true;
+ is_ne_exact -> true;
+ _ -> false
+ end,
+ case Useful of
+ false -> insert_labels(Is, Lc, [I|Acc]);
+ true -> insert_labels(Is, Lc+1, [{label,Lc},I|Acc])
+ end;
+insert_labels([I|Is], Lc, Acc) ->
+ insert_labels(Is, Lc, [I|Acc]);
+insert_labels([], Lc, Acc) ->
+ {reverse(Acc),Lc}.
%%%
%%% (1) We try to share the code for identical code segments by replacing all
@@ -271,8 +364,6 @@ extract_seq([{line,_}=Line|Is], Acc) ->
extract_seq(Is, [Line|Acc]);
extract_seq([{block,_}=Bl|Is], Acc) ->
extract_seq_1(Is, [Bl|Acc]);
-extract_seq([{bs_context_to_binary,_}=I|Is], Acc) ->
- extract_seq_1(Is, [I|Acc]);
extract_seq([{label,_}|_]=Is, Acc) ->
extract_seq_1(Is, Acc);
extract_seq(_, _) -> no.
@@ -571,52 +662,76 @@ drop_upto_label([{label,_}|_]=Is) -> Is;
drop_upto_label([_|Is]) -> drop_upto_label(Is);
drop_upto_label([]) -> [].
-%% ulbl(Instruction, UsedGbSet) -> UsedGbSet'
-%% Update the gb_set UsedGbSet with any function-local labels
+%% ulbl(Instruction, UsedCerlSet) -> UsedCerlSet'
+%% Update the cerl_set UsedCerlSet with any function-local labels
%% (i.e. not with labels in call instructions) referenced by
%% the instruction Instruction.
%%
%% NOTE: This function does NOT look for labels inside blocks.
-ulbl({test,_,Fail,_}, Used) ->
- mark_used(Fail, Used);
-ulbl({test,_,Fail,_,_,_}, Used) ->
- mark_used(Fail, Used);
-ulbl({select,_,_,Fail,Vls}, Used) ->
- mark_used_list(Vls, mark_used(Fail, Used));
-ulbl({'try',_,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({'catch',_,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({jump,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({loop_rec,Lbl,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({loop_rec_end,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({wait,Lbl}, Used) ->
- mark_used(Lbl, Used);
-ulbl({wait_timeout,Lbl,_To}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bif,_Name,Lbl,_As,_R}, Used) ->
- mark_used(Lbl, Used);
-ulbl({gc_bif,_Name,Lbl,_Live,_As,_R}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_init,Lbl,_,_,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({bs_put,Lbl,_,_}, Used) ->
- mark_used(Lbl, Used);
-ulbl({put_map,Lbl,_Op,_Src,_Dst,_Live,_List}, Used) ->
- mark_used(Lbl, Used);
-ulbl({get_map_elements,Lbl,_Src,_List}, Used) ->
- mark_used(Lbl, Used);
-ulbl(_, Used) -> Used.
-
-mark_used({f,0}, Used) -> Used;
-mark_used({f,L}, Used) -> cerl_sets:add_element(L, Used).
-
-mark_used_list([{f,L}|T], Used) ->
- mark_used_list(T, cerl_sets:add_element(L, Used));
-mark_used_list([_|T], Used) ->
- mark_used_list(T, Used);
-mark_used_list([], Used) -> Used.
+ulbl(I, Used) ->
+ case instr_labels(I) of
+ [] ->
+ Used;
+ [Lbl] ->
+ cerl_sets:add_element(Lbl, Used);
+ [_|_]=L ->
+ ulbl_list(L, Used)
+ end.
+
+ulbl_list([L|Ls], Used) ->
+ ulbl_list(Ls, cerl_sets:add_element(L, Used));
+ulbl_list([], Used) -> Used.
+
+-spec instr_labels(Instruction) -> Labels when
+ Instruction :: instruction(),
+ Labels :: [beam_asm:label()].
+
+instr_labels({test,_,Fail,_}) ->
+ do_instr_labels(Fail);
+instr_labels({test,_,Fail,_,_,_}) ->
+ do_instr_labels(Fail);
+instr_labels({select,_,_,Fail,Vls}) ->
+ do_instr_labels_list(Vls, do_instr_labels(Fail));
+instr_labels({'try',_,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({'catch',_,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({jump,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({loop_rec,Lbl,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({loop_rec_end,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({wait,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({wait_timeout,Lbl,_To}) ->
+ do_instr_labels(Lbl);
+instr_labels({bif,_Name,Lbl,_As,_R}) ->
+ do_instr_labels(Lbl);
+instr_labels({gc_bif,_Name,Lbl,_Live,_As,_R}) ->
+ do_instr_labels(Lbl);
+instr_labels({bs_init,Lbl,_,_,_,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({bs_put,Lbl,_,_}) ->
+ do_instr_labels(Lbl);
+instr_labels({put_map,Lbl,_Op,_Src,_Dst,_Live,_List}) ->
+ do_instr_labels(Lbl);
+instr_labels({get_map_elements,Lbl,_Src,_List}) ->
+ do_instr_labels(Lbl);
+instr_labels({recv_mark,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({recv_set,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels({fcheckerror,Lbl}) ->
+ do_instr_labels(Lbl);
+instr_labels(_) -> [].
+
+do_instr_labels({f,0}) -> [];
+do_instr_labels({f,F}) -> [F].
+
+do_instr_labels_list([{f,F}|T], Acc) ->
+ do_instr_labels_list(T, [F|Acc]);
+do_instr_labels_list([_|T], Acc) ->
+ do_instr_labels_list(T, Acc);
+do_instr_labels_list([], Acc) -> Acc.
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl
new file mode 100644
index 0000000000..d6e675ae72
--- /dev/null
+++ b/lib/compiler/src/beam_kernel_to_ssa.erl
@@ -0,0 +1,1325 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Convert the Kernel Erlang format to the SSA format.
+
+-module(beam_kernel_to_ssa).
+
+%% The main interface.
+-export([module/2]).
+
+-import(lists, [append/1,duplicate/2,flatmap/2,foldl/3,
+ keysort/2,mapfoldl/3,map/2,member/2,
+ reverse/1,reverse/2,sort/1]).
+
+-include("v3_kernel.hrl").
+-include("beam_ssa.hrl").
+
+-type label() :: beam_ssa:label().
+
+%% Main codegen structure.
+-record(cg, {lcount=1 :: label(), %Label counter
+ bfail=1 :: label(),
+ catch_label=none :: 'none' | label(),
+ vars=#{} :: map(), %Defined variables.
+ break=0 :: label(), %Break label
+ recv=0 :: label(), %Receive label
+ ultimate_failure=0 :: label() %Label for ultimate match failure.
+ }).
+
+%% Internal records.
+-record(cg_break, {args :: [beam_ssa:value()],
+ phi :: label()
+ }).
+-record(cg_phi, {vars :: [beam_ssa:b_var()]
+ }).
+-record(cg_unreachable, {}).
+
+-spec module(#k_mdef{}, [compile:option()]) -> {'ok',#b_module{}}.
+
+module(#k_mdef{name=Mod,exports=Es,attributes=Attr,body=Forms}, _Opts) ->
+ Body = functions(Forms, Mod),
+ Module = #b_module{name=Mod,exports=Es,attributes=Attr,body=Body},
+ {ok,Module}.
+
+functions(Forms, Mod) ->
+ [function(F, Mod) || F <- Forms].
+
+function(#k_fdef{anno=Anno0,func=Name,arity=Arity,
+ vars=As0,body=Kb}, Mod) ->
+ try
+ #k_match{} = Kb, %Assertion.
+
+ %% Generate the SSA form immediate format.
+ St0 = #cg{},
+ {As,St1} = new_ssa_vars(As0, St0),
+ {Asm,St} = cg_fun(Kb, St1),
+ Anno1 = line_anno(Anno0),
+ Anno = Anno1#{func_info=>{Mod,Name,Arity}},
+ #b_function{anno=Anno,args=As,bs=Asm,cnt=St#cg.lcount}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%% cg_fun([Lkexpr], [HeadVar], State) -> {[Ainstr],State}
+
+cg_fun(Ke, St0) ->
+ {UltimateFail,FailIs,St1} = make_failure(badarg, St0),
+ St2 = St1#cg{bfail=UltimateFail,ultimate_failure=UltimateFail},
+ {B,St} = cg(Ke, St2),
+ Asm = [{label,0}|B++FailIs],
+ finalize(Asm, St).
+
+make_failure(Reason, St0) ->
+ {Lbl,St1} = new_label(St0),
+ {Dst,St} = new_ssa_var('@ssa_ret', St1),
+ Is = [{label,Lbl},
+ #b_set{op=call,dst=Dst,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error},
+ arity=1},
+ #b_literal{val=Reason}]},
+ #b_ret{arg=Dst}],
+ {Lbl,Is,St}.
+
+%% cg(Lkexpr, State) -> {[Ainstr],State}.
+%% Generate code for a kexpr.
+
+cg(#k_match{body=M,ret=Rs}, St) ->
+ do_match_cg(M, Rs, St);
+cg(#k_guard_match{body=M,ret=Rs}, St) ->
+ do_match_cg(M, Rs, St);
+cg(#k_seq{arg=Arg,body=Body}, St0) ->
+ {ArgIs,St1} = cg(Arg, St0),
+ {BodyIs,St} = cg(Body, St1),
+ {ArgIs++BodyIs,St};
+cg(#k_call{anno=Le,op=Func,args=As,ret=Rs}, St) ->
+ call_cg(Func, As, Rs, Le, St);
+cg(#k_enter{anno=Le,op=Func,args=As}, St) ->
+ enter_cg(Func, As, Le, St);
+cg(#k_bif{anno=Le}=Bif, St) ->
+ bif_cg(Bif, Le, St);
+cg(#k_try{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th,ret=Rs}, St) ->
+ try_cg(Ta, Vs, Tb, Evs, Th, Rs, St);
+cg(#k_try_enter{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th}, St) ->
+ try_enter_cg(Ta, Vs, Tb, Evs, Th, St);
+cg(#k_catch{body=Cb,ret=[R]}, St) ->
+ do_catch_cg(Cb, R, St);
+cg(#k_receive{anno=Le,timeout=Te,var=Rvar,body=Rm,action=Tes,ret=Rs}, St) ->
+ recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, St);
+cg(#k_receive_next{}, #cg{recv=Recv}=St) ->
+ Is = [#b_set{op=recv_next},make_uncond_branch(Recv)],
+ {Is,St};
+cg(#k_receive_accept{}, St) ->
+ Remove = #b_set{op=remove_message},
+ {[Remove],St};
+cg(#k_put{anno=Le,arg=Con,ret=Var}, St) ->
+ put_cg(Var, Con, Le, St);
+cg(#k_return{args=[Ret0]}, St) ->
+ Ret = ssa_arg(Ret0, St),
+ {[#b_ret{arg=Ret}],St};
+cg(#k_break{args=Bs}, #cg{break=Br}=St) ->
+ Args = ssa_args(Bs, St),
+ {[#cg_break{args=Args,phi=Br}],St};
+cg(#k_guard_break{args=Bs}, St) ->
+ cg(#k_break{args=Bs}, St).
+
+%% match_cg(Matc, [Ret], State) -> {[Ainstr],State}.
+%% Generate code for a match.
+
+do_match_cg(M, Rs, St0) ->
+ {B,St1} = new_label(St0),
+ {Mis,St2} = match_cg(M, St1#cg.bfail, St1#cg{break=B}),
+ {BreakVars,St} = new_ssa_vars(Rs, St2),
+ {Mis ++ [{label,B},#cg_phi{vars=BreakVars}],
+ St#cg{bfail=St0#cg.bfail,break=St1#cg.break}}.
+
+%% match_cg(Match, Fail, State) -> {[Ainstr],State}.
+%% Generate code for a match tree.
+
+match_cg(#k_alt{first=F,then=S}, Fail, St0) ->
+ {Tf,St1} = new_label(St0),
+ {Fis,St2} = match_cg(F, Tf, St1),
+ {Sis,St3} = match_cg(S, Fail, St2),
+ {Fis ++ [{label,Tf}] ++ Sis,St3};
+match_cg(#k_select{var=#k_var{}=V,types=Scs}, Fail, St) ->
+ match_fmf(fun (S, F, Sta) ->
+ select_cg(S, V, F, Fail, Sta)
+ end, Fail, St, Scs);
+match_cg(#k_guard{clauses=Gcs}, Fail, St) ->
+ match_fmf(fun (G, F, Sta) ->
+ guard_clause_cg(G, F, Sta)
+ end, Fail, St, Gcs);
+match_cg(Ke, _Fail, St0) ->
+ cg(Ke, St0).
+
+%% select_cg(Sclause, V, TypeFail, ValueFail, State) -> {Is,State}.
+%% Selecting type and value needs two failure labels, TypeFail is the
+%% label to jump to of the next type test when this type fails, and
+%% ValueFail is the label when this type is correct but the value is
+%% wrong. These are different as in the second case there is no need
+%% to try the next type, it will always fail.
+
+select_cg(#k_type_clause{type=k_binary,values=[S]}, Var, Tf, Vf, St) ->
+ select_binary(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_bin_seg,values=Vs}, Var, Tf, _Vf, St) ->
+ select_bin_segs(Vs, Var, Tf, St);
+select_cg(#k_type_clause{type=k_bin_int,values=Vs}, Var, Tf, _Vf, St) ->
+ select_bin_segs(Vs, Var, Tf, St);
+select_cg(#k_type_clause{type=k_bin_end,values=[S]}, Var, Tf, _Vf, St) ->
+ select_bin_end(S, Var, Tf, St);
+select_cg(#k_type_clause{type=k_map,values=Vs}, Var, Tf, Vf, St) ->
+ select_map(Vs, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_cons,values=[S]}, Var, Tf, Vf, St) ->
+ select_cons(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_nil,values=[S]}, Var, Tf, Vf, St) ->
+ select_nil(S, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=k_literal,values=Vs}, Var, Tf, Vf, St) ->
+ select_literal(Vs, Var, Tf, Vf, St);
+select_cg(#k_type_clause{type=Type,values=Scs}, Var, Tf, Vf, St0) ->
+ {Vis,St1} =
+ mapfoldl(fun (S, Sta) ->
+ {Val,Is,Stb} = select_val(S, Var, Vf, Sta),
+ {{Is,[Val]},Stb}
+ end, St0, Scs),
+ OptVls = combine(lists:sort(combine(Vis))),
+ {Vls,Sis,St2} = select_labels(OptVls, St1, [], []),
+ Arg = ssa_arg(Var, St2),
+ {Is,St} = select_val_cg(Type, Arg, Vls, Tf, Vf, Sis, St2),
+ {Is,St}.
+
+select_val_cg(k_tuple, Tuple, Vls, Tf, Vf, Sis, St0) ->
+ {Is0,St1} = make_cond_branch({bif,is_tuple}, [Tuple], Tf, St0),
+ {Arity,St2} = new_ssa_var('@ssa_arity', St1),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is,St} = select_val_cg(k_int, Arity, Vls, Vf, Vf, Sis, St2),
+ {Is0++[GetArity]++Is,St};
+select_val_cg(Type, R, Vls, Tf, Vf, Sis, St0) ->
+ {TypeIs,St1} = if
+ Tf =:= Vf ->
+ %% The type and value failure labels are the same;
+ %% we don't need a type test.
+ {[],St0};
+ true ->
+ %% Different labels for type failure and
+ %% label failure; we need a type test.
+ Test = select_type_test(Type),
+ make_cond_branch(Test, [R], Tf, St0)
+ end,
+ case Vls of
+ [{Val,Succ}] ->
+ {Is,St} = make_cond({bif,'=:='}, [R,Val], Vf, Succ, St1),
+ {TypeIs++Is++Sis,St};
+ [_|_] ->
+ {TypeIs++[#b_switch{arg=R,fail=Vf,list=Vls}|Sis],St1}
+ end.
+
+select_type_test(k_int) -> {bif,is_integer};
+select_type_test(k_atom) -> {bif,is_atom};
+select_type_test(k_float) -> {bif,is_float}.
+
+combine([{Is,Vs1},{Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]);
+combine([V|Vis]) -> [V|combine(Vis)];
+combine([]) -> [].
+
+select_labels([{Is,Vs}|Vis], St0, Vls, Sis) ->
+ {Lbl,St1} = new_label(St0),
+ select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]);
+select_labels([], St, Vls, Sis) ->
+ {Vls,append(Sis),St}.
+
+add_vls([V|Vs], Lbl, Acc) ->
+ add_vls(Vs, Lbl, [{#b_literal{val=V},Lbl}|Acc]);
+add_vls([], _, Acc) -> Acc.
+
+select_literal(S, V, Tf, Vf, St) ->
+ Src = ssa_arg(V, St),
+ F = fun(ValClause, Fail, St0) ->
+ {Val,ValIs,St1} = select_val(ValClause, V, Vf, St0),
+ Args = [Src,#b_literal{val=Val}],
+ {Is,St2} = make_cond_branch({bif,'=:='}, Args, Fail, St1),
+ {Is++ValIs,St2}
+ end,
+ match_fmf(F, Tf, St, S).
+
+select_cons(#k_val_clause{val=#k_cons{hd=Hd,tl=Tl},body=B},
+ V, Tf, Vf, St0) ->
+ Es = [Hd,Tl],
+ {Eis,St1} = select_extract_cons(V, Es, St0),
+ {Bis,St2} = match_cg(B, Vf, St1),
+ Src = ssa_arg(V, St2),
+ {Is,St} = make_cond_branch(is_nonempty_list, [Src], Tf, St2),
+ {Is ++ Eis ++ Bis,St}.
+
+select_nil(#k_val_clause{val=#k_nil{},body=B}, V, Tf, Vf, St0) ->
+ {Bis,St1} = match_cg(B, Vf, St0),
+ Src = ssa_arg(V, St1),
+ {Is,St} = make_cond_branch({bif,'=:='}, [Src,#b_literal{val=[]}], Tf, St1),
+ {Is ++ Bis,St}.
+
+select_binary(#k_val_clause{val=#k_binary{segs=#k_var{name=Ctx0}},body=B},
+ #k_var{}=Src, Tf, Vf, St0) ->
+ {Ctx,St1} = new_ssa_var(Ctx0, St0),
+ {Bis0,St2} = match_cg(B, Vf, St1),
+ {TestIs,St} = make_cond_branch(succeeded, [Ctx], Tf, St2),
+ Bis1 = [#b_set{op=bs_start_match,dst=Ctx,
+ args=[ssa_arg(Src, St)]}] ++ TestIs ++ Bis0,
+ Bis = finish_bs_matching(Bis1),
+ {Bis,St}.
+
+finish_bs_matching([#b_set{op=bs_match,
+ args=[#b_literal{val=string},Ctx,#b_literal{val=BinList}]}=Set|Is])
+ when is_list(BinList) ->
+ I = Set#b_set{args=[#b_literal{val=string},Ctx,
+ #b_literal{val=list_to_bitstring(BinList)}]},
+ finish_bs_matching([I|Is]);
+finish_bs_matching([I|Is]) ->
+ [I|finish_bs_matching(Is)];
+finish_bs_matching([]) -> [].
+
+make_cond(Cond, Args, Fail, Succ, St0) ->
+ {Bool,St} = new_ssa_var('@ssa_bool', St0),
+ Bif = #b_set{op=Cond,dst=Bool,args=Args},
+ Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
+ {[Bif,Br],St}.
+
+make_cond_branch(Cond, Args, Fail, St0) ->
+ {Bool,St1} = new_ssa_var('@ssa_bool', St0),
+ {Succ,St} = new_label(St1),
+ Bif = #b_set{op=Cond,dst=Bool,args=Args},
+ Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
+ {[Bif,Br,{label,Succ}],St}.
+
+make_uncond_branch(Fail) ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail}.
+
+%% Instructions for selection of binary segments.
+
+select_bin_segs(Scs, Ivar, Tf, St) ->
+ match_fmf(fun(S, Fail, Sta) ->
+ select_bin_seg(S, Ivar, Fail, Sta)
+ end, Tf, St, Scs).
+
+select_bin_seg(#k_val_clause{val=#k_bin_seg{size=Size,unit=U,type=T,
+ seg=Seg,flags=Fs,next=Next},
+ body=B,anno=Anno},
+ #k_var{}=Src, Fail, St0) ->
+ LineAnno = line_anno(Anno),
+ Ctx = get_context(Src, St0),
+ {Mis,St1} = select_extract_bin(Next, Size, U, T, Fs, Fail,
+ Ctx, LineAnno, St0),
+ {Extracted,St2} = new_ssa_var(Seg#k_var.name, St1),
+ {Bis,St} = bin_match_cg(Size, B, Fail, St2),
+ BsGet = #b_set{op=bs_extract,dst=Extracted,args=[ssa_arg(Next, St)]},
+ Is = Mis ++ [BsGet] ++ Bis,
+ {Is,St};
+select_bin_seg(#k_val_clause{val=#k_bin_int{size=Sz,unit=U,flags=Fs,
+ val=Val,next=Next},
+ body=B},
+ #k_var{}=Src, Fail, St0) ->
+ Ctx = get_context(Src, St0),
+ {Mis,St1} = select_extract_int(Next, Val, Sz, U, Fs, Fail,
+ Ctx, St0),
+ {Bis,St} = match_cg(B, Fail, St1),
+ Is = case Mis ++ Bis of
+ [#b_set{op=bs_match,args=[#b_literal{val=string},OtherCtx1,Bin1]},
+ #b_set{op=succeeded,dst=Bool1},
+ #b_br{bool=Bool1,succ=Succ,fail=Fail},
+ {label,Succ},
+ #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},_OtherCtx2,Bin2]}|
+ [#b_set{op=succeeded,dst=Bool2},
+ #b_br{bool=Bool2,fail=Fail}|_]=Is0] ->
+ %% We used to do this optimization later, but it
+ %% turns out that in huge functions with many
+ %% string matching instructions, it's a huge win
+ %% to do the combination now. To avoid copying the
+ %% binary data again and again, we'll combine bitstrings
+ %% in a list and convert all of it to a bitstring later.
+ {#b_literal{val=B1},#b_literal{val=B2}} = {Bin1,Bin2},
+ Bin = #b_literal{val=[B1,B2]},
+ Set = #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},OtherCtx1,Bin]},
+ [Set|Is0];
+ Is0 ->
+ Is0
+ end,
+ {Is,St}.
+
+bin_match_cg(#k_atom{val=all}, B0, Fail, St) ->
+ #k_select{types=Types} = B0,
+ [#k_type_clause{type=k_bin_end,values=Values}] = Types,
+ [#k_val_clause{val=#k_bin_end{},body=B}] = Values,
+ match_cg(B, Fail, St);
+bin_match_cg(_, B, Fail, St) ->
+ match_cg(B, Fail, St).
+
+get_context(#k_var{}=Var, St) ->
+ ssa_arg(Var, St).
+
+select_bin_end(#k_val_clause{val=#k_bin_end{},body=B}, Src, Tf, St0) ->
+ Ctx = get_context(Src, St0),
+ {Bis,St1} = match_cg(B, Tf, St0),
+ {TestIs,St} = make_cond_branch(bs_test_tail, [Ctx,#b_literal{val=0}], Tf, St1),
+ Is = TestIs++Bis,
+ {Is,St}.
+
+select_extract_bin(#k_var{name=Hd}, Size0, Unit, Type, Flags, Vf,
+ Ctx, Anno, St0) ->
+ {Dst,St1} = new_ssa_var(Hd, St0),
+ Size = ssa_arg(Size0, St0),
+ build_bs_instr(Anno, Type, Vf, Ctx, Size, Unit, Flags, Dst, St1).
+
+select_extract_int(#k_var{name=Tl}, 0, #k_int{val=0}, _U, _Fs, _Vf,
+ Ctx, St0) ->
+ St = set_ssa_var(Tl, Ctx, St0),
+ {[],St};
+select_extract_int(#k_var{name=Tl}, Val, #k_int{val=Sz}, U, Fs, Vf,
+ Ctx, St0) ->
+ {Dst,St1} = new_ssa_var(Tl, St0),
+ Bits = U*Sz,
+ Bin = case member(big, Fs) of
+ true ->
+ <<Val:Bits>>;
+ false ->
+ true = member(little, Fs), %Assertion.
+ <<Val:Bits/little>>
+ end,
+ Bits = bit_size(Bin), %Assertion.
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Vf, St1),
+ Set = #b_set{op=bs_match,dst=Dst,
+ args=[#b_literal{val=string},Ctx,#b_literal{val=Bin}]},
+ {[Set|TestIs],St}.
+
+build_bs_instr(Anno, Type, Fail, Ctx, Size, Unit0, Flags0, Dst, St0) ->
+ Unit = #b_literal{val=Unit0},
+ Flags = #b_literal{val=Flags0},
+ NeedSize = bs_need_size(Type),
+ TypeArg = #b_literal{val=Type},
+ Get = case NeedSize of
+ true ->
+ #b_set{anno=Anno,op=bs_match,dst=Dst,
+ args=[TypeArg,Ctx,Flags,Size,Unit]};
+ false ->
+ #b_set{anno=Anno,op=bs_match,dst=Dst,
+ args=[TypeArg,Ctx,Flags]}
+ end,
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St0),
+ {[Get|Is],St}.
+
+select_val(#k_val_clause{val=#k_tuple{es=Es},body=B}, V, Vf, St0) ->
+ #k{us=Used} = k_get_anno(B),
+ {Eis,St1} = select_extract_tuple(V, Es, Used, St0),
+ {Bis,St2} = match_cg(B, Vf, St1),
+ {length(Es),Eis ++ Bis,St2};
+select_val(#k_val_clause{val=Val0,body=B}, _V, Vf, St0) ->
+ Val = case Val0 of
+ #k_atom{val=Lit} -> Lit;
+ #k_float{val=Lit} -> Lit;
+ #k_int{val=Lit} -> Lit;
+ #k_literal{val=Lit} -> Lit
+ end,
+ {Bis,St1} = match_cg(B, Vf, St0),
+ {Val,Bis,St1}.
+
+%% select_extract_tuple(Src, [V], State) -> {[E],State}.
+%% Extract tuple elements, but only if they are actually used.
+%%
+%% Not extracting tuple elements that are not used is an
+%% optimization for compile time and memory use during compilation.
+%% It is probably worthwhile because it is common to extract only a
+%% few elements from a huge record.
+
+select_extract_tuple(Src, Vs, Used, St0) ->
+ Tuple = ssa_arg(Src, St0),
+ F = fun (#k_var{name=V}, {Elem,S0}) ->
+ case member(V, Used) of
+ true ->
+ Args = [Tuple,#b_literal{val=Elem}],
+ {Dst,S} = new_ssa_var(V, S0),
+ Get = #b_set{op=get_tuple_element,dst=Dst,args=Args},
+ {[Get],{Elem+1,S}};
+ false ->
+ {[],{Elem+1,S0}}
+ end
+ end,
+ {Es,{_,St}} = flatmapfoldl(F, {0,St0}, Vs),
+ {Es,St}.
+
+select_map(Scs, V, Tf, Vf, St0) ->
+ MapSrc = ssa_arg(V, St0),
+ {Is,St1} =
+ match_fmf(fun(#k_val_clause{val=#k_map{op=exact,es=Es},
+ body=B}, Fail, St1) ->
+ select_map_val(V, Es, B, Fail, St1)
+ end, Vf, St0, Scs),
+ {TestIs,St} = make_cond_branch({bif,is_map}, [MapSrc], Tf, St1),
+ {TestIs++Is,St}.
+
+select_map_val(V, Es, B, Fail, St0) ->
+ {Eis,St1} = select_extract_map(Es, V, Fail, St0),
+ {Bis,St2} = match_cg(B, Fail, St1),
+ {Eis++Bis,St2}.
+
+select_extract_map([P|Ps], Src, Fail, St0) ->
+ MapSrc = ssa_arg(Src, St0),
+ #k_map_pair{key=Key0,val=#k_var{name=Dst0}} = P,
+ Key = ssa_arg(Key0, St0),
+ {Dst,St1} = new_ssa_var(Dst0, St0),
+ Set = #b_set{op=get_map_element,dst=Dst,args=[MapSrc,Key]},
+ {TestIs,St2} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {Is,St} = select_extract_map(Ps, Src, Fail, St2),
+ {[Set|TestIs]++Is,St};
+select_extract_map([], _, _, St) ->
+ {[],St}.
+
+select_extract_cons(Src0, [#k_var{name=Hd},#k_var{name=Tl}], St0) ->
+ Src = ssa_arg(Src0, St0),
+ {HdDst,St1} = new_ssa_var(Hd, St0),
+ {TlDst,St2} = new_ssa_var(Tl, St1),
+ GetHd = #b_set{op=get_hd,dst=HdDst,args=[Src]},
+ GetTl = #b_set{op=get_tl,dst=TlDst,args=[Src]},
+ {[GetHd,GetTl],St2}.
+
+guard_clause_cg(#k_guard_clause{guard=G,body=B}, Fail, St0) ->
+ {Gis,St1} = guard_cg(G, Fail, St0),
+ {Bis,St} = match_cg(B, Fail, St1),
+ {Gis ++ Bis,St}.
+
+%% guard_cg(Guard, Fail, State) -> {[Ainstr],State}.
+%% A guard is a boolean expression of tests. Tests return true or
+%% false. A fault in a test causes the test to return false. Tests
+%% never return the boolean, instead we generate jump code to go to
+%% the correct exit point. Primops and tests all go to the next
+%% instruction on success or jump to a failure label.
+
+guard_cg(#k_protected{arg=Ts,ret=Rs,inner=Inner}, Fail, St) ->
+ protected_cg(Ts, Rs, Inner, Fail, St);
+guard_cg(#k_test{op=Test0,args=As,inverted=Inverted}, Fail, St0) ->
+ #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Test}} = Test0,
+ test_cg(Test, Inverted, As, Fail, St0);
+guard_cg(#k_seq{arg=Arg,body=Body}, Fail, St0) ->
+ {ArgIs,St1} = guard_cg(Arg, Fail, St0),
+ {BodyIs,St} = guard_cg(Body, Fail, St1),
+ {ArgIs++BodyIs,St};
+guard_cg(G, _Fail, St) ->
+ cg(G, St).
+
+test_cg('=/=', Inverted, As, Fail, St) ->
+ test_cg('=:=', not Inverted, As, Fail, St);
+test_cg('/=', Inverted, As, Fail, St) ->
+ test_cg('==', not Inverted, As, Fail, St);
+test_cg(Test, Inverted, As0, Fail, St0) ->
+ As = ssa_args(As0, St0),
+ case {Test,ssa_args(As0, St0)} of
+ {is_record,[Tuple,#b_literal{val=Atom}=Tag,#b_literal{val=Int}=Arity]}
+ when is_atom(Atom), is_integer(Int) ->
+ test_is_record_cg(Inverted, Fail, Tuple, Tag, Arity, St0);
+ {_,As} ->
+ {Bool,St1} = new_ssa_var('@ssa_bool', St0),
+ {Succ,St} = new_label(St1),
+ Bif = #b_set{op={bif,Test},dst=Bool,args=As},
+ Br = case Inverted of
+ false -> #b_br{bool=Bool,succ=Succ,fail=Fail};
+ true -> #b_br{bool=Bool,succ=Fail,fail=Succ}
+ end,
+ {[Bif,Br,{label,Succ}],St}
+ end.
+
+test_is_record_cg(false, Fail, Tuple, TagVal, ArityVal, St0) ->
+ {Arity,St1} = new_ssa_var('@ssa_arity', St0),
+ {Tag,St2} = new_ssa_var('@ssa_tag', St1),
+ {Is0,St3} = make_cond_branch({bif,is_tuple}, [Tuple], Fail, St2),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St4} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], Fail, St3),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], Fail, St4),
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2,
+ {Is,St};
+test_is_record_cg(true, Fail, Tuple, TagVal, ArityVal, St0) ->
+ {Succ,St1} = new_label(St0),
+ {Arity,St2} = new_ssa_var('@ssa_arity', St1),
+ {Tag,St3} = new_ssa_var('@ssa_tag', St2),
+ {Is0,St4} = make_cond_branch({bif,is_tuple}, [Tuple], Succ, St3),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St5} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], Succ, St4),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], Succ, St5),
+ Is3 = [make_uncond_branch(Fail),{label,Succ}],
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2 ++ Is3,
+ {Is,St}.
+
+%% protected_cg([Kexpr], [Ret], Fail, St) -> {[Ainstr],St}.
+%% Do a protected. Protecteds without return values are just done
+%% for effect, the return value is not checked, success passes on to
+%% the next instruction and failure jumps to Fail. If there are
+%% return values then these must be set to 'false' on failure,
+%% control always passes to the next instruction.
+
+protected_cg(Ts, [], _, Fail, St0) ->
+ %% Protect these calls, revert when done.
+ {Tis,St1} = guard_cg(Ts, Fail, St0#cg{bfail=Fail}),
+ {Tis,St1#cg{bfail=St0#cg.bfail}};
+protected_cg(Ts, Rs, Inner0, _Fail, St0) ->
+ {Pfail,St1} = new_label(St0),
+ {Br,St2} = new_label(St1),
+ Prot = duplicate(length(Rs), #b_literal{val=false}),
+ {Tis,St3} = guard_cg(Ts, Pfail, St2#cg{break=Pfail,bfail=Pfail}),
+ Inner = ssa_args(Inner0, St3),
+ {BreakVars,St} = new_ssa_vars(Rs, St3),
+ Is = Tis ++ [#cg_break{args=Inner,phi=Br},
+ {label,Pfail},#cg_break{args=Prot,phi=Br},
+ {label,Br},#cg_phi{vars=BreakVars}],
+ {Is,St#cg{break=St0#cg.break,bfail=St0#cg.bfail}}.
+
+%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,State}.
+%% This is a special flatmapfoldl for match code gen where we
+%% generate a "failure" label for each clause. The last clause uses
+%% an externally generated failure label, LastFail. N.B. We do not
+%% know or care how the failure labels are used.
+
+match_fmf(F, LastFail, St, [H]) ->
+ F(H, LastFail, St);
+match_fmf(F, LastFail, St0, [H|T]) ->
+ {Fail,St1} = new_label(St0),
+ {R,St2} = F(H, Fail, St1),
+ {Rs,St3} = match_fmf(F, LastFail, St2, T),
+ {R ++ [{label,Fail}] ++ Rs,St3}.
+
+%% fail_label(State) -> {Where,FailureLabel}.
+%% Where = guard | no_catch | in_catch
+%% Return an indication of which part of a function code is
+%% being generated for and the appropriate failure label to
+%% use.
+%%
+%% Where has the following meaning:
+%%
+%% guard - Inside a guard.
+%% no_catch - In a function body, not in the scope of
+%% a try/catch or catch.
+%% in_catch - In the scope of a try/catch or catch.
+
+fail_label(#cg{catch_label=Catch,bfail=Fail,ultimate_failure=Ult}) ->
+ if
+ Fail =/= Ult ->
+ {guard,Fail};
+ Catch =:= none ->
+ {no_catch,Fail};
+ is_integer(Catch) ->
+ {in_catch,Catch}
+ end.
+
+%% bif_fail_label(State) -> FailureLabel.
+%% Return the appropriate failure label for a guard BIF call or
+%% primop that fails.
+
+bif_fail_label(St) ->
+ {_,Fail} = fail_label(St),
+ Fail.
+
+%% call_cg(Func, [Arg], [Ret], Le, State) ->
+%% {[Ainstr],State}.
+%% enter_cg(Func, [Arg], Le, St) -> {[Ainstr],St}.
+%% Generate code for call and enter.
+
+call_cg(Func, As, [], Le, St) ->
+ call_cg(Func, As, [#k_var{name='@ssa_ignored'}], Le, St);
+call_cg(Func0, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) ->
+ case fail_label(St0) of
+ {guard,Fail} ->
+ %% Inside a guard. The only allowed function call is to
+ %% erlang:error/1,2. We will generate a branch to the
+ %% failure branch.
+ #k_remote{mod=#k_atom{val=erlang},
+ name=#k_atom{val=error}} = Func0, %Assertion.
+ [#k_var{name=DestVar}] = Rs,
+ St = set_ssa_var(DestVar, #b_literal{val=unused}, St0),
+ {[make_uncond_branch(Fail),#cg_unreachable{}],St};
+ {Catch,Fail} ->
+ %% Ordinary function call in a function body.
+ Args = ssa_args(As, St0),
+ {Ret,St1} = new_ssa_var(R, St0),
+ Func = call_target(Func0, Args, St0),
+ Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=[Func|Args]},
+
+ %% If this is a call to erlang:error(), MoreRs could be a
+ %% nonempty list of variables that each need a value.
+ St2 = foldl(fun(#k_var{name=Dummy}, S) ->
+ set_ssa_var(Dummy, #b_literal{val=unused}, S)
+ end, St1, MoreRs),
+ case Catch of
+ no_catch ->
+ {[Call],St2};
+ in_catch ->
+ {TestIs,St} = make_cond_branch(succeeded, [Ret], Fail, St2),
+ {[Call|TestIs],St}
+ end
+ end.
+
+enter_cg(Func0, As0, Le, St0) ->
+ Anno = line_anno(Le),
+ Func = call_target(Func0, As0, St0),
+ As = ssa_args(As0, St0),
+ {Ret,St} = new_ssa_var('@ssa_ret', St0),
+ Call = #b_set{anno=Anno,op=call,dst=Ret,args=[Func|As]},
+ {[Call,#b_ret{arg=Ret}],St}.
+
+call_target(Func, As, St) ->
+ Arity = length(As),
+ case Func of
+ #k_remote{mod=Mod0,name=Name0} ->
+ Mod = ssa_arg(Mod0, St),
+ Name = ssa_arg(Name0, St),
+ #b_remote{mod=Mod,name=Name,arity=Arity};
+ #k_local{name=Name} when is_atom(Name) ->
+ #b_local{name=#b_literal{val=Name},arity=Arity};
+ #k_var{}=Var ->
+ ssa_arg(Var, St)
+ end.
+
+%% bif_cg(#k_bif{}, Le,State) -> {[Ainstr],State}.
+%% Generate code for a guard BIF or primop.
+
+bif_cg(#k_bif{op=#k_internal{name=Name},args=As,ret=Rs}, Le, St) ->
+ internal_cg(Name, As, Rs, Le, St);
+bif_cg(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}},
+ args=As,ret=Rs}, Le, St) ->
+ bif_cg(Name, As, Rs, Le, St).
+
+%% internal_cg(Bif, [Arg], [Ret], Le, State) ->
+%% {[Ainstr],State}.
+
+internal_cg(dsetelement, [Index0,Tuple0,New0], _Rs, _Le, St) ->
+ [New,Tuple,#b_literal{val=Index1}] = ssa_args([New0,Tuple0,Index0], St),
+ Index = #b_literal{val=Index1-1},
+ Set = #b_set{op=set_tuple_element,args=[New,Tuple,Index]},
+ {[Set],St};
+internal_cg(make_fun, [Name0,Arity0|As], Rs, _Le, St0) ->
+ #k_atom{val=Name} = Name0,
+ #k_int{val=Arity} = Arity0,
+ [#k_var{name=Dst0}] = Rs,
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Local = #b_local{name=#b_literal{val=Name},arity=Arity},
+ MakeFun = #b_set{op=make_fun,dst=Dst,args=[Local|Args]},
+ {[MakeFun],St};
+internal_cg(bs_init_writable=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ %% This behaves like a function call.
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St};
+internal_cg(build_stacktrace=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St};
+internal_cg(raise, As, [#k_var{name=Dst0}], _Le, St0) ->
+ Args = ssa_args(As, St0),
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Resume = #b_set{op=resume,dst=Dst,args=Args},
+ case St of
+ #cg{catch_label=none} ->
+ {[Resume],St};
+ #cg{catch_label=Catch} when is_integer(Catch) ->
+ Is = [Resume,make_uncond_branch(Catch),#cg_unreachable{}],
+ {Is,St}
+ end;
+internal_cg(raw_raise=I, As, [#k_var{name=Dst0}], _Le, St0) ->
+ %% This behaves like a function call.
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Set = #b_set{op=I,dst=Dst,args=Args},
+ {[Set],St}.
+
+bif_cg(Bif, As0, [#k_var{name=Dst0}], Le, St0) ->
+ {Dst,St1} = new_ssa_var(Dst0, St0),
+ case {Bif,ssa_args(As0, St0)} of
+ {is_record,[Tuple,#b_literal{val=Atom}=Tag,
+ #b_literal{val=Int}=Arity]}
+ when is_atom(Atom), is_integer(Int) ->
+ bif_is_record_cg(Dst, Tuple, Tag, Arity, St1);
+ {_,As} ->
+ I = #b_set{anno=line_anno(Le),op={bif,Bif},dst=Dst,args=As},
+ case erl_bifs:is_safe(erlang, Bif, length(As)) of
+ false ->
+ Fail = bif_fail_label(St1),
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {[I|Is],St};
+ true->
+ {[I],St1}
+ end
+ end.
+
+bif_is_record_cg(Dst, Tuple, TagVal, ArityVal, St0) ->
+ {Arity,St1} = new_ssa_var('@ssa_arity', St0),
+ {Tag,St2} = new_ssa_var('@ssa_tag', St1),
+ {Phi,St3} = new_label(St2),
+ {False,St4} = new_label(St3),
+ {Is0,St5} = make_cond_branch({bif,is_tuple}, [Tuple], False, St4),
+ GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
+ {Is1,St6} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], False, St5),
+ GetTag = #b_set{op=get_tuple_element,dst=Tag,
+ args=[Tuple,#b_literal{val=0}]},
+ {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], False, St6),
+ Is3 = [#cg_break{args=[#b_literal{val=true}],phi=Phi},
+ {label,False},
+ #cg_break{args=[#b_literal{val=false}],phi=Phi},
+ {label,Phi},
+ #cg_phi{vars=[Dst]}],
+ Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2 ++ Is3,
+ {Is,St}.
+
+%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs,
+%% [Ret], Le, St) -> {[Ainstr],St}.
+
+recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, St0) ->
+ %% Get labels.
+ {Rl,St1} = new_label(St0),
+ {Tl,St2} = new_label(St1),
+ {Bl,St3} = new_label(St2),
+ St4 = St3#cg{break=Bl,recv=Rl},
+ {Ris,St5} = cg_recv_mesg(Rvar, Rm, Tl, Le, St4),
+ {Wis,St6} = cg_recv_wait(Te, Tes, St5),
+ {BreakVars,St} = new_ssa_vars(Rs, St6),
+ {Ris ++ [{label,Tl}] ++ Wis ++
+ [{label,Bl},#cg_phi{vars=BreakVars}],
+ St#cg{break=St0#cg.break,recv=St0#cg.recv}}.
+
+%% cg_recv_mesg( ) -> {[Ainstr],St}.
+
+cg_recv_mesg(#k_var{name=R}, Rm, Tl, Le, St0) ->
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Mis,St2} = match_cg(Rm, none, St1),
+ RecvLbl = St1#cg.recv,
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Tl, St2),
+ Is = [#b_br{anno=line_anno(Le),bool=#b_literal{val=true},
+ succ=RecvLbl,fail=RecvLbl},
+ {label,RecvLbl},
+ #b_set{op=peek_message,dst=Dst}|TestIs],
+ {Is++Mis,St}.
+
+%% cg_recv_wait(Te, Tes, St) -> {[Ainstr],St}.
+
+cg_recv_wait(#k_int{val=0}, Es, St0) ->
+ {Tis,St} = cg(Es, St0),
+ {[#b_set{op=timeout}|Tis],St};
+cg_recv_wait(Te, Es, St0) ->
+ {Tis,St1} = cg(Es, St0),
+ Args = [ssa_arg(Te, St1)],
+ {WaitDst,St2} = new_ssa_var('@ssa_wait', St1),
+ {WaitIs,St} = make_cond_branch(succeeded, [WaitDst], St1#cg.recv, St2),
+ %% Infinite timeout will be optimized later.
+ Is = [#b_set{op=wait_timeout,dst=WaitDst,args=Args}] ++ WaitIs ++
+ [#b_set{op=timeout}] ++ Tis,
+ {Is,St}.
+
+%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret], St) ->
+%% {[Ainstr],St}.
+
+try_cg(Ta, Vs, Tb, Evs, Th, Rs, St0) ->
+ {B,St1} = new_label(St0), %Body label
+ {H,St2} = new_label(St1), %Handler label
+ {E,St3} = new_label(St2), %End label
+ {Next,St4} = new_label(St3),
+ {TryTag,St5} = new_ssa_var('@ssa_catch_tag', St4),
+ {SsaVs,St6} = new_ssa_vars(Vs, St5),
+ {SsaEvs,St7} = new_ssa_vars(Evs, St6),
+ {Ais,St8} = cg(Ta, St7#cg{break=B,catch_label=H}),
+ St9 = St8#cg{break=E,catch_label=St7#cg.catch_label},
+ {Bis,St10} = cg(Tb, St9),
+ {His,St11} = cg(Th, St10),
+ {BreakVars,St12} = new_ssa_vars(Rs, St11),
+ {CatchedAgg,St} = new_ssa_var('@ssa_agg', St12),
+ ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
+ KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
+ Args = [#b_literal{val='try'},TryTag],
+ Handler = [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
+ ExtractVs ++ [KillTryTag],
+ {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
+ #b_br{bool=TryTag,succ=Next,fail=H},
+ {label,Next}] ++ Ais ++
+ [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
+ Handler ++ His ++
+ [{label,E},#cg_phi{vars=BreakVars}],
+ St#cg{break=St0#cg.break}}.
+
+try_enter_cg(Ta, Vs, Tb, Evs, Th, St0) ->
+ {B,St1} = new_label(St0), %Body label
+ {H,St2} = new_label(St1), %Handler label
+ {Next,St3} = new_label(St2),
+ {TryTag,St4} = new_ssa_var('@ssa_catch_tag', St3),
+ {SsaVs,St5} = new_ssa_vars(Vs, St4),
+ {SsaEvs,St6} = new_ssa_vars(Evs, St5),
+ {Ais,St7} = cg(Ta, St6#cg{break=B,catch_label=H}),
+ St8 = St7#cg{catch_label=St6#cg.catch_label},
+ {Bis,St9} = cg(Tb, St8),
+ {His,St10} = cg(Th, St9),
+ {CatchedAgg,St} = new_ssa_var('@ssa_agg', St10),
+ ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
+ KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
+ Args = [#b_literal{val='try'},TryTag],
+ Handler = [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
+ ExtractVs ++ [KillTryTag],
+ {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
+ #b_br{bool=TryTag,succ=Next,fail=H},
+ {label,Next}] ++ Ais ++
+ [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
+ Handler ++ His,
+ St#cg{break=St0#cg.break}}.
+
+extract_vars([V|Vs], Agg, N) ->
+ I = #b_set{op=extract,dst=V,args=[Agg,#b_literal{val=N}]},
+ [I|extract_vars(Vs, Agg, N+1)];
+extract_vars([], _, _) -> [].
+
+%% do_catch_cg(CatchBlock, Ret, St) -> {[Ainstr],St}.
+
+do_catch_cg(Block, #k_var{name=R}, St0) ->
+ {B,St1} = new_label(St0),
+ {Next,St2} = new_label(St1),
+ {H,St3} = new_label(St2),
+ {CatchReg,St4} = new_ssa_var('@ssa_catch_tag', St3),
+ {Dst,St5} = new_ssa_var(R, St4),
+ {Succ,St6} = new_label(St5),
+ {Cis,St7} = cg(Block, St6#cg{break=Succ,catch_label=H}),
+ {CatchedVal,St8} = new_ssa_var('@catched_val', St7),
+ {SuccVal,St9} = new_ssa_var('@success_val', St8),
+ {CatchedAgg,St10} = new_ssa_var('@ssa_agg', St9),
+ {CatchEndVal,St} = new_ssa_var('@catch_end_val', St10),
+ Args = [#b_literal{val='catch'},CatchReg],
+ {[#b_set{op=new_try_tag,dst=CatchReg,args=[#b_literal{val='catch'}]},
+ #b_br{bool=CatchReg,succ=Next,fail=H},
+ {label,Next}] ++ Cis ++
+ [{label,H},
+ #b_set{op=landingpad,dst=CatchedAgg,args=Args},
+ #b_set{op=extract,dst=CatchedVal,
+ args=[CatchedAgg,#b_literal{val=0}]},
+ #cg_break{args=[CatchedVal],phi=B},
+ {label,Succ},
+ #cg_phi{vars=[SuccVal]},
+ #cg_break{args=[SuccVal],phi=B},
+ {label,B},#cg_phi{vars=[CatchEndVal]},
+ #b_set{op=catch_end,dst=Dst,args=[CatchReg,CatchEndVal]}],
+ St#cg{break=St1#cg.break,catch_label=St1#cg.catch_label}}.
+
+%% put_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],St}.
+%% Generate code for constructing terms.
+
+put_cg([#k_var{name=R}], #k_cons{hd=Hd,tl=Tl}, _Le, St0) ->
+ Args = ssa_args([Hd,Tl], St0),
+ {Dst,St} = new_ssa_var(R, St0),
+ PutList = #b_set{op=put_list,dst=Dst,args=Args},
+ {[PutList],St};
+put_cg([#k_var{name=R}], #k_tuple{es=Es}, _Le, St0) ->
+ {Ret,St} = new_ssa_var(R, St0),
+ Args = ssa_args(Es, St),
+ PutTuple = #b_set{op=put_tuple,dst=Ret,args=Args},
+ {[PutTuple],St};
+put_cg([#k_var{name=R}], #k_binary{segs=Segs}, Le, St0) ->
+ Fail = bif_fail_label(St0),
+ {Dst,St1} = new_ssa_var(R, St0),
+ cg_binary(Dst, Segs, Fail, Le, St1);
+put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,
+ es=[#k_map_pair{key=#k_var{}=K,val=V}]},
+ Le, St0) ->
+ %% Map: single variable key.
+ SrcMap = ssa_arg(Map, St0),
+ LineAnno = line_anno(Le),
+ List = [ssa_arg(K, St0),ssa_arg(V, St0)],
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
+ {Is,St};
+put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,es=Es}, Le, St0) ->
+ %% Map: one or more literal keys.
+ [] = [Var || #k_map_pair{key=#k_var{}=Var} <- Es], %Assertion
+ SrcMap = ssa_arg(Map, St0),
+ LineAnno = line_anno(Le),
+ List = flatmap(fun(#k_map_pair{key=K,val=V}) ->
+ [ssa_arg(K, St0),ssa_arg(V, St0)]
+ end, Es),
+ {Dst,St1} = new_ssa_var(R, St0),
+ {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
+ {Is,St};
+put_cg([#k_var{name=R}], Con0, _Le, St0) ->
+ %% Create an alias for a variable or literal.
+ Con = ssa_arg(Con0, St0),
+ St = set_ssa_var(R, Con, St0),
+ {[],St}.
+
+put_cg_map(LineAnno, Op, SrcMap, Dst, List, St0) ->
+ Fail = bif_fail_label(St0),
+ Args = [#b_literal{val=Op},SrcMap|List],
+ PutMap = #b_set{anno=LineAnno,op=put_map,dst=Dst,args=Args},
+ if
+ Op =:= assoc ->
+ {[PutMap],St0};
+ true ->
+ {Is,St} = make_cond_branch(succeeded, [Dst], Fail, St0),
+ {[PutMap|Is],St}
+ end.
+
+%%%
+%%% Code generation for constructing binaries.
+%%%
+
+cg_binary(Dst, Segs0, Fail, Le, St0) ->
+ {PutCode0,SzCalc0,St1} = cg_bin_put(Segs0, Fail, St0),
+ LineAnno = line_anno(Le),
+ Anno = Le#k.a,
+ case PutCode0 of
+ [#b_set{op=bs_put,dst=Bool,args=[_,_,Src,#b_literal{val=all}|_]},
+ #b_br{bool=Bool},
+ {label,_}|_] ->
+ #k_bin_seg{unit=Unit0,next=Segs} = Segs0,
+ Unit = #b_literal{val=Unit0},
+ {PutCode,SzCalc1,St2} = cg_bin_put(Segs, Fail, St1),
+ {_,SzVar,SzCode0,St3} = cg_size_calc(1, SzCalc1, Fail, St2),
+ SzCode = cg_bin_anno(SzCode0, LineAnno),
+ Args = case member(single_use, Anno) of
+ true ->
+ [#b_literal{val=private_append},Src,SzVar,Unit];
+ false ->
+ [#b_literal{val=append},Src,SzVar,Unit]
+ end,
+ BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St3),
+ {SzCode ++ [BsInit] ++ TestIs ++ PutCode,St};
+ [#b_set{op=bs_put}|_] ->
+ {Unit,SzVar,SzCode0,St2} = cg_size_calc(8, SzCalc0, Fail, St1),
+ SzCode = cg_bin_anno(SzCode0, LineAnno),
+ Args = [#b_literal{val=new},SzVar,Unit],
+ BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St2),
+ {SzCode ++ [BsInit] ++ TestIs ++ PutCode0,St}
+ end.
+
+cg_bin_anno([Set|Sets], Anno) ->
+ [Set#b_set{anno=Anno}|Sets];
+cg_bin_anno([], _) -> [].
+
+%% cg_size_calc(PreferredUnit, SzCalc, Fail, St0) ->
+%% {ActualUnit,SizeVariable,SizeCode,St}.
+%% Generate size calculation code.
+
+cg_size_calc(Unit, error, _Fail, St) ->
+ {#b_literal{val=Unit},#b_literal{val=badarg},[],St};
+cg_size_calc(8, [{1,_}|_]=SzCalc, Fail, St) ->
+ cg_size_calc(1, SzCalc, Fail, St);
+cg_size_calc(8, SzCalc, Fail, St0) ->
+ {Var,Pre,St} = cg_size_calc_1(SzCalc, Fail, St0),
+ {#b_literal{val=8},Var,Pre,St};
+cg_size_calc(1, SzCalc0, Fail, St0) ->
+ SzCalc = map(fun({8,#b_literal{val=Size}}) ->
+ {1,#b_literal{val=8*Size}};
+ ({8,{{bif,byte_size},Src}}) ->
+ {1,{{bif,bit_size},Src}};
+ ({8,{_,_}=UtfCalc}) ->
+ {1,{'*',#b_literal{val=8},UtfCalc}};
+ ({_,_}=Pair) ->
+ Pair
+ end, SzCalc0),
+ {Var,Pre,St} = cg_size_calc_1(SzCalc, Fail, St0),
+ {#b_literal{val=1},Var,Pre,St}.
+
+cg_size_calc_1(SzCalc, Fail, St0) ->
+ cg_size_calc_2(SzCalc, #b_literal{val=0}, Fail, St0).
+
+cg_size_calc_2([{_,{'*',Unit,{_,_}=Bif}}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {BifDst,Pre1,St2} = cg_size_bif(Bif, Fail, St1),
+ {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, Unit, Fail, St2),
+ {Sum,Pre0++Pre1++Pre2,St};
+cg_size_calc_2([{_,#b_literal{}=Sz}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, Fail, St1),
+ {Sum,Pre0++Pre,St};
+cg_size_calc_2([{_,#b_var{}=Sz}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, Fail, St1),
+ {Sum,Pre0++Pre,St};
+cg_size_calc_2([{_,{_,_}=Bif}|T], Sum0, Fail, St0) ->
+ {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, Fail, St0),
+ {BifDst,Pre1,St2} = cg_size_bif(Bif, Fail, St1),
+ {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, #b_literal{val=1}, Fail, St2),
+ {Sum,Pre0++Pre1++Pre2,St};
+cg_size_calc_2([], Sum, _Fail, St) ->
+ {Sum,[],St}.
+
+cg_size_bif(#b_var{}=Var, _Fail, St) ->
+ {Var,[],St};
+cg_size_bif({Name,Src}, Fail, St0) ->
+ {Dst,St1} = new_ssa_var('@ssa_bif', St0),
+ Bif = #b_set{op=Name,dst=Dst,args=[Src]},
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ {Dst,[Bif|TestIs],St}.
+
+cg_size_add(#b_literal{val=0}, Val, #b_literal{val=1}, _Fail, St) ->
+ {Val,[],St};
+cg_size_add(A, B, Unit, Fail, St0) ->
+ {Dst,St1} = new_ssa_var('@ssa_sum', St0),
+ {TestIs,St} = make_cond_branch(succeeded, [Dst], Fail, St1),
+ BsAdd = #b_set{op=bs_add,dst=Dst,args=[A,B,Unit]},
+ {Dst,[BsAdd|TestIs],St}.
+
+cg_bin_put(Seg, Fail, St) ->
+ cg_bin_put_1(Seg, Fail, [], [], St).
+
+cg_bin_put_1(#k_bin_seg{size=Size0,unit=U,type=T,flags=Fs,seg=Src0,next=Next},
+ Fail, Acc, SzCalcAcc, St0) ->
+ [Src,Size] = ssa_args([Src0,Size0], St0),
+ NeedSize = bs_need_size(T),
+ TypeArg = #b_literal{val=T},
+ Flags = #b_literal{val=Fs},
+ Unit = #b_literal{val=U},
+ Args = case NeedSize of
+ true -> [TypeArg,Flags,Src,Size,Unit];
+ false -> [TypeArg,Flags,Src]
+ end,
+ {Is,St} = make_cond_branch(bs_put, Args, Fail, St0),
+ SzCalc = bin_size_calc(T, Src, Size, U),
+ cg_bin_put_1(Next, Fail, reverse(Is, Acc), [SzCalc|SzCalcAcc], St);
+cg_bin_put_1(#k_bin_end{}, _, Acc, SzCalcAcc, St) ->
+ SzCalc = fold_size_calc(SzCalcAcc, 0, []),
+ {reverse(Acc),SzCalc,St}.
+
+bs_need_size(utf8) -> false;
+bs_need_size(utf16) -> false;
+bs_need_size(utf32) -> false;
+bs_need_size(_) -> true.
+
+bin_size_calc(utf8, Src, _Size, _Unit) ->
+ {8,{bs_utf8_size,Src}};
+bin_size_calc(utf16, Src, _Size, _Unit) ->
+ {8,{bs_utf16_size,Src}};
+bin_size_calc(utf32, _Src, _Size, _Unit) ->
+ {8,#b_literal{val=4}};
+bin_size_calc(binary, Src, #b_literal{val=all}, Unit) ->
+ case Unit rem 8 of
+ 0 -> {8,{{bif,byte_size},Src}};
+ _ -> {1,{{bif,bit_size},Src}}
+ end;
+bin_size_calc(_Type, _Src, Size, Unit) ->
+ {Unit,Size}.
+
+fold_size_calc([{Unit,#b_literal{val=Size}}|T], Bits, Acc) ->
+ if
+ is_integer(Size) ->
+ fold_size_calc(T, Bits + Unit*Size, Acc);
+ true ->
+ error
+ end;
+fold_size_calc([{U,#b_var{}}=H|T], Bits, Acc) when U =:= 1; U =:= 8 ->
+ fold_size_calc(T, Bits, [H|Acc]);
+fold_size_calc([{U,#b_var{}=Var}|T], Bits, Acc) ->
+ fold_size_calc(T, Bits, [{1,{'*',#b_literal{val=U},Var}}|Acc]);
+fold_size_calc([{_,_}=H|T], Bits, Acc) ->
+ fold_size_calc(T, Bits, [H|Acc]);
+fold_size_calc([], Bits, Acc) ->
+ Bytes = Bits div 8,
+ RemBits = Bits rem 8,
+ Sizes = sort([{1,#b_literal{val=RemBits}},{8,#b_literal{val=Bytes}}|Acc]),
+ [Pair || {_,Sz}=Pair <- Sizes, Sz =/= #b_literal{val=0}].
+
+%%%
+%%% Utilities for creating the SSA types.
+%%%
+
+ssa_args(As, St) ->
+ [ssa_arg(A, St) || A <- As].
+
+ssa_arg(#k_var{name=V}, #cg{vars=Vars}) -> maps:get(V, Vars);
+ssa_arg(#k_literal{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_atom{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_float{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_int{val=V}, _) -> #b_literal{val=V};
+ssa_arg(#k_nil{}, _) -> #b_literal{val=[]}.
+
+new_ssa_vars(Vs, St) ->
+ mapfoldl(fun(#k_var{name=V}, S) ->
+ new_ssa_var(V, S)
+ end, St, Vs).
+
+new_ssa_var(VarBase, #cg{lcount=Uniq,vars=Vars}=St0)
+ when is_atom(VarBase); is_integer(VarBase) ->
+ case Vars of
+ #{VarBase:=_} ->
+ Var = #b_var{name={VarBase,Uniq}},
+ St = St0#cg{lcount=Uniq+1,vars=Vars#{VarBase=>Var}},
+ {Var,St};
+ #{} ->
+ Var = #b_var{name=VarBase},
+ St = St0#cg{vars=Vars#{VarBase=>Var}},
+ {Var,St}
+ end.
+
+set_ssa_var(VarBase, Val, #cg{vars=Vars}=St)
+ when is_atom(VarBase); is_integer(VarBase) ->
+ St#cg{vars=Vars#{VarBase=>Val}}.
+
+%% new_label(St) -> {L,St}.
+
+new_label(#cg{lcount=Next}=St) ->
+ {Next,St#cg{lcount=Next+1}}.
+
+%% line_anno(Le) -> #{} | #{location:={File,Line}}.
+%% Create a location annotation, containing information about the
+%% current filename and line number. The annotation should be
+%% included in any operation that could cause an exception.
+
+line_anno(#k{a=Anno}) ->
+ line_anno_1(Anno).
+
+line_anno_1([Line,{file,Name}]) when is_integer(Line) ->
+ line_anno_2(Name, Line);
+line_anno_1([_|_]=A) ->
+ {Name,Line} = find_loc(A, no_file, 0),
+ line_anno_2(Name, Line);
+line_anno_1([]) ->
+ #{}.
+
+line_anno_2(no_file, _) ->
+ #{};
+line_anno_2(_, 0) ->
+ %% Missing line number or line number 0.
+ #{};
+line_anno_2(Name, Line) ->
+ #{location=>{Name,Line}}.
+
+find_loc([Line|T], File, _) when is_integer(Line) ->
+ find_loc(T, File, Line);
+find_loc([{file,File}|T], _, Line) ->
+ find_loc(T, File, Line);
+find_loc([_|T], File, Line) ->
+ find_loc(T, File, Line);
+find_loc([], File, Line) -> {File,Line}.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
+
+%%%
+%%% Finalize the code.
+%%%
+
+finalize(Asm0, St0) ->
+ Asm1 = fix_phis(Asm0),
+ {Asm,St} = fix_sets(Asm1, [], St0),
+ {build_map(Asm),St}.
+
+fix_phis(Is) ->
+ fix_phis_1(Is, none, #{}).
+
+fix_phis_1([{label,L},#cg_phi{vars=[]}=Phi|Is0], _Lbl, Map0) ->
+ case maps:is_key(L, Map0) of
+ false ->
+ %% No #cg_break{} references this label. Nothing else can
+ %% reference it, so it can be safely be removed.
+ {Is,Map} = drop_upto_label(Is0, Map0),
+ fix_phis_1(Is, none, Map);
+ true ->
+ %% There is a break referencing this label; probably caused
+ %% by a try/catch whose return value is ignored.
+ [{label,L}|fix_phis_1([Phi|Is0], L, Map0)]
+ end;
+fix_phis_1([{label,L}=I|Is], _Lbl, Map) ->
+ [I|fix_phis_1(Is, L, Map)];
+fix_phis_1([#cg_unreachable{}|Is0], _Lbl, Map0) ->
+ {Is,Map} = drop_upto_label(Is0, Map0),
+ fix_phis_1(Is, none, Map);
+fix_phis_1([#cg_break{args=Args,phi=Target}|Is], Lbl, Map) when is_integer(Lbl) ->
+ Pairs1 = case Map of
+ #{Target:=Pairs0} -> Pairs0;
+ #{} -> []
+ end,
+ Pairs = [[{Arg,Lbl} || Arg <- Args]|Pairs1],
+ I = make_uncond_branch(Target),
+ [I|fix_phis_1(Is, none, Map#{Target=>Pairs})];
+fix_phis_1([#cg_phi{vars=Vars}|Is0], Lbl, Map0) ->
+ Pairs = maps:get(Lbl, Map0),
+ Map1 = maps:remove(Lbl, Map0),
+ case gen_phis(Vars, Pairs) of
+ [#b_set{op=phi,args=[]}] ->
+ {Is,Map} = drop_upto_label(Is0, Map1),
+ Ret = #b_ret{arg=#b_literal{val=unreachable}},
+ [Ret|fix_phis_1(Is, none, Map)];
+ Phis ->
+ Phis ++ fix_phis_1(Is0, Lbl, Map1)
+ end;
+fix_phis_1([I|Is], Lbl, Map) ->
+ [I|fix_phis_1(Is, Lbl, Map)];
+fix_phis_1([], _, Map) ->
+ [] = maps:to_list(Map), %Assertion.
+ [].
+
+gen_phis([V|Vs], Preds0) ->
+ {Pairs,Preds} = collect_preds(Preds0, [], []),
+ [#b_set{op=phi,dst=V,args=Pairs}|gen_phis(Vs, Preds)];
+gen_phis([], _) -> [].
+
+collect_preds([[First|Rest]|T], ColAcc, RestAcc) ->
+ collect_preds(T, [First|ColAcc], [Rest|RestAcc]);
+collect_preds([], ColAcc, RestAcc) ->
+ {keysort(2, ColAcc),RestAcc}.
+
+fix_sets([#b_set{dst=none}=Set|Is], Acc, St0) ->
+ {Dst,St} = new_ssa_var('@ssa_ignored', St0),
+ I = Set#b_set{dst=Dst},
+ fix_sets(Is, [I|Acc], St);
+fix_sets([I|Is], Acc, St) ->
+ fix_sets(Is, [I|Acc], St);
+fix_sets([], Acc, St) ->
+ {reverse(Acc),St}.
+
+build_map(Is) ->
+ Blocks = build_graph_1(Is, [], []),
+ maps:from_list(Blocks).
+
+build_graph_1([{label,L}|Is], Lbls, []) ->
+ build_graph_1(Is, [L|Lbls], []);
+build_graph_1([{label,L}|Is], Lbls, [_|_]=BlockAcc) ->
+ make_blocks(Lbls, BlockAcc) ++ build_graph_1(Is, [L], []);
+build_graph_1([I|Is], Lbls, BlockAcc) ->
+ build_graph_1(Is, Lbls, [I|BlockAcc]);
+build_graph_1([], Lbls, BlockAcc) ->
+ make_blocks(Lbls, BlockAcc).
+
+make_blocks(Lbls, [Last|Is0]) ->
+ Is = reverse(Is0),
+ Block = #b_blk{is=Is,last=Last},
+ [{L,Block} || L <- Lbls].
+
+drop_upto_label([{label,_}|_]=Is, Map) ->
+ {Is,Map};
+drop_upto_label([#cg_break{phi=Target}|Is], Map) ->
+ Pairs = case Map of
+ #{Target:=Pairs0} -> Pairs0;
+ #{} -> []
+ end,
+ drop_upto_label(Is, Map#{Target=>Pairs});
+drop_upto_label([_|Is], Map) ->
+ drop_upto_label(Is, Map).
+
+k_get_anno(Thing) -> element(2, Thing).
diff --git a/lib/compiler/src/beam_listing.erl b/lib/compiler/src/beam_listing.erl
index 518b958794..6121593b11 100644
--- a/lib/compiler/src/beam_listing.erl
+++ b/lib/compiler/src/beam_listing.erl
@@ -23,6 +23,7 @@
-include("core_parse.hrl").
-include("v3_kernel.hrl").
+-include("beam_ssa.hrl").
-include("beam_disasm.hrl").
-import(lists, [foreach/2]).
@@ -41,6 +42,12 @@ module(File, #k_mdef{}=Kern) ->
%% This is a kernel module.
io:put_chars(File, v3_kernel_pp:format(Kern));
%%io:put_chars(File, io_lib:format("~p~n", [Kern]));
+module(File, #b_module{name=Mod,exports=Exp,attributes=Attr,body=Fs}) ->
+ io:format(File, "module ~p.\n", [Mod]),
+ io:format(File, "exports ~p.\n", [Exp]),
+ io:format(File, "attributes ~p.\n\n", [Attr]),
+ PP = [beam_ssa_pp:format_function(F) || F <- Fs],
+ io:put_chars(File, lists:join($\n, PP));
module(Stream, {Mod,Exp,Attr,Code,NumLabels}) ->
%% This is output from v3_codegen.
io:format(Stream, "{module, ~p}. %% version = ~w\n",
@@ -59,7 +66,7 @@ module(Stream, [_|_]=Fs) ->
foreach(fun (F) -> io:format(Stream, "~p.\n", [F]) end, Fs).
format_asm([{label,L}|Is]) ->
- [" {label,",integer_to_list(L),"}.\n"|format_asm(Is)];
+ [io_lib:format(" {label,~p}.\n", [L])|format_asm(Is)];
format_asm([I|Is]) ->
[io_lib:format(" ~p", [I]),".\n"|format_asm(Is)];
format_asm([]) -> [].
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index 2b8dd40e29..2323a439e9 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -101,31 +101,40 @@ peep([{select,Op,R,F,Vls0}|Is], SeenTests0, Acc0) ->
I = {jump,F},
peep([I|Is], gb_sets:empty(), Acc0);
[{atom,_}=Value,Lbl] when Op =:= select_val ->
- %% Single value left. Convert to regular test and pop redundant tests.
+ %% Single value left. Convert to regular test.
Is1 = [{test,is_eq_exact,F,[R,Value]},{jump,Lbl}|Is],
- case Acc0 of
- [{test,is_atom,F,[R]}|Acc] ->
- peep(Is1, SeenTests0, Acc);
- _ ->
- peep(Is1, SeenTests0, Acc0)
- end;
+ peep(Is1, SeenTests0, Acc0);
[{integer,_}=Value,Lbl] when Op =:= select_val ->
- %% Single value left. Convert to regular test and pop redundant tests.
+ %% Single value left. Convert to regular test.
Is1 = [{test,is_eq_exact,F,[R,Value]},{jump,Lbl}|Is],
- case Acc0 of
- [{test,is_integer,F,[R]}|Acc] ->
- peep(Is1, SeenTests0, Acc);
- _ ->
- peep(Is1, SeenTests0, Acc0)
- end;
+ peep(Is1, SeenTests0, Acc0);
[Arity,Lbl] when Op =:= select_tuple_arity ->
%% Single value left. Convert to regular test
Is1 = [{test,test_arity,F,[R,Arity]},{jump,Lbl}|Is],
peep(Is1, SeenTests0, Acc0);
+ [{atom,B1},Lbl,{atom,B2},Lbl] when B1 =:= not B2 ->
+ %% Replace with is_boolean test.
+ Is1 = [{test,is_boolean,F,[R]},{jump,Lbl}|Is],
+ peep(Is1, SeenTests0, Acc0);
[_|_]=Vls ->
I = {select,Op,R,F,Vls},
peep(Is, gb_sets:empty(), [I|Acc0])
end;
+peep([{get_map_elements,Fail,Src,List}=I|Is], _SeenTests, Acc0) ->
+ SeenTests = gb_sets:empty(),
+ case simplify_get_map_elements(Fail, Src, List, Acc0) of
+ {ok,Acc} ->
+ peep(Is, SeenTests, Acc);
+ error ->
+ peep(Is, SeenTests, [I|Acc0])
+ end;
+peep([{test,has_map_fields,Fail,Ops}=I|Is], SeenTests, Acc0) ->
+ case simplify_has_map_fields(Fail, Ops, Acc0) of
+ {ok,Acc} ->
+ peep(Is, SeenTests, Acc);
+ error ->
+ peep(Is, SeenTests, [I|Acc0])
+ end;
peep([{test,Op,_,Ops}=I|Is], SeenTests0, Acc) ->
case beam_utils:is_pure_test(I) of
false ->
@@ -176,3 +185,39 @@ prune_redundant_values([_Val,F|Vls], F) ->
prune_redundant_values([Val,Lbl|Vls], F) ->
[Val,Lbl|prune_redundant_values(Vls, F)];
prune_redundant_values([], _) -> [].
+
+simplify_get_map_elements(Fail, Src, {list,[Key,Dst]},
+ [{get_map_elements,Fail,Src,{list,List1}}|Acc]) ->
+ case are_keys_literals([Key]) andalso are_keys_literals(List1) of
+ true ->
+ case member(Key, List1) of
+ true ->
+ %% The key is already in the other list. That is
+ %% very unusual, because there are optimizations to get
+ %% rid of duplicate keys. Therefore, don't try to
+ %% do anything smart here; just keep the
+ %% get_map_elements instructions separate.
+ error;
+ false ->
+ List = [Key,Dst|List1],
+ {ok,[{get_map_elements,Fail,Src,{list,List}}|Acc]}
+ end;
+ false ->
+ error
+ end;
+simplify_get_map_elements(_, _, _, _) -> error.
+
+simplify_has_map_fields(Fail, [Src|Keys0],
+ [{test,has_map_fields,Fail,[Src|Keys1]}|Acc]) ->
+ case are_keys_literals(Keys0) andalso are_keys_literals(Keys1) of
+ true ->
+ Keys = Keys0 ++ Keys1,
+ {ok,[{test,has_map_fields,Fail,[Src|Keys]}|Acc]};
+ false ->
+ error
+ end;
+simplify_has_map_fields(_, _, _) -> error.
+
+are_keys_literals([{x,_}|_]) -> false;
+are_keys_literals([{y,_}|_]) -> false;
+are_keys_literals([_|_]) -> true.
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
deleted file mode 100644
index ddbe67605a..0000000000
--- a/lib/compiler/src/beam_receive.erl
+++ /dev/null
@@ -1,416 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_receive).
--export([module/2]).
--import(lists, [foldl/3,reverse/1,reverse/2]).
-
-%%%
-%%% In code such as:
-%%%
-%%% Ref = make_ref(), %Or erlang:monitor(process, Pid)
-%%% .
-%%% .
-%%% .
-%%% receive
-%%% {Ref,Reply} -> Reply
-%%% end.
-%%%
-%%% we know that none of the messages that exist in the message queue
-%%% before the call to make_ref/0 can be matched out in the receive
-%%% statement. Therefore we can avoid going through the entire message
-%%% queue if we introduce two new instructions (here written as
-%%% BIFs in pseudo-Erlang):
-%%%
-%%% recv_mark(SomeUniqInteger),
-%%% Ref = make_ref(),
-%%% .
-%%% .
-%%% .
-%%% recv_set(SomeUniqInteger),
-%%% receive
-%%% {Ref,Reply} -> Reply
-%%% end.
-%%%
-%%% The recv_mark/1 instruction will save the current position and
-%%% SomeUniqInteger in the process context. The recv_set
-%%% instruction will verify that SomeUniqInteger is still stored
-%%% in the process context. If it is, it will set the current pointer
-%%% for the message queue (the next message to be read out) to the
-%%% position that was saved by recv_mark/1.
-%%%
-%%% The remove_message instruction must be modified to invalidate
-%%% the information stored by the previous recv_mark/1, in case there
-%%% is another receive executed between the calls to recv_mark/1 and
-%%% recv_set/1.
-%%%
-%%% We use a reference to a label (i.e. a position in the loaded code)
-%%% as the SomeUniqInteger.
-%%%
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [function(F) || F <- Fs0],
- Code = {Mod,Exp,Attr,Fs,Lc},
- {ok,Code}.
-
-%%%
-%%% Local functions.
-%%%
-
-function({function,Name,Arity,Entry,Is}) ->
- try
- D = beam_utils:index_labels(Is),
- {function,Name,Arity,Entry,opt(Is, D, [])}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-opt([{call_ext,A,{extfunc,erlang,spawn_monitor,A}}=I0|Is0], D, Acc)
- when A =:= 1; A =:= 3 ->
- case ref_in_tuple(Is0) of
- no ->
- opt(Is0, D, [I0|Acc]);
- {yes,Regs,Is1,MatchReversed} ->
- %% The call creates a brand new reference. Now
- %% search for a receive statement in the same
- %% function that will match against the reference.
- case opt_recv(Is1, Regs, D) of
- no ->
- opt(Is0, D, [I0|Acc]);
- {yes,Is,Lbl} ->
- opt(Is, D, MatchReversed++[I0,{recv_mark,{f,Lbl}}|Acc])
- end
- end;
-opt([{call_ext,Arity,{extfunc,erlang,Name,Arity}}=I|Is0], D, Acc) ->
- case creates_new_ref(Name, Arity) of
- true ->
- %% The call creates a brand new reference. Now
- %% search for a receive statement in the same
- %% function that will match against the reference.
- case opt_recv(Is0, regs_init_x0(), D) of
- no ->
- opt(Is0, D, [I|Acc]);
- {yes,Is,Lbl} ->
- opt(Is, D, [I,{recv_mark,{f,Lbl}}|Acc])
- end;
- false ->
- opt(Is0, D, [I|Acc])
- end;
-opt([I|Is], D, Acc) ->
- opt(Is, D, [I|Acc]);
-opt([], _, Acc) ->
- reverse(Acc).
-
-ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
- {test,test_arity,_,[{x,0},2]}=I2,
- {block,[{set,[_],[{x,0}],{get_tuple_element,0}},
- {set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
- ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
-ref_in_tuple([{test,is_tuple,_,[{x,0}]}=I1,
- {test,test_arity,_,[{x,0},2]}=I2,
- {block,[{set,[Dst],[{x,0}],{get_tuple_element,1}}|Bl]}=I3|Is]) ->
- ref_in_tuple_1(Bl, Dst, Is, [I3,I2,I1]);
-ref_in_tuple(_) -> no.
-
-ref_in_tuple_1(Bl, Dst, Is, MatchReversed) ->
- Regs0 = regs_init_singleton(Dst),
- Regs = opt_update_regs_bl(Bl, Regs0),
- {yes,Regs,Is,MatchReversed}.
-
-%% creates_new_ref(Name, Arity) -> true|false.
-%% Return 'true' if the BIF Name/Arity will create a new reference.
-creates_new_ref(monitor, 2) -> true;
-creates_new_ref(make_ref, 0) -> true;
-creates_new_ref(_, _) -> false.
-
-%% opt_recv([Instruction], Regs, LabelIndex) -> no|{yes,[Instruction]}
-%% Search for a receive statement that will only retrieve messages
-%% that contain the newly created reference (which is currently in {x,0}).
-opt_recv(Is, Regs, D) ->
- L = gb_sets:empty(),
- opt_recv(Is, D, Regs, L, []).
-
-opt_recv([{label,L}=Lbl,{loop_rec,{f,Fail},_}=Loop|Is], D, R0, _, Acc) ->
- R = regs_kill_not_live(0, R0),
- case regs_empty(R) of
- false ->
- %% We now have the new reference in Y registers
- %% and the current instruction is the beginning of a
- %% receive statement. We must now verify that only messages
- %% that contain the reference will be matched.
- case opt_ref_used(Is, R, Fail, D) of
- false ->
- no;
- true ->
- RecvSet = {recv_set,{f,L}},
- {yes,reverse(Acc, [RecvSet,Lbl,Loop|Is]),L}
- end;
- true ->
- no
- end;
-opt_recv([I|Is], D, R0, L0, Acc) ->
- {R,L} = opt_update_regs(I, R0, L0),
- case regs_empty(R) of
- true ->
- %% The reference is no longer alive. There is no
- %% point in continuing the search.
- no;
- false ->
- opt_recv(Is, D, R, L, [I|Acc])
- end;
-opt_recv([], _, _, _, _) -> no.
-
-opt_update_regs({block,Bl}, R, L) ->
- {opt_update_regs_bl(Bl, R),L};
-opt_update_regs({call,_,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({call_ext,_,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({call_fun,_}, R, L) ->
- {regs_kill_not_live(0, R),L};
-opt_update_regs({kill,Y}, R, L) ->
- {regs_kill([Y], R),L};
-opt_update_regs({'catch',_,{f,Lbl}}, R, L) ->
- {R,gb_sets:add(Lbl, L)};
-opt_update_regs({catch_end,_}, R, L) ->
- {R,L};
-opt_update_regs({label,Lbl}, R, L) ->
- case gb_sets:is_member(Lbl, L) of
- false ->
- %% We can't allow arbitrary labels (since the receive
- %% could be entered without first creating the reference).
- {regs_init(),L};
- true ->
- %% A catch label for a previously seen catch instruction is OK.
- {R,L}
- end;
-opt_update_regs({'try',_,{f,Lbl}}, R, L) ->
- {R,gb_sets:add(Lbl, L)};
-opt_update_regs({try_end,_}, R, L) ->
- {R,L};
-opt_update_regs({line,_}, R, L) ->
- {R,L};
-opt_update_regs(_I, _R, L) ->
- %% Unrecognized instruction. Abort the search.
- {regs_init(),L}.
-
-opt_update_regs_bl([{set,Ds,_,{alloc,Live,_}}|Is], Regs0) ->
- Regs1 = regs_kill_not_live(Live, Regs0),
- Regs = regs_kill(Ds, Regs1),
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([{set,[Dst]=Ds,[Src],move}|Is], Regs0) ->
- Regs1 = regs_kill(Ds, Regs0),
- Regs = case regs_is_member(Src, Regs1) of
- false -> Regs1;
- true -> regs_add(Dst, Regs1)
- end,
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([{set,Ds,_,_}|Is], Regs0) ->
- Regs = regs_kill(Ds, Regs0),
- opt_update_regs_bl(Is, Regs);
-opt_update_regs_bl([], Regs) -> Regs.
-
-%% opt_ref_used([Instruction], RefRegs, FailLabel, LabelIndex) -> true|false
-%% Return 'true' if it is certain that only messages that contain the same
-%% reference as in RefRegs can be matched out. Otherwise return 'false'.
-%%
-%% Basically, we follow all possible paths through the receive statement.
-%% If all paths are safe, we return 'true'.
-%%
-%% A branch to FailLabel is safe, because it exits the receive statement
-%% and no further message may be matched out.
-%%
-%% If a path hits an comparision between RefRegs and part of the message,
-%% that path is safe (any messages that may be matched further down the
-%% path is guaranteed to contain the reference).
-%%
-%% Otherwise, if we hit a 'remove_message' instruction, we give up
-%% and return 'false' (the optimization is definitely unsafe). If
-%% we hit an unrecognized instruction, we also give up and return
-%% 'false' (the optimization may be unsafe).
-
-opt_ref_used(Is, RefRegs, Fail, D) ->
- Done = gb_sets:singleton(Fail),
- Regs = regs_init_x0(),
- try
- _ = opt_ref_used_1(Is, RefRegs, D, Done, Regs),
- true
- catch
- throw:not_used ->
- false
- end.
-
-%% This functions only returns if all paths through the receive
-%% statement are safe, and throws an 'not_used' term otherwise.
-opt_ref_used_1([{block,Bl}|Is], RefRegs, D, Done, Regs0) ->
- Regs = opt_ref_used_bl(Bl, Regs0),
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
-opt_ref_used_1([{test,is_eq_exact,{f,Fail},Args}|Is],
- RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefRegs, Regs) of
- false ->
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
- true ->
- %% The instructions that follow (Is) can only be executed
- %% if the message contains the same reference as in RefRegs.
- Done
- end;
-opt_ref_used_1([{test,is_ne_exact,{f,Fail},Args}|Is],
- RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
- case is_ref_msg_comparison(Args, RefRegs, Regs) of
- false ->
- opt_ref_used_at(Fail, RefRegs, D, Done, Regs);
- true ->
- Done
- end;
-opt_ref_used_1([{test,_,{f,Fail},_}|Is], RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(Fail, RefRegs, D, Done0, Regs),
- opt_ref_used_1(Is, RefRegs, D, Done, Regs);
-opt_ref_used_1([{select,_,_,{f,Fail},List}|_], RefRegs, D, Done, Regs) ->
- Lbls = [F || {f,F} <- List] ++ [Fail],
- opt_ref_used_in_all(Lbls, RefRegs, D, Done, Regs);
-opt_ref_used_1([{label,Lbl}|Is], RefRegs, D, Done, Regs) ->
- case gb_sets:is_member(Lbl, Done) of
- true -> Done;
- false -> opt_ref_used_1(Is, RefRegs, D, Done, Regs)
- end;
-opt_ref_used_1([{loop_rec_end,_}|_], _, _, Done, _) ->
- Done;
-opt_ref_used_1([_I|_], _RefReg, _D, _Done, _Regs) ->
- %% The optimization may be unsafe.
- throw(not_used).
-
-%% is_ref_msg_comparison(Args, RefRegs, RegisterSet) -> true|false.
-%% Return 'true' if Args denotes a comparison between the
-%% reference and message or part of the message.
-is_ref_msg_comparison([R1,R2], RefRegs, Regs) ->
- (regs_is_member(R2, RefRegs) andalso regs_is_member(R1, Regs)) orelse
- (regs_is_member(R1, RefRegs) andalso regs_is_member(R2, Regs)).
-
-opt_ref_used_in_all([L|Ls], RefRegs, D, Done0, Regs) ->
- Done = opt_ref_used_at(L, RefRegs, D, Done0, Regs),
- opt_ref_used_in_all(Ls, RefRegs, D, Done, Regs);
-opt_ref_used_in_all([], _, _, Done, _) -> Done.
-
-opt_ref_used_at(Fail, RefRegs, D, Done0, Regs) ->
- case gb_sets:is_member(Fail, Done0) of
- true ->
- Done0;
- false ->
- Is = beam_utils:code_at(Fail, D),
- Done = opt_ref_used_1(Is, RefRegs, D, Done0, Regs),
- gb_sets:add(Fail, Done)
- end.
-
-opt_ref_used_bl([{set,[],[],remove_message}|_], _) ->
- %% We have proved that a message that does not depend on the
- %% reference can be matched out.
- throw(not_used);
-opt_ref_used_bl([{set,Ds,Ss,_}|Is], Regs0) ->
- case regs_all_members(Ss, Regs0) of
- false ->
- %% The destination registers may be assigned values that
- %% are not dependent on the message being matched.
- Regs = regs_kill(Ds, Regs0),
- opt_ref_used_bl(Is, Regs);
- true ->
- %% All the sources depend on the message directly or
- %% indirectly.
- Regs = regs_add_list(Ds, Regs0),
- opt_ref_used_bl(Is, Regs)
- end;
-opt_ref_used_bl([], Regs) -> Regs.
-
-%%%
-%%% Functions for keeping track of a set of registers.
-%%%
-
-%% regs_init() -> RegisterSet
-%% Return an empty set of registers.
-
-regs_init() ->
- {0,0}.
-
-%% regs_init_singleton(Register) -> RegisterSet
-%% Return a set that only contains one register.
-
-regs_init_singleton(Reg) ->
- regs_add(Reg, regs_init()).
-
-%% regs_init_x0() -> RegisterSet
-%% Return a set that only contains the {x,0} register.
-
-regs_init_x0() ->
- {1 bsl 0,0}.
-
-%% regs_empty(Register) -> true|false
-%% Test whether the register set is empty.
-
-regs_empty(R) ->
- R =:= {0,0}.
-
-%% regs_kill_not_live(Live, RegisterSet) -> RegisterSet'
-%% Kill all registers indicated not live by Live.
-
-regs_kill_not_live(Live, {Xregs,Yregs}) ->
- {Xregs band ((1 bsl Live)-1),Yregs}.
-
-%% regs_kill([Register], RegisterSet) -> RegisterSet'
-%% Kill all registers mentioned in the list of registers.
-
-regs_kill([{x,N}|Rs], {Xregs,Yregs}) ->
- regs_kill(Rs, {Xregs band (bnot (1 bsl N)),Yregs});
-regs_kill([{y,N}|Rs], {Xregs,Yregs}) ->
- regs_kill(Rs, {Xregs,Yregs band (bnot (1 bsl N))});
-regs_kill([{fr,_}|Rs], Regs) ->
- regs_kill(Rs, Regs);
-regs_kill([], Regs) -> Regs.
-
-regs_add_list(List, Regs) ->
- foldl(fun(R, A) -> regs_add(R, A) end, Regs, List).
-
-%% regs_add(Register, RegisterSet) -> RegisterSet'
-%% Add a new register to the set of registers.
-
-regs_add({x,N}, {Xregs,Yregs}) ->
- {Xregs bor (1 bsl N),Yregs};
-regs_add({y,N}, {Xregs,Yregs}) ->
- {Xregs,Yregs bor (1 bsl N)}.
-
-%% regs_all_members([Register], RegisterSet) -> true|false
-%% Test whether all of the registers are part of the register set.
-
-regs_all_members([R|Rs], Regs) ->
- regs_is_member(R, Regs) andalso regs_all_members(Rs, Regs);
-regs_all_members([], _) -> true.
-
-%% regs_is_member(Register, RegisterSet) -> true|false
-%% Test whether Register is part of the register set.
-
-regs_is_member({x,N}, {Regs,_}) -> Regs band (1 bsl N) =/= 0;
-regs_is_member({y,N}, {_,Regs}) -> Regs band (1 bsl N) =/= 0;
-regs_is_member(_, _) -> false.
diff --git a/lib/compiler/src/beam_record.erl b/lib/compiler/src/beam_record.erl
deleted file mode 100644
index 58a6de6775..0000000000
--- a/lib/compiler/src/beam_record.erl
+++ /dev/null
@@ -1,131 +0,0 @@
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2014-2017. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%% Rewrite the instruction stream on tagged tuple tests.
-%% Tagged tuples means a tuple of any arity with an atom as its
-%% first element, such as records and error tuples.
-%%
-%% From:
-%% ...
-%% {test,is_tuple,Fail,[Src]}.
-%% {test,test_arity,Fail,[Src,Sz]}.
-%% ...
-%% {get_tuple_element,Src,0,Dst}.
-%% ...
-%% {test,is_eq_exact,Fail,[Dst,Atom]}.
-%% ...
-%% To:
-%% ...
-%% {test,is_tagged_tuple,Fail,[Src,Sz,Atom]}.
-%% ...
-%%
-
--module(beam_record).
--export([module/2]).
-
--import(lists, [reverse/1,reverse/2]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}) ->
- try
- Is1 = beam_utils:anno_defs(Is0),
- Idx = beam_utils:index_labels(Is1),
- Is = rewrite(reverse(Is1), Idx),
- {function,Name,Arity,CLabel,Is}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-rewrite(Is, Idx) ->
- rewrite(Is, Idx, 0, []).
-
-rewrite([{test,test_arity,Fail,[Src,N]}=TA,
- {test,is_tuple,Fail,[Src]}=TT|Is], Idx, Def, Acc0) ->
- case is_tagged_tuple(Acc0, Def, Fail, Src, Idx) of
- no ->
- rewrite(Is, Idx, 0, [TT,TA|Acc0]);
- {yes,Atom,Acc} ->
- I = {test,is_tagged_tuple,Fail,[Src,N,Atom]},
- rewrite(Is, Idx, Def, [I|Acc])
- end;
-rewrite([{block,[{'%anno',{def,Def}}|Bl]}|Is], Idx, _Def, Acc) ->
- rewrite(Is, Idx, Def, [{block,Bl}|Acc]);
-rewrite([{label,L}=I|Is], Idx0, Def, Acc) ->
- Idx = beam_utils:index_label(L, Acc, Idx0),
- rewrite(Is, Idx, Def, [I|Acc]);
-rewrite([I|Is], Idx, Def, Acc) ->
- rewrite(Is, Idx, Def, [I|Acc]);
-rewrite([], _, _, Acc) -> Acc.
-
-is_tagged_tuple([{block,Bl},
- {test,is_eq_exact,Fail,[Dst,{atom,_}=Atom]}|Is],
- Def, Fail, Src, Idx) ->
- case is_tagged_tuple_1(Bl, Is, Fail, Src, Dst, Idx, Def, []) of
- no ->
- no;
- {yes,[]} ->
- {yes,Atom,Is};
- {yes,[_|_]=Block} ->
- {yes,Atom,[{block,Block}|Is]}
- end;
-is_tagged_tuple(_, _, _, _, _) ->
- no.
-
-is_tagged_tuple_1([{set,[Dst],[Src],{get_tuple_element,0}}=I|Bl],
- Is, Fail, Src, Dst, Idx, Def, Acc) ->
- %% Check usage of Dst to find out whether the get_tuple_element
- %% is needed.
- case usage(Dst, Is, Fail, Idx) of
- killed ->
- %% Safe to remove the get_tuple_element instruction.
- {yes,reverse(Acc, Bl)};
- used ->
- %% Actively used. Must keep instruction.
- {yes,reverse(Acc, [I|Bl])};
- not_used ->
- %% Not actually used (but must be initialized).
- case is_defined(Dst, Def) of
- false ->
- %% Dst must be initialized, but the
- %% actual value does not matter.
- Kill = {set,[Dst],[nil],move},
- {yes,reverse(Acc, [Kill|Bl])};
- true ->
- %% The register is previously initialized.
- %% We can remove the instruction.
- {yes,reverse(Acc, Bl)}
- end
- end;
-is_tagged_tuple_1([I|Bl], Is, Fail, Src, Dst, Idx, Def, Acc) ->
- is_tagged_tuple_1(Bl, Is, Fail, Src, Dst, Idx, Def, [I|Acc]);
-is_tagged_tuple_1(_, _, _, _, _, _, _, _) ->
- no.
-
-usage(Dst, Is, Fail, Idx) ->
- beam_utils:usage(Dst, [{test,is_number,Fail,[nil]}|Is], Idx).
-
-is_defined({x,X}, Def) ->
- (Def bsr X) band 1 =:= 1.
diff --git a/lib/compiler/src/beam_reorder.erl b/lib/compiler/src/beam_reorder.erl
deleted file mode 100644
index 8d2ef5a431..0000000000
--- a/lib/compiler/src/beam_reorder.erl
+++ /dev/null
@@ -1,150 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_reorder).
-
--export([module/2]).
--import(lists, [member/2,reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opt) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Is0}) ->
- try
- Is = reorder(Is0),
- {function,Name,Arity,CLabel,Is}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% reorder(Instructions0) -> Instructions
-%% Reorder instructions before the beam_block pass, because reordering
-%% will be more cumbersome when the blocks are in place.
-%%
-%% Execution of get_tuple_element instructions can be delayed until
-%% they are actually needed. Consider the sequence:
-%%
-%% get_tuple_element Tuple Pos Dst
-%% test Test Fail Operands
-%%
-%% If Dst is killed at label Fail (and not referenced in Operands),
-%% we can can swap the instructions:
-%%
-%% test Test Fail Operands
-%% get_tuple_element Tuple Pos Dst
-%%
-%% That can be beneficial in two ways: Firstly, if the branch is taken
-%% we have avoided execution of the get_tuple_element instruction.
-%% Secondly, even if the branch is not taken, subsequent optimization
-%% (opt_blocks/1) may be able to change Dst to the final destination
-%% register and eliminate a 'move' instruction.
-
-reorder(Is) ->
- D = beam_utils:index_labels(Is),
- reorder_1(Is, D, []).
-
-reorder_1([{Op,_,_}=TryCatch|[I|Is]=Is0], D, Acc)
- when Op =:= 'catch'; Op =:= 'try' ->
- %% Don't allow 'try' or 'catch' instructions to split blocks if
- %% it can be avoided.
- case is_safe(I) of
- false ->
- reorder_1(Is0, D, [TryCatch|Acc]);
- true ->
- reorder_1([TryCatch|Is], D, [I|Acc])
- end;
-reorder_1([{label,L}=I|_], D, Acc) ->
- Is = beam_utils:code_at(L, D),
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,is_nonempty_list,_,_}=I|Is], D, Acc) ->
- %% The run-time system may combine the is_nonempty_list test with
- %% the following get_list instruction.
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,_,_,_}=I,
- {select,_,_,_,_}=S|Is], D, Acc) ->
- %% There is nothing to gain by inserting a get_tuple_element
- %% instruction between the test instruction and the select
- %% instruction.
- reorder_1(Is, D, [S,I|Acc]);
-reorder_1([{test,_,{f,_},[Src|_]}=I|Is], D,
- [{get_tuple_element,Src,_,_}|_]=Acc) ->
- %% We want to avoid code that can confuse beam_validator such as:
- %% is_tuple Fail Src
- %% test_arity Fail Src Arity
- %% is_map Fail Src
- %% get_tuple_element Src Pos Dst
- %% Therefore, don't reorder the instructions in such cases.
- reorder_1(Is, D, [I|Acc]);
-reorder_1([{test,_,{f,L},Ss}=I|Is0], D0,
- [{get_tuple_element,_,_,El}=G|Acc0]=Acc) ->
- case member(El, Ss) of
- true ->
- reorder_1(Is0, D0, [I|Acc]);
- false ->
- case beam_utils:is_killed_at(El, L, D0) of
- true ->
- Is = [I,G|Is0],
- reorder_1(Is, D0, Acc0);
- false ->
- case beam_utils:is_killed(El, Is0, D0) of
- true ->
- Code0 = beam_utils:code_at(L, D0),
- Code = [G|Code0],
- D = beam_utils:index_label(L, Code, D0),
- Is = [I|Is0],
- reorder_1(Is, D, Acc0);
- false ->
- reorder_1(Is0, D0, [I|Acc])
- end
- end
- end;
-reorder_1([{allocate_zero,N,Live}=I0|Is], D,
- [{get_tuple_element,{x,Tup},_,{x,Dst}}=G|Acc]=Acc0) ->
- case Tup < Dst andalso Dst+1 =:= Live of
- true ->
- %% Move allocation instruction upwards past
- %% get_tuple_element instructions to create more
- %% opportunities for moving get_tuple_element
- %% instructions.
- I = {allocate_zero,N,Dst},
- reorder_1([I,G|Is], D, Acc);
- false ->
- reorder_1(Is, D, [I0|Acc0])
- end;
-reorder_1([I|Is], D, Acc) ->
- reorder_1(Is, D, [I|Acc]);
-reorder_1([], _, Acc) -> reverse(Acc).
-
-%% is_safe(Instruction) -> true|false
-%% Test whether an instruction is safe (cannot cause an exception).
-
-is_safe({kill,_}) -> true;
-is_safe({move,_,_}) -> true;
-is_safe({put,_}) -> true;
-is_safe({put_list,_,_,_}) -> true;
-is_safe({put_tuple,_,_}) -> true;
-is_safe({test_heap,_,_}) -> true;
-is_safe(_) -> false.
diff --git a/lib/compiler/src/beam_split.erl b/lib/compiler/src/beam_split.erl
deleted file mode 100644
index 809e49b3d0..0000000000
--- a/lib/compiler/src/beam_split.erl
+++ /dev/null
@@ -1,94 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
--module(beam_split).
--export([module/2]).
-
--import(lists, [reverse/1]).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [split_blocks(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-%% We must split the basic block when we encounter instructions with labels,
-%% such as catches and BIFs. All labels must be visible outside the blocks.
-
-split_blocks({function,Name,Arity,CLabel,Is0}) ->
- Is = split_blocks(Is0, []),
- {function,Name,Arity,CLabel,Is}.
-
-split_blocks([{block,Bl}|Is], Acc0) ->
- Acc = split_block(Bl, [], Acc0),
- split_blocks(Is, Acc);
-split_blocks([I|Is], Acc) ->
- split_blocks(Is, [I|Acc]);
-split_blocks([], Acc) -> reverse(Acc).
-
-split_block([{set,[R],[_,_,_]=As,{bif,is_record,{f,Lbl}}}|Is], Bl, Acc) ->
- %% is_record/3 must be translated by beam_clean; therefore,
- %% it must be outside of any block.
- split_block(Is, [], [{bif,is_record,{f,Lbl},As,R}|make_block(Bl, Acc)]);
-split_block([{set,[R],As,{bif,N,{f,Lbl}=Fail}}|Is], Bl, Acc) when Lbl =/= 0 ->
- split_block(Is, [], [{bif,N,Fail,As,R}|make_block(Bl, Acc)]);
-split_block([{set,[],[],{line,_}=Line},
- {set,[R],As,{bif,raise,{f,_}=Fail}}|Is], Bl, Acc) ->
- split_block(Is, [], [{bif,raise,Fail,As,R},Line|make_block(Bl, Acc)]);
-split_block([{set,[R],As,{alloc,Live,{gc_bif,N,{f,Lbl}=Fail}}}|Is], Bl, Acc)
- when Lbl =/= 0 ->
- split_block(Is, [], [{gc_bif,N,Fail,Live,As,R}|make_block(Bl, Acc)]);
-split_block([{set,[D],[S|Puts],{alloc,R,{put_map,Op,{f,Lbl}=Fail}}}|Is],
- Bl, Acc) when Lbl =/= 0 ->
- split_block(Is, [], [{put_map,Fail,Op,S,D,R,{list,Puts}}|
- make_block(Bl, Acc)]);
-split_block([{set,[R],[],{try_catch,Op,L}}|Is], Bl, Acc) ->
- split_block(Is, [], [{Op,R,L}|make_block(Bl, Acc)]);
-split_block([I|Is], Bl, Acc) ->
- split_block(Is, [I|Bl], Acc);
-split_block([], Bl, Acc) -> make_block(Bl, Acc).
-
-make_block([], Acc) -> Acc;
-make_block([{set,[D],Ss,{bif,Op,Fail}}|Bl]=Bl0, Acc) ->
- %% If the last instruction in the block is a comparison or boolean operator
- %% (such as '=:='), move it out of the block to facilitate further
- %% optimizations.
- Arity = length(Ss),
- case erl_internal:comp_op(Op, Arity) orelse
- erl_internal:new_type_test(Op, Arity) orelse
- erl_internal:bool_op(Op, Arity) of
- false ->
- [{block,reverse(Bl0)}|Acc];
- true ->
- I = {bif,Op,Fail,Ss,D},
- case Bl =:= [] of
- true -> [I|Acc];
- false -> [I,{block,reverse(Bl)}|Acc]
- end
- end;
-make_block([{set,[Dst],[Src],move}|Bl], Acc) ->
- %% Make optimization of {move,Src,Dst}, {jump,...} possible.
- I = {move,Src,Dst},
- case Bl =:= [] of
- true -> [I|Acc];
- false -> [I,{block,reverse(Bl)}|Acc]
- end;
-make_block(Bl, Acc) -> [{block,reverse(Bl)}|Acc].
diff --git a/lib/compiler/src/beam_ssa.erl b/lib/compiler/src/beam_ssa.erl
new file mode 100644
index 0000000000..c5e23d2ae0
--- /dev/null
+++ b/lib/compiler/src/beam_ssa.erl
@@ -0,0 +1,841 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Type definitions and utilities for the SSA format.
+
+-module(beam_ssa).
+-export([add_anno/3,get_anno/2,get_anno/3,
+ clobbers_xregs/1,def/2,def_used/2,
+ definitions/1,
+ dominators/1,
+ flatmapfold_instrs_rpo/4,
+ fold_po/3,fold_po/4,fold_rpo/3,fold_rpo/4,
+ fold_instrs_rpo/4,
+ linearize/1,
+ mapfold_blocks_rpo/4,
+ mapfold_instrs_rpo/4,
+ normalize/1,
+ no_side_effect/1,
+ predecessors/1,
+ rename_vars/3,
+ rpo/1,rpo/2,
+ split_blocks/3,
+ successors/1,successors/2,
+ trim_unreachable/1,
+ update_phi_labels/4,used/1,
+ uses/1,uses/2]).
+
+-export_type([b_module/0,b_function/0,b_blk/0,b_set/0,
+ b_ret/0,b_br/0,b_switch/0,terminator/0,
+ b_var/0,b_literal/0,b_remote/0,b_local/0,
+ value/0,argument/0,label/0,
+ var_name/0,var_base/0,literal_value/0,
+ op/0,anno/0,block_map/0,dominator_map/0,
+ rename_map/0,rename_proplist/0,usage_map/0,
+ definition_map/0]).
+
+-include("beam_ssa.hrl").
+
+-type b_module() :: #b_module{}.
+-type b_function() :: #b_function{}.
+-type b_blk() :: #b_blk{}.
+-type b_set() :: #b_set{}.
+
+-type b_br() :: #b_br{}.
+-type b_ret() :: #b_ret{}.
+-type b_switch() :: #b_switch{}.
+-type terminator() :: b_br() | b_ret() | b_switch().
+
+-type construct() :: b_module() | b_function() | b_blk() | b_set() |
+ terminator().
+
+-type b_var() :: #b_var{}.
+-type b_literal() :: #b_literal{}.
+-type b_remote() :: #b_remote{}.
+-type b_local() :: #b_local{}.
+
+-type value() :: b_var() | b_literal().
+-type phi_value() :: {value(),label()}.
+-type argument() :: value() | b_remote() | b_local() | phi_value().
+-type label() :: non_neg_integer().
+
+-type var_name() :: var_base() | {var_base(),non_neg_integer()}.
+-type var_base() :: atom() | non_neg_integer().
+
+-type literal_value() :: atom() | integer() | float() | list() |
+ nil() | tuple() | map() | binary().
+
+-type op() :: {'bif',atom()} | {'float',float_op()} | prim_op() | cg_prim_op().
+-type anno() :: #{atom() := any()}.
+
+-type block_map() :: #{label():=b_blk()}.
+-type dominator_map() :: #{label():=ordsets:ordset(label())}.
+-type usage_map() :: #{b_var():=[{label(),b_set() | terminator()}]}.
+-type definition_map() :: #{b_var():=b_set()}.
+-type rename_map() :: #{b_var():=value()}.
+-type rename_proplist() :: [{b_var(),value()}].
+
+%% Note: By default, dialyzer will collapse this type to atom().
+%% To avoid the collapsing, change the value of SET_LIMIT to 50 in the
+%% file erl_types.erl in the hipe application.
+
+-type prim_op() :: 'bs_add' | 'bs_extract' | 'bs_init' | 'bs_init_writable' |
+ 'bs_match' | 'bs_put' | 'bs_start_match' | 'bs_test_tail' |
+ 'bs_utf16_size' | 'bs_utf8_size' | 'build_stacktrace' |
+ 'call' | 'catch_end' |
+ 'extract' |
+ 'get_hd' | 'get_map_element' | 'get_tl' | 'get_tuple_element' |
+ 'has_map_field' |
+ 'is_nonempty_list' | 'is_tagged_tuple' |
+ 'kill_try_tag' |
+ 'landingpad' |
+ 'make_fun' | 'new_try_tag' |
+ 'peek_message' | 'phi' | 'put_list' | 'put_map' | 'put_tuple' |
+ 'raw_raise' | 'recv_next' | 'remove_message' | 'resume' |
+ 'set_tuple_element' | 'succeeded' |
+ 'timeout' |
+ 'wait' | 'wait_timeout'.
+
+-type float_op() :: 'checkerror' | 'clearerror' | 'convert' | 'get' | 'put' |
+ '+' | '-' | '*' | '/'.
+
+%% Primops only used internally during code generation.
+-type cg_prim_op() :: 'bs_get' | 'bs_match_string' | 'bs_restore' | 'bs_skip' |
+ 'copy' | 'put_tuple_arity' | 'put_tuple_element'.
+
+-import(lists, [foldl/3,keyfind/3,mapfoldl/3,member/2,reverse/1]).
+
+-spec add_anno(Key, Value, Construct) -> Construct when
+ Key :: atom(),
+ Value :: any(),
+ Construct :: construct().
+
+add_anno(Key, Val, #b_function{anno=Anno}=Bl) ->
+ Bl#b_function{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_blk{anno=Anno}=Bl) ->
+ Bl#b_blk{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_set{anno=Anno}=Bl) ->
+ Bl#b_set{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_br{anno=Anno}=Bl) ->
+ Bl#b_br{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_ret{anno=Anno}=Bl) ->
+ Bl#b_ret{anno=Anno#{Key=>Val}};
+add_anno(Key, Val, #b_switch{anno=Anno}=Bl) ->
+ Bl#b_switch{anno=Anno#{Key=>Val}}.
+
+-spec get_anno(atom(), construct()) -> any().
+
+get_anno(Key, Construct) ->
+ maps:get(Key, get_anno(Construct)).
+
+-spec get_anno(atom(), construct(),any()) -> any().
+
+get_anno(Key, Construct, Default) ->
+ maps:get(Key, get_anno(Construct), Default).
+
+get_anno(#b_function{anno=Anno}) -> Anno;
+get_anno(#b_blk{anno=Anno}) -> Anno;
+get_anno(#b_set{anno=Anno}) -> Anno;
+get_anno(#b_br{anno=Anno}) -> Anno;
+get_anno(#b_ret{anno=Anno}) -> Anno;
+get_anno(#b_switch{anno=Anno}) -> Anno.
+
+%% clobbers_xregs(#b_set{}) -> true|false.
+%% Test whether the instruction invalidates all X registers.
+
+-spec clobbers_xregs(b_set()) -> boolean().
+
+clobbers_xregs(#b_set{op=Op}) ->
+ case Op of
+ bs_init_writable -> true;
+ build_stacktrace -> true;
+ call -> true;
+ landingpad -> true;
+ make_fun -> true;
+ peek_message -> true;
+ raw_raise -> true;
+ _ -> false
+ end.
+
+%% no_side_effect(#b_set{}) -> true|false.
+%% Test whether this instruction has no side effect and thus is safe
+%% not to execute if its value is not used. Note that even if `true`
+%% is returned, the instruction could still be impure (e.g. bif:get).
+
+-spec no_side_effect(b_set()) -> boolean().
+
+no_side_effect(#b_set{op=Op}) ->
+ case Op of
+ {bif,_} -> true;
+ {float,get} -> true;
+ bs_init -> true;
+ bs_extract -> true;
+ bs_match -> true;
+ bs_start_match -> true;
+ bs_test_tail -> true;
+ bs_get_tail -> true;
+ bs_put -> true;
+ extract -> true;
+ get_hd -> true;
+ get_tl -> true;
+ get_tuple_element -> true;
+ has_map_field -> true;
+ is_nonempty_list -> true;
+ is_tagged_tuple -> true;
+ make_fun -> true;
+ put_map -> true;
+ put_list -> true;
+ put_tuple -> true;
+ succeeded -> true;
+ _ -> false
+ end.
+
+-spec predecessors(Blocks) -> #{BlockNumber:=[Predecessor]} when
+ Blocks :: block_map(),
+ BlockNumber :: label(),
+ Predecessor :: label().
+
+predecessors(Blocks) ->
+ P0 = [{S,L} || {L,Blk} <- maps:to_list(Blocks),
+ S <- successors(Blk)],
+ P1 = sofs:relation(P0),
+ P2 = sofs:rel2fam(P1),
+ P3 = sofs:to_external(P2),
+ P = [{0,[]}|P3],
+ maps:from_list(P).
+
+-spec successors(b_blk()) -> [label()].
+
+successors(#b_blk{last=Terminator}) ->
+ case Terminator of
+ #b_br{bool=#b_literal{val=true},succ=Succ} ->
+ [Succ];
+ #b_br{bool=#b_literal{val=false},fail=Fail} ->
+ [Fail];
+ #b_br{succ=Succ,fail=Fail} ->
+ [Fail,Succ];
+ #b_switch{fail=Fail,list=List} ->
+ [Fail|[L || {_,L} <- List]];
+ #b_ret{} ->
+ []
+ end.
+
+%% normalize(Instr0) -> Instr.
+%% Normalize instructions to help optimizations.
+%%
+%% For commutative operators (such as '+' and 'or'), always
+%% place a variable operand before a literal operand.
+%%
+%% Normalize #b_br{} to one of the following forms:
+%%
+%% #b_br{b_literal{val=true},succ=Label,fail=Label}
+%% #b_br{b_var{},succ=Label1,fail=Label2} where Label1 =/= Label2
+%%
+%% Simplify a #b_switch{} with a literal argument to a #b_br{}.
+%%
+%% Simplify a #b_switch{} with a variable argument and an empty
+%% switch list to a #b_br{}.
+
+-spec normalize(b_set() | terminator()) ->
+ b_set() | terminator().
+
+normalize(#b_set{op={bif,Bif},args=Args}=Set) ->
+ case {is_commutative(Bif),Args} of
+ {false,_} ->
+ Set;
+ {true,[#b_literal{}=Lit,#b_var{}=Var]} ->
+ Set#b_set{args=[Var,Lit]};
+ {true,_} ->
+ Set
+ end;
+normalize(#b_set{}=Set) ->
+ Set;
+normalize(#b_br{}=Br) ->
+ case Br of
+ #b_br{bool=Bool,succ=Same,fail=Same} ->
+ case Bool of
+ #b_literal{val=true} ->
+ Br;
+ _ ->
+ Br#b_br{bool=#b_literal{val=true}}
+ end;
+ #b_br{bool=#b_literal{val=true},succ=Succ} ->
+ Br#b_br{fail=Succ};
+ #b_br{bool=#b_literal{val=false},fail=Fail} ->
+ Br#b_br{bool=#b_literal{val=true},succ=Fail};
+ #b_br{} ->
+ Br
+ end;
+normalize(#b_switch{arg=Arg,fail=Fail,list=List}=Sw) ->
+ case Arg of
+ #b_literal{} ->
+ case keyfind(Arg, 1, List) of
+ false ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+ {Arg,L} ->
+ #b_br{bool=#b_literal{val=true},succ=L,fail=L}
+ end;
+ #b_var{} when List =:= [] ->
+ #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+ #b_var{} ->
+ Sw
+ end;
+normalize(#b_ret{}=Ret) ->
+ Ret.
+
+-spec successors(label(), block_map()) -> [label()].
+
+successors(L, Blocks) ->
+ successors(maps:get(L, Blocks)).
+
+-spec def(Ls, Blocks) -> Def when
+ Ls :: [label()],
+ Blocks :: block_map(),
+ Def :: ordsets:ordset(var_name()).
+
+def(Ls, Blocks) ->
+ Top = rpo(Ls, Blocks),
+ Blks = [maps:get(L, Blocks) || L <- Top],
+ def_1(Blks, []).
+
+-spec def_used(Ls, Blocks) -> {Def,Used} when
+ Ls :: [label()],
+ Blocks :: block_map(),
+ Def :: ordsets:ordset(var_name()),
+ Used :: ordsets:ordset(var_name()).
+
+def_used(Ls, Blocks) ->
+ Top = rpo(Ls, Blocks),
+ Blks = [maps:get(L, Blocks) || L <- Top],
+ Preds = gb_sets:from_list(Top),
+ def_used_1(Blks, Preds, [], gb_sets:empty()).
+
+-spec dominators(Blocks) -> Result when
+ Blocks :: block_map(),
+ Result :: dominator_map().
+
+dominators(Blocks) ->
+ Preds = predecessors(Blocks),
+ Top0 = rpo(Blocks),
+ Top = [{L,maps:get(L, Preds)} || L <- Top0],
+
+ %% The flow graph for an Erlang function is reducible, and
+ %% therefore one traversal in reverse postorder is sufficient.
+ iter_dominators(Top, #{}).
+
+-spec fold_instrs_rpo(Fun, From, Acc0, Blocks) -> any() when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Blocks :: block_map().
+
+fold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ fold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% Like mapfold_instrs_rpo but at the block level to support lookahead and
+%% scope-dependent transformations.
+-spec mapfold_blocks_rpo(Fun, From, Acc, Blocks) -> Result when
+ Fun :: fun((label(), b_blk(), any()) -> {b_blk(), any()}),
+ From :: [label()],
+ Acc :: any(),
+ Blocks :: block_map(),
+ Result :: {block_map(), any()}.
+mapfold_blocks_rpo(Fun, From, Acc, Blocks) ->
+ Successors = rpo(From, Blocks),
+ foldl(fun(Lbl, A) ->
+ mapfold_blocks_rpo_1(Fun, Lbl, A)
+ end, {Blocks, Acc}, Successors).
+
+mapfold_blocks_rpo_1(Fun, Lbl, {Blocks0, Acc0}) ->
+ Block0 = maps:get(Lbl, Blocks0),
+ {Block, Acc} = Fun(Lbl, Block0, Acc0),
+ Blocks = maps:put(Lbl, Block, Blocks0),
+ {Blocks, Acc}.
+
+-spec mapfold_instrs_rpo(Fun, From, Acc0, Blocks0) -> {Blocks,Acc} when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Acc :: any(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+mapfold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ mapfold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+-spec flatmapfold_instrs_rpo(Fun, From, Acc0, Blocks0) -> {Blocks,Acc} when
+ Fun :: fun((b_blk()|terminator(), any()) -> any()),
+ From :: [label()],
+ Acc0 :: any(),
+ Acc :: any(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+flatmapfold_instrs_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ flatmapfold_instrs_rpo_1(Top, Fun, Blocks, Acc0).
+
+-type fold_fun() :: fun((label(), b_blk(), any()) -> any()).
+
+%% fold_rpo(Fun, [Label], Acc0, Blocks) -> Acc.
+%% Fold over all blocks a reverse postorder traversal of the block
+%% graph; that is, first visit a block, then visit its successors.
+
+-spec fold_rpo(Fun, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+fold_rpo(Fun, Acc0, Blocks) ->
+ fold_rpo(Fun, [0], Acc0, Blocks).
+
+%% fold_rpo(Fun, [Label], Acc0, Blocks) -> Acc. Fold over all blocks
+%% reachable from a given set of labels in a reverse postorder
+%% traversal of the block graph; that is, first visit a block, then
+%% visit its successors.
+
+-spec fold_rpo(Fun, Labels, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Labels :: [label()],
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+fold_rpo(Fun, From, Acc0, Blocks) ->
+ Top = rpo(From, Blocks),
+ fold_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% fold_po(Fun, Acc0, Blocks) -> Acc.
+%% Fold over all blocks in a postorder traversal of the block graph;
+%% that is, first visit all successors of block, then the block
+%% itself.
+
+-spec fold_po(Fun, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Acc0 :: any(),
+ Blocks :: #{label():=b_blk()}.
+
+%% fold_po(Fun, From, Acc0, Blocks) -> Acc.
+%% Fold over the blocks reachable from the block numbers given
+%% by From in a postorder traversal of the block graph.
+
+fold_po(Fun, Acc0, Blocks) ->
+ fold_po(Fun, [0], Acc0, Blocks).
+
+-spec fold_po(Fun, Labels, Acc0, Blocks) -> any() when
+ Fun :: fold_fun(),
+ Labels :: [label()],
+ Acc0 :: any(),
+ Blocks :: block_map().
+
+fold_po(Fun, From, Acc0, Blocks) ->
+ Top = reverse(rpo(From, Blocks)),
+ fold_rpo_1(Top, Fun, Blocks, Acc0).
+
+%% linearize(Blocks) -> [{BlockLabel,#b_blk{}}].
+%% Linearize the intermediate representation of the code.
+%% Unreachable blocks will be discarded, and phi nodes will
+%% be adjusted so that they no longer refers to discarded
+%% blocks or to blocks that no longer are predecessors of
+%% the phi node block.
+
+-spec linearize(Blocks) -> Linear when
+ Blocks :: block_map(),
+ Linear :: [{label(),b_blk()}].
+
+linearize(Blocks) ->
+ Seen = cerl_sets:new(),
+ {Linear0,_} = linearize_1([0], Blocks, Seen, []),
+ Linear = fix_phis(Linear0, #{}),
+ Linear.
+
+-spec rpo(Blocks) -> [Label] when
+ Blocks :: block_map(),
+ Label :: label().
+
+rpo(Blocks) ->
+ rpo([0], Blocks).
+
+-spec rpo(From, Blocks) -> Labels when
+ From :: [label()],
+ Blocks :: block_map(),
+ Labels :: [label()].
+
+rpo(From, Blocks) ->
+ Seen = cerl_sets:new(),
+ {Ls,_} = rpo_1(From, Blocks, Seen, []),
+ Ls.
+
+-spec rename_vars(Rename, [label()], block_map()) -> block_map() when
+ Rename :: rename_map() | rename_proplist().
+
+rename_vars(Rename, From, Blocks) when is_list(Rename) ->
+ rename_vars(maps:from_list(Rename), From, Blocks);
+rename_vars(Rename, From, Blocks) when is_map(Rename)->
+ Top = rpo(From, Blocks),
+ Preds = cerl_sets:from_list(Top),
+ F = fun(#b_set{op=phi,args=Args0}=Set) ->
+ Args = rename_phi_vars(Args0, Preds, Rename),
+ Set#b_set{args=Args};
+ (#b_set{args=Args0}=Set) ->
+ Args = [rename_var(A, Rename) || A <- Args0],
+ Set#b_set{args=Args};
+ (#b_switch{arg=Bool}=Sw) ->
+ Sw#b_switch{arg=rename_var(Bool, Rename)};
+ (#b_br{bool=Bool}=Br) ->
+ Br#b_br{bool=rename_var(Bool, Rename)};
+ (#b_ret{arg=Arg}=Ret) ->
+ Ret#b_ret{arg=rename_var(Arg, Rename)}
+ end,
+ map_instrs_1(Top, F, Blocks).
+
+%% split_blocks(Predicate, Blocks0, Count0) -> {Blocks,Count}.
+%% Call Predicate(Instruction) for each instruction in all
+%% blocks. If Predicate/1 returns true, split the block
+%% before this instruction.
+
+-spec split_blocks(Pred, Blocks0, Count0) -> {Blocks,Count} when
+ Pred :: fun((b_set()) -> boolean()),
+ Blocks :: block_map(),
+ Count0 :: beam_ssa:label(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map(),
+ Count :: beam_ssa:label().
+
+split_blocks(P, Blocks, Count) ->
+ Ls = beam_ssa:rpo(Blocks),
+ split_blocks_1(Ls, P, Blocks, Count).
+
+-spec trim_unreachable(Blocks0) -> Blocks when
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+%% trim_unreachable(Blocks0) -> Blocks.
+%% Remove all unreachable blocks. Adjust all phi nodes so
+%% they don't refer to blocks that has been removed or no
+%% no longer branch to the phi node in question.
+
+trim_unreachable(Blocks) ->
+ %% Could perhaps be optimized if there is any need.
+ maps:from_list(linearize(Blocks)).
+
+%% update_phi_labels([BlockLabel], Old, New, Blocks0) -> Blocks.
+%% In the given blocks, replace label Old in with New in all
+%% phi nodes. This is useful after merging or splitting
+%% blocks.
+
+-spec update_phi_labels(From, Old, New, Blocks0) -> Blocks when
+ From :: [label()],
+ Old :: label(),
+ New :: label(),
+ Blocks0 :: block_map(),
+ Blocks :: block_map().
+
+update_phi_labels([L|Ls], Old, New, Blocks0) ->
+ case Blocks0 of
+ #{L:=#b_blk{is=[#b_set{op=phi}|_]=Is0}=Blk0} ->
+ Is = update_phi_labels_is(Is0, Old, New),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ update_phi_labels(Ls, Old, New, Blocks);
+ #{L:=#b_blk{}} ->
+ %% No phi nodes in this block.
+ update_phi_labels(Ls, Old, New, Blocks0)
+ end;
+update_phi_labels([], _, _, Blocks) -> Blocks.
+
+-spec used(b_blk() | b_set() | terminator()) -> [var_name()].
+
+used(#b_blk{is=Is,last=Last}) ->
+ used_1([Last|Is], ordsets:new());
+used(#b_br{bool=#b_var{}=V}) ->
+ [V];
+used(#b_ret{arg=#b_var{}=V}) ->
+ [V];
+used(#b_set{op=phi,args=Args}) ->
+ ordsets:from_list([V || {#b_var{}=V,_} <- Args]);
+used(#b_set{args=Args}) ->
+ ordsets:from_list(used_args(Args));
+used(#b_switch{arg=#b_var{}=V}) ->
+ [V];
+used(_) -> [].
+
+-spec definitions(Blocks :: block_map()) -> definition_map().
+definitions(Blocks) ->
+ fold_instrs_rpo(fun(#b_set{ dst = Var }=I, Acc) ->
+ maps:put(Var, I, Acc);
+ (_Terminator, Acc) ->
+ Acc
+ end, [0], #{}, Blocks).
+
+-spec uses(Blocks :: block_map()) -> usage_map().
+uses(Blocks) ->
+ uses([0], Blocks).
+
+-spec uses(From, Blocks) -> usage_map() when
+ From :: [label()],
+ Blocks :: block_map().
+uses(From, Blocks) ->
+ fold_rpo(fun fold_uses_block/3, From, #{}, Blocks).
+
+fold_uses_block(Lbl, #b_blk{is=Is,last=Last}, UseMap0) ->
+ F = fun(I, UseMap) ->
+ foldl(fun(Var, Acc) ->
+ Uses0 = maps:get(Var, Acc, []),
+ Uses = [{Lbl, I} | Uses0],
+ maps:put(Var, Uses, Acc)
+ end, UseMap, used(I))
+ end,
+ F(Last, foldl(F, UseMap0, Is)).
+
+%%%
+%%% Internal functions.
+%%%
+
+is_commutative('and') -> true;
+is_commutative('or') -> true;
+is_commutative('xor') -> true;
+is_commutative('band') -> true;
+is_commutative('bor') -> true;
+is_commutative('bxor') -> true;
+is_commutative('+') -> true;
+is_commutative('*') -> true;
+is_commutative('=:=') -> true;
+is_commutative('==') -> true;
+is_commutative('=/=') -> true;
+is_commutative('/=') -> true;
+is_commutative(_) -> false.
+
+def_used_1([#b_blk{is=Is,last=Last}|Bs], Preds, Def0, Used0) ->
+ {Def,Used1} = def_used_is(Is, Preds, Def0, Used0),
+ Used = gb_sets:union(gb_sets:from_list(used(Last)), Used1),
+ def_used_1(Bs, Preds, Def, Used);
+def_used_1([], _Preds, Def, Used) ->
+ {ordsets:from_list(Def),gb_sets:to_list(Used)}.
+
+def_used_is([#b_set{op=phi,dst=Dst,args=Args}|Is],
+ Preds, Def0, Used0) ->
+ Def = [Dst|Def0],
+ %% We must be careful to only include variables that will
+ %% be used when arriving from one of the predecessor blocks
+ %% in Preds.
+ Used1 = [V || {#b_var{}=V,L} <- Args, gb_sets:is_member(L, Preds)],
+ Used = gb_sets:union(gb_sets:from_list(Used1), Used0),
+ def_used_is(Is, Preds, Def, Used);
+def_used_is([#b_set{dst=Dst}=I|Is], Preds, Def0, Used0) ->
+ Def = [Dst|Def0],
+ Used = gb_sets:union(gb_sets:from_list(used(I)), Used0),
+ def_used_is(Is, Preds, Def, Used);
+def_used_is([], _Preds, Def, Used) ->
+ {Def,Used}.
+
+def_1([#b_blk{is=Is}|Bs], Def0) ->
+ Def = def_is(Is, Def0),
+ def_1(Bs, Def);
+def_1([], Def) ->
+ ordsets:from_list(Def).
+
+def_is([#b_set{dst=Dst}|Is], Def) ->
+ def_is(Is, [Dst|Def]);
+def_is([], Def) -> Def.
+
+iter_dominators([{0,[]}|Ls], _Doms) ->
+ Dom = [0],
+ iter_dominators(Ls, #{0=>Dom});
+iter_dominators([{L,Preds}|Ls], Doms) ->
+ DomPreds = [maps:get(P, Doms) || P <- Preds, maps:is_key(P, Doms)],
+ Dom = ordsets:add_element(L, ordsets:intersection(DomPreds)),
+ iter_dominators(Ls, Doms#{L=>Dom});
+iter_dominators([], Doms) -> Doms.
+
+fold_rpo_1([L|Ls], Fun, Blocks, Acc0) ->
+ Block = maps:get(L, Blocks),
+ Acc = Fun(L, Block, Acc0),
+ fold_rpo_1(Ls, Fun, Blocks, Acc);
+fold_rpo_1([], _, _, Acc) -> Acc.
+
+fold_instrs_rpo_1([L|Ls], Fun, Blocks, Acc0) ->
+ #b_blk{is=Is,last=Last} = maps:get(L, Blocks),
+ Acc1 = foldl(Fun, Acc0, Is),
+ Acc = Fun(Last, Acc1),
+ fold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+fold_instrs_rpo_1([], _, _, Acc) -> Acc.
+
+mapfold_instrs_rpo_1([L|Ls], Fun, Blocks0, Acc0) ->
+ #b_blk{is=Is0,last=Last0} = Block0 = maps:get(L, Blocks0),
+ {Is,Acc1} = mapfoldl(Fun, Acc0, Is0),
+ {Last,Acc} = Fun(Last0, Acc1),
+ Block = Block0#b_blk{is=Is,last=Last},
+ Blocks = maps:put(L, Block, Blocks0),
+ mapfold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+mapfold_instrs_rpo_1([], _, Blocks, Acc) ->
+ {Blocks,Acc}.
+
+flatmapfold_instrs_rpo_1([L|Ls], Fun, Blocks0, Acc0) ->
+ #b_blk{is=Is0,last=Last0} = Block0 = maps:get(L, Blocks0),
+ {Is,Acc1} = flatmapfoldl(Fun, Acc0, Is0),
+ {[Last],Acc} = Fun(Last0, Acc1),
+ Block = Block0#b_blk{is=Is,last=Last},
+ Blocks = maps:put(L, Block, Blocks0),
+ flatmapfold_instrs_rpo_1(Ls, Fun, Blocks, Acc);
+flatmapfold_instrs_rpo_1([], _, Blocks, Acc) ->
+ {Blocks,Acc}.
+
+linearize_1([L|Ls], Blocks, Seen0, Acc0) ->
+ case cerl_sets:is_element(L, Seen0) of
+ true ->
+ linearize_1(Ls, Blocks, Seen0, Acc0);
+ false ->
+ Seen1 = cerl_sets:add_element(L, Seen0),
+ Block = maps:get(L, Blocks),
+ Successors = successors(Block),
+ {Acc,Seen} = linearize_1(Successors, Blocks, Seen1, Acc0),
+ linearize_1(Ls, Blocks, Seen, [{L,Block}|Acc])
+ end;
+linearize_1([], _, Seen, Acc) ->
+ {Acc,Seen}.
+
+fix_phis([{L,Blk0}|Bs], S) ->
+ Blk = case Blk0 of
+ #b_blk{is=[#b_set{op=phi}|_]=Is0} ->
+ Is = fix_phis_1(Is0, L, S),
+ Blk0#b_blk{is=Is};
+ #b_blk{} ->
+ Blk0
+ end,
+ Successors = successors(Blk),
+ [{L,Blk}|fix_phis(Bs, S#{L=>Successors})];
+fix_phis([], _) -> [].
+
+fix_phis_1([#b_set{op=phi,args=Args0}=I|Is], L, S) ->
+ Args = [{Val,Pred} || {Val,Pred} <- Args0,
+ is_successor(L, Pred, S)],
+ [I#b_set{args=Args}|fix_phis_1(Is, L, S)];
+fix_phis_1(Is, _, _) -> Is.
+
+is_successor(L, Pred, S) ->
+ case S of
+ #{Pred:=Successors} ->
+ member(L, Successors);
+ #{} ->
+ %% This block has been removed.
+ false
+ end.
+
+rpo_1([L|Ls], Blocks, Seen0, Acc0) ->
+ case cerl_sets:is_element(L, Seen0) of
+ true ->
+ rpo_1(Ls, Blocks, Seen0, Acc0);
+ false ->
+ Block = maps:get(L, Blocks),
+ Seen1 = cerl_sets:add_element(L, Seen0),
+ Successors = successors(Block),
+ {Acc,Seen} = rpo_1(Successors, Blocks, Seen1, Acc0),
+ rpo_1(Ls, Blocks, Seen, [L|Acc])
+ end;
+rpo_1([], _, Seen, Acc) ->
+ {Acc,Seen}.
+
+rename_var(#b_var{}=Old, Rename) ->
+ case Rename of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end;
+rename_var(#b_remote{mod=Mod0,name=Name0}=Remote, Rename) ->
+ Mod = rename_var(Mod0, Rename),
+ Name = rename_var(Name0, Rename),
+ Remote#b_remote{mod=Mod,name=Name};
+rename_var(Old, _) -> Old.
+
+rename_phi_vars([{Var,L}|As], Preds, Ren) ->
+ case cerl_sets:is_element(L, Preds) of
+ true ->
+ [{rename_var(Var, Ren),L}|rename_phi_vars(As, Preds, Ren)];
+ false ->
+ [{Var,L}|rename_phi_vars(As, Preds, Ren)]
+ end;
+rename_phi_vars([], _, _) -> [].
+
+map_instrs_1([L|Ls], Fun, Blocks0) ->
+ #b_blk{is=Is0,last=Last0} = Blk0 = maps:get(L, Blocks0),
+ Is = [Fun(I) || I <- Is0],
+ Last = Fun(Last0),
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ Blocks = maps:put(L, Blk, Blocks0),
+ map_instrs_1(Ls, Fun, Blocks);
+map_instrs_1([], _, Blocks) -> Blocks.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
+
+split_blocks_1([L|Ls], P, Blocks0, Count0) ->
+ #b_blk{is=Is0} = Blk = maps:get(L, Blocks0),
+ case split_blocks_is(Is0, P, []) of
+ {yes,Bef,Aft} ->
+ NewLbl = Count0,
+ Count = Count0 + 1,
+ Br = #b_br{bool=#b_literal{val=true},succ=NewLbl,fail=NewLbl},
+ BefBlk = Blk#b_blk{is=Bef,last=Br},
+ NewBlk = Blk#b_blk{is=Aft},
+ Blocks1 = Blocks0#{L:=BefBlk,NewLbl=>NewBlk},
+ Successors = successors(NewBlk),
+ Blocks = update_phi_labels(Successors, L, NewLbl, Blocks1),
+ split_blocks_1([NewLbl|Ls], P, Blocks, Count);
+ no ->
+ split_blocks_1(Ls, P, Blocks0, Count0)
+ end;
+split_blocks_1([], _, Blocks, Count) ->
+ {Blocks,Count}.
+
+split_blocks_is([I|Is], P, []) ->
+ split_blocks_is(Is, P, [I]);
+split_blocks_is([I|Is], P, Acc) ->
+ case P(I) of
+ true ->
+ {yes,reverse(Acc),[I|Is]};
+ false ->
+ split_blocks_is(Is, P, [I|Acc])
+ end;
+split_blocks_is([], _, _) -> no.
+
+update_phi_labels_is([#b_set{op=phi,args=Args0}=I0|Is], Old, New) ->
+ Args = [{Arg,rename_label(Lbl, Old, New)} || {Arg,Lbl} <- Args0],
+ I = I0#b_set{args=Args},
+ [I|update_phi_labels_is(Is, Old, New)];
+update_phi_labels_is(Is, _, _) -> Is.
+
+rename_label(Old, Old, New) -> New;
+rename_label(Lbl, _Old, _New) -> Lbl.
+
+used_args([#b_var{}=V|As]) ->
+ [V|used_args(As)];
+used_args([#b_remote{mod=Mod,name=Name}|As]) ->
+ used_args([Mod,Name|As]);
+used_args([_|As]) ->
+ used_args(As);
+used_args([]) -> [].
+
+used_1([H|T], Used0) ->
+ Used = ordsets:union(used(H), Used0),
+ used_1(T, Used);
+used_1([], Used) -> Used.
diff --git a/lib/compiler/src/beam_ssa.hrl b/lib/compiler/src/beam_ssa.hrl
new file mode 100644
index 0000000000..fa76b08453
--- /dev/null
+++ b/lib/compiler/src/beam_ssa.hrl
@@ -0,0 +1,66 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-record(b_module, {anno=#{} :: beam_ssa:anno(),
+ name :: module(),
+ exports :: [{atom(),arity()}],
+ attributes :: list(),
+ body :: [beam_ssa:b_function()]}).
+-record(b_function, {anno=#{} :: beam_ssa:anno(),
+ args :: [beam_ssa:b_var()],
+ bs :: #{beam_ssa:label():=beam_ssa:b_blk()},
+ cnt :: beam_ssa:label()}).
+
+-record(b_blk, {anno=#{} :: beam_ssa:anno(),
+ is :: [beam_ssa:b_set()],
+ last :: beam_ssa:terminator()}).
+-record(b_set, {anno=#{} :: beam_ssa:anno(),
+ dst=none :: 'none'|beam_ssa:b_var(),
+ op :: beam_ssa:op(),
+ args=[] :: [beam_ssa:argument()]}).
+
+%% Terminators.
+-record(b_ret, {anno=#{} :: beam_ssa:anno(),
+ arg :: beam_ssa:value()}).
+
+-record(b_br, {anno=#{},
+ bool :: beam_ssa:value(),
+ succ :: beam_ssa:label(),
+ fail :: beam_ssa:label()}).
+
+-record(b_switch, {anno=#{} :: beam_ssa:anno(),
+ arg :: beam_ssa:value(),
+ fail :: beam_ssa:label(),
+ list :: [{beam_ssa:b_literal(),beam_ssa:label()}]}).
+
+%% Values.
+-record(b_var, {name :: beam_ssa:var_name()}).
+
+-record(b_literal, {val :: beam_ssa:literal_value()}).
+
+-record(b_remote, {mod :: beam_ssa:value(),
+ name :: beam_ssa:value(),
+ arity :: non_neg_integer()}).
+
+-record(b_local, {name :: beam_ssa:b_literal(),
+ arity :: non_neg_integer()}).
+
+%% If this block exists, it calls erlang:error(badarg).
+-define(BADARG_BLOCK, 1).
diff --git a/lib/compiler/src/beam_ssa_bsm.erl b/lib/compiler/src/beam_ssa_bsm.erl
new file mode 100644
index 0000000000..9631bf3334
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_bsm.erl
@@ -0,0 +1,1043 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%
+%%% This pass optimizes bit syntax matching, and is centered around the concept
+%%% of "match context reuse" which is best explained through example. To put it
+%%% shortly we attempt to turn this:
+%%%
+%%% <<0,B/bits>> = A,
+%%% <<1,C/bits>> = B,
+%%% <<D,_/bits>> = C,
+%%% D.
+%%%
+%%% ... Into this:
+%%%
+%%% <<0,1,D,_/bits>>=A,
+%%% D.
+%%%
+%%% Which is much faster as it avoids the creation of intermediate terms. This
+%%% is especially noticeable in loops where such garbage is generated on each
+%%% iteration.
+%%%
+%%% The optimization itself is very simple and can be applied whenever there's
+%%% matching on the tail end of a binary; instead of creating a new binary and
+%%% starting a new match context on it, we reuse the match context used to
+%%% extract the tail and avoid the creation of both objects.
+%%%
+%%% The catch is that a match context isn't a proper type and nothing outside
+%%% of bit syntax match operations can handle them. We therefore need to make
+%%% sure that they never "leak" into other instructions, and most of the pass
+%%% revolves around getting around that limitation.
+%%%
+%%% Unlike most other passes we look at the whole module so we can combine
+%%% matches across function boundaries, greatly increasing the performance of
+%%% complex matches and loops.
+%%%
+
+-module(beam_ssa_bsm).
+
+-export([module/2, format_error/1]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [member/2, reverse/1, splitwith/2, map/2, foldl/3, mapfoldl/3,
+ nth/2, max/1, unzip/1]).
+
+-spec format_error(term()) -> nonempty_string().
+
+format_error(OptInfo) ->
+ format_opt_info(OptInfo).
+
+-spec module(Module, Options) -> Result when
+ Module :: beam_ssa:b_module(),
+ Options :: [compile:option()],
+ Result :: {ok, beam_ssa:b_module(), list()}.
+
+-define(PASS(N), {N,fun N/1}).
+
+module(#b_module{body=Fs0}=Module, Opts) ->
+ ModInfo = analyze_module(Module),
+
+ %% combine_matches is repeated after accept_context_args as the control
+ %% flow changes can enable further optimizations, as in the example below:
+ %%
+ %% a(<<0,X/binary>>) -> a(X);
+ %% a(A) when bit_size(A) =:= 52 -> bar;
+ %% a(<<1,X/binary>>) -> X. %% Match context will be reused here when
+ %% %% when repeated.
+
+ {Fs, _} = compile:run_sub_passes(
+ [?PASS(combine_matches),
+ ?PASS(accept_context_args),
+ ?PASS(combine_matches),
+ ?PASS(allow_context_passthrough),
+ ?PASS(skip_outgoing_tail_extraction),
+ ?PASS(annotate_context_parameters)],
+ {Fs0, ModInfo}),
+
+ Ws = case proplists:get_bool(bin_opt_info, Opts) of
+ true -> collect_opt_info(Fs);
+ false -> []
+ end,
+
+ {ok, Module#b_module{body=Fs}, Ws}.
+
+-type module_info() :: #{ func_id() => func_info() }.
+
+-type func_id() :: {Name :: atom(), Arity :: non_neg_integer()}.
+
+-type func_info() :: #{ has_bsm_ops => boolean(),
+ parameters => [#b_var{}],
+ parameter_info => #{ #b_var{} => param_info() } }.
+
+-type param_info() :: suitable_for_reuse |
+ {Problem :: atom(), Where :: term()}.
+
+-spec analyze_module(#b_module{}) -> module_info().
+
+analyze_module(#b_module{body=Fs}) ->
+ foldl(fun(#b_function{args=Parameters}=F, I) ->
+ FuncInfo = #{ has_bsm_ops => has_bsm_ops(F),
+ parameters => Parameters,
+ parameter_info => #{} },
+ FuncId = get_fa(F),
+ I#{ FuncId => FuncInfo }
+ end, #{}, Fs).
+
+has_bsm_ops(#b_function{bs=Blocks}) ->
+ hbo_blocks(maps:to_list(Blocks)).
+
+hbo_blocks([{_,#b_blk{is=Is}} | Blocks]) ->
+ case hbo_is(Is) of
+ false -> hbo_blocks(Blocks);
+ true -> true
+ end;
+hbo_blocks([]) ->
+ false.
+
+hbo_is([#b_set{op=bs_start_match} | _]) -> true;
+hbo_is([_I | Is]) -> hbo_is(Is);
+hbo_is([]) -> false.
+
+%% Checks whether it's legal to make a call with the given argument as a match
+%% context, returning the param_info() of the relevant parameter.
+-spec check_context_call(#b_set{}, Arg, CtxChain, ModInfo) -> param_info() when
+ Arg :: #b_var{},
+ CtxChain :: [#b_var{}],
+ ModInfo :: module_info().
+check_context_call(#b_set{args=Args}, Arg, CtxChain, ModInfo) ->
+ Aliases = [Arg | CtxChain],
+ ccc_1(Args, Arg, Aliases, ModInfo).
+
+ccc_1([#b_local{}=Call | Args], Ctx, Aliases, ModInfo) ->
+ %% Matching operations assume that their context isn't aliased (as in
+ %% pointer aliasing), so we must reject calls whose arguments contain more
+ %% than one reference to the context.
+ %%
+ %% TODO: Try to fall back to passing binaries in these cases. Partial reuse
+ %% is better than nothing.
+ UseCount = foldl(fun(Arg, C) ->
+ case member(Arg, Aliases) of
+ true -> C + 1;
+ false -> C
+ end
+ end, 0, Args),
+ if
+ UseCount =:= 1 ->
+ #b_local{name=#b_literal{val=Name},arity=Arity} = Call,
+ Callee = {Name, Arity},
+
+ ParamInfo = funcinfo_get(Callee, parameter_info, ModInfo),
+ Parameters = funcinfo_get(Callee, parameters, ModInfo),
+ Parameter = nth(1 + arg_index(Ctx, Args), Parameters),
+
+ case maps:find(Parameter, ParamInfo) of
+ {ok, suitable_for_reuse} ->
+ suitable_for_reuse;
+ {ok, Other} ->
+ {unsuitable_call, {Call, Other}};
+ error ->
+ {no_match_on_entry, Call}
+ end;
+ UseCount > 1 ->
+ {multiple_uses_in_call, Call}
+ end;
+ccc_1([#b_remote{}=Call | _Args], _Ctx, _CtxChain, _ModInfo) ->
+ {remote_call, Call};
+ccc_1([Fun | _Args], _Ctx, _CtxChain, _ModInfo) ->
+ %% TODO: It may be possible to support this in the future for locally
+ %% defined funs, including ones with free variables.
+ {fun_call, Fun}.
+
+%% Returns the index of Var in Args.
+arg_index(Var, Args) -> arg_index_1(Var, Args, 0).
+
+arg_index_1(Var, [Var | _Args], Index) -> Index;
+arg_index_1(Var, [_Arg | Args], Index) -> arg_index_1(Var, Args, Index + 1).
+
+is_tail_binary(#b_set{op=bs_match,args=[#b_literal{val=binary} | Rest]}) ->
+ member(#b_literal{val=all}, Rest);
+is_tail_binary(#b_set{op=bs_get_tail}) ->
+ true;
+is_tail_binary(_) ->
+ false.
+
+is_tail_binary(#b_var{}=Var, Defs) ->
+ case find_match_definition(Var, Defs) of
+ {ok, Def} -> is_tail_binary(Def);
+ _ -> false
+ end;
+is_tail_binary(_Literal, _Defs) ->
+ false.
+
+assert_match_context(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_match,args=[_,#b_var{}=Ctx|_]}} ->
+ assert_match_context(Ctx, Defs);
+ {ok, #b_set{op=bs_start_match}} ->
+ ok
+ end.
+
+find_match_definition(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_extract,args=[Ctx]}} -> maps:find(Ctx, Defs);
+ {ok, #b_set{op=bs_get_tail}=Def} -> {ok, Def};
+ _ -> error
+ end.
+
+%% Returns a list of all contexts that were used to extract Var.
+context_chain_of(#b_var{}=Var, Defs) ->
+ case maps:find(Var, Defs) of
+ {ok, #b_set{op=bs_match,args=[_,#b_var{}=Ctx|_]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ {ok, #b_set{op=bs_get_tail,args=[Ctx]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ {ok, #b_set{op=bs_extract,args=[Ctx]}} ->
+ [Ctx | context_chain_of(Ctx, Defs)];
+ _ ->
+ []
+ end.
+
+%% Grabs the match context used to produce the given variable.
+match_context_of(#b_var{}=Var, Defs) ->
+ Ctx = match_context_of_1(Var, Defs),
+ assert_match_context(Ctx, Defs),
+ Ctx.
+
+match_context_of_1(Var, Defs) ->
+ case maps:get(Var, Defs) of
+ #b_set{op=bs_extract,args=[#b_var{}=Ctx0]} ->
+ #b_set{op=bs_match,
+ args=[_,#b_var{}=Ctx|_]} = maps:get(Ctx0, Defs),
+ Ctx;
+ #b_set{op=bs_get_tail,args=[#b_var{}=Ctx]} ->
+ Ctx
+ end.
+
+funcinfo_get(#b_function{}=F, Attribute, ModInfo) ->
+ funcinfo_get(get_fa(F), Attribute, ModInfo);
+funcinfo_get({_,_}=Key, Attribute, ModInfo) ->
+ FuncInfo = maps:get(Key, ModInfo),
+ maps:get(Attribute, FuncInfo).
+
+funcinfo_set(#b_function{}=F, Attribute, Value, ModInfo) ->
+ funcinfo_set(get_fa(F), Attribute, Value, ModInfo);
+funcinfo_set(Key, Attribute, Value, ModInfo) ->
+ FuncInfo = maps:put(Attribute, Value, maps:get(Key, ModInfo, #{})),
+ maps:put(Key, FuncInfo, ModInfo).
+
+get_fa(#b_function{ anno = Anno }) ->
+ {_,Name,Arity} = maps:get(func_info, Anno),
+ {Name,Arity}.
+
+%% Replaces matched-out binaries with aliases that are lazily converted to
+%% binary form when used, allowing us to keep the "match path" free of binary
+%% creation.
+
+-spec alias_matched_binaries(Blocks, Counter, AliasMap) -> Result when
+ Blocks :: beam_ssa:block_map(),
+ Counter :: non_neg_integer(),
+ AliasMap :: match_alias_map(),
+ Result :: {Blocks, Counter}.
+
+-type match_alias_map() ::
+ #{ Binary :: #b_var{} =>
+ { %% Replace all uses of Binary with an alias after this
+ %% label.
+ AliasAfter :: beam_ssa:label(),
+ %% The match context whose tail is equal to Binary.
+ Context :: #b_var{} } }.
+
+%% Keeps track of the promotions we need to insert. They're partially keyed by
+%% location because they may not be valid on all execution paths and we may
+%% need to add redundant promotions in some cases.
+-type promotion_map() ::
+ #{ { PromoteAt :: beam_ssa:label(),
+ Variable :: #b_var{} } =>
+ Instruction :: #b_set{} }.
+
+-record(amb, { dominators :: beam_ssa:dominator_map(),
+ match_aliases :: match_alias_map(),
+ cnt :: non_neg_integer(),
+ promotions = #{} :: promotion_map() }).
+
+alias_matched_binaries(Blocks0, Counter, AliasMap) when AliasMap =/= #{} ->
+ State0 = #amb{ dominators = beam_ssa:dominators(Blocks0),
+ match_aliases = AliasMap,
+ cnt = Counter },
+ {Blocks, State} = beam_ssa:mapfold_blocks_rpo(fun amb_1/3, [0], State0,
+ Blocks0),
+ {amb_insert_promotions(Blocks, State), State#amb.cnt};
+alias_matched_binaries(Blocks, Counter, _AliasMap) ->
+ {Blocks, Counter}.
+
+amb_1(Lbl, #b_blk{is=Is0,last=Last0}=Block, State0) ->
+ {Is, State1} = mapfoldl(fun(I, State) ->
+ amb_assign_set(I, Lbl, State)
+ end, State0, Is0),
+ {Last, State} = amb_assign_last(Last0, Lbl, State1),
+ {Block#b_blk{is=Is,last=Last}, State}.
+
+amb_assign_set(#b_set{op=phi,args=Args0}=I, _Lbl, State0) ->
+ %% Phi node aliases are relative to their source block, not their
+ %% containing block.
+ {Args, State} =
+ mapfoldl(fun({Arg0, Lbl}, Acc) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, Acc),
+ {{Arg, Lbl}, State}
+ end, State0, Args0),
+ {I#b_set{args=Args}, State};
+amb_assign_set(#b_set{args=Args0}=I, Lbl, State0) ->
+ {Args, State} = mapfoldl(fun(Arg0, Acc) ->
+ amb_get_alias(Arg0, Lbl, Acc)
+ end, State0, Args0),
+ {I#b_set{args=Args}, State}.
+
+amb_assign_last(#b_ret{arg=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_ret{arg=Arg}, State};
+amb_assign_last(#b_switch{arg=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_switch{arg=Arg}, State};
+amb_assign_last(#b_br{bool=Arg0}=T, Lbl, State0) ->
+ {Arg, State} = amb_get_alias(Arg0, Lbl, State0),
+ {T#b_br{bool=Arg}, State}.
+
+amb_get_alias(#b_var{}=Arg, Lbl, State) ->
+ case maps:find(Arg, State#amb.match_aliases) of
+ {ok, {AliasAfter, Context}} ->
+ %% Our context may not have been created yet, so we skip assigning
+ %% an alias unless the given block is among our dominators.
+ Dominators = maps:get(Lbl, State#amb.dominators),
+ case ordsets:is_element(AliasAfter, Dominators) of
+ true -> amb_create_alias(Arg, Context, Lbl, State);
+ false -> {Arg, State}
+ end;
+ error ->
+ {Arg, State}
+ end;
+amb_get_alias(#b_remote{mod=Mod0,name=Name0}=Arg0, Lbl, State0) ->
+ {Mod, State1} = amb_get_alias(Mod0, Lbl, State0),
+ {Name, State} = amb_get_alias(Name0, Lbl, State1),
+ Arg = Arg0#b_remote{mod=Mod,name=Name},
+ {Arg, State};
+amb_get_alias(Arg, _Lbl, State) ->
+ {Arg, State}.
+
+amb_create_alias(#b_var{}=Arg0, Context, Lbl, State0) ->
+ Dominators = maps:get(Lbl, State0#amb.dominators),
+ Promotions0 = State0#amb.promotions,
+
+ PrevPromotions =
+ [maps:get({Dom, Arg0}, Promotions0)
+ || Dom <- Dominators, is_map_key({Dom, Arg0}, Promotions0)],
+
+ case PrevPromotions of
+ [_|_] ->
+ %% We've already created an alias prior to this block, so we'll
+ %% grab the most recent one to minimize stack use.
+
+ #b_set{dst=Alias} = max(PrevPromotions),
+ {Alias, State0};
+ [] ->
+ %% If we haven't created an alias we need to do so now. The
+ %% promotion will be inserted later by amb_insert_promotions/2.
+
+ Counter = State0#amb.cnt,
+ Alias = #b_var{name={'@ssa_bsm_alias', Counter}},
+ Promotion = #b_set{op=bs_get_tail,dst=Alias,args=[Context]},
+
+ Promotions = maps:put({Lbl, Arg0}, Promotion, Promotions0),
+ State = State0#amb{ promotions=Promotions, cnt=Counter+1 },
+
+ {Alias, State}
+ end.
+
+amb_insert_promotions(Blocks0, State) ->
+ F = fun({Lbl, #b_var{}}, Promotion, Blocks) ->
+ Block = maps:get(Lbl, Blocks),
+
+ Alias = Promotion#b_set.dst,
+ {Before, After} = splitwith(
+ fun(#b_set{args=Args}) ->
+ not is_var_in_args(Alias, Args)
+ end, Block#b_blk.is),
+ Is = Before ++ [Promotion | After],
+
+ maps:put(Lbl, Block#b_blk{is=Is}, Blocks)
+ end,
+ maps:fold(F, Blocks0, State#amb.promotions).
+
+is_var_in_args(Var, [Var | _]) -> true;
+is_var_in_args(Var, [#b_remote{name=Var} | _]) -> true;
+is_var_in_args(Var, [#b_remote{mod=Var} | _]) -> true;
+is_var_in_args(Var, [_ | Args]) -> is_var_in_args(Var, Args);
+is_var_in_args(_Var, []) -> false.
+
+%%%
+%%% Subpasses
+%%%
+
+%% Removes superflous chained bs_start_match instructions in the same
+%% function. When matching on an extracted tail binary, or on a binary we've
+%% already matched on, we reuse the original match context.
+%%
+%% This pass runs first since it makes subsequent optimizations more effective
+%% by removing spots where promotion would be required.
+
+-type prior_match_map() ::
+ #{ Binary :: #b_var{} =>
+ [{ %% The context and success label of a previous
+ %% bs_start_match made on this binary.
+ ValidAfter :: beam_ssa:label(),
+ Context :: #b_var{} }] }.
+
+-record(cm, { definitions :: beam_ssa:definition_map(),
+ dominators :: beam_ssa:dominator_map(),
+ blocks :: beam_ssa:block_map(),
+ match_aliases = #{} :: match_alias_map(),
+ prior_matches = #{} :: prior_match_map(),
+ renames = #{} :: beam_ssa:rename_map() }).
+
+combine_matches({Fs0, ModInfo}) ->
+ Fs = map(fun(F) -> combine_matches(F, ModInfo) end, Fs0),
+ {Fs, ModInfo}.
+
+combine_matches(#b_function{bs=Blocks0,cnt=Counter0}=F, ModInfo) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo) of
+ true ->
+ {Blocks1, State} =
+ beam_ssa:mapfold_blocks_rpo(
+ fun(Lbl, #b_blk{is=Is0}=Block0, State0) ->
+ {Is, State} = cm_1(Is0, [], Lbl, State0),
+ {Block0#b_blk{is=Is}, State}
+ end, [0],
+ #cm{ definitions = beam_ssa:definitions(Blocks0),
+ dominators = beam_ssa:dominators(Blocks0),
+ blocks = Blocks0 },
+ Blocks0),
+
+ Blocks2 = beam_ssa:rename_vars(State#cm.renames, [0], Blocks1),
+
+ {Blocks, Counter} = alias_matched_binaries(Blocks2, Counter0,
+ State#cm.match_aliases),
+
+ F#b_function{ bs=Blocks, cnt=Counter };
+ false ->
+ F
+ end.
+
+cm_1([#b_set{ op=bs_start_match,
+ dst=Ctx,
+ args=[Src] },
+ #b_set{ op=succeeded,
+ dst=Bool,
+ args=[Ctx] }]=MatchSeq, Acc0, Lbl, State0) ->
+ Acc = reverse(Acc0),
+ case is_tail_binary(Src, State0#cm.definitions) of
+ true -> cm_combine_tail(Src, Ctx, Bool, Acc, State0);
+ false -> cm_handle_priors(Src, Ctx, Bool, Acc, MatchSeq, Lbl, State0)
+ end;
+cm_1([I | Is], Acc, Lbl, State) ->
+ cm_1(Is, [I | Acc], Lbl, State);
+cm_1([], Acc, _Lbl, State) ->
+ {reverse(Acc), State}.
+
+%% If we're dominated by at least one match on the same source, we can reuse
+%% the context created by that match.
+cm_handle_priors(Src, DstCtx, Bool, Acc, MatchSeq, Lbl, State0) ->
+ PriorCtxs = case maps:find(Src, State0#cm.prior_matches) of
+ {ok, Priors} ->
+ %% We've seen other match contexts on this source, but
+ %% we can only consider the ones whose success path
+ %% dominate us.
+ Dominators = maps:get(Lbl, State0#cm.dominators, []),
+ [Ctx || {ValidAfter, Ctx} <- Priors,
+ ordsets:is_element(ValidAfter, Dominators)];
+ error ->
+ []
+ end,
+ case PriorCtxs of
+ [Ctx|_] ->
+ Renames0 = State0#cm.renames,
+ Renames = Renames0#{ Bool => #b_literal{val=true}, DstCtx => Ctx },
+ {Acc, State0#cm{ renames = Renames }};
+ [] ->
+ %% Since we lack a prior match, we need to register this one in
+ %% case we dominate another.
+ State = cm_register_prior(Src, DstCtx, Lbl, State0),
+ {Acc ++ MatchSeq, State}
+ end.
+
+cm_register_prior(Src, DstCtx, Lbl, State) ->
+ Block = maps:get(Lbl, State#cm.blocks),
+ #b_br{succ=ValidAfter} = Block#b_blk.last,
+
+ Priors0 = maps:get(Src, State#cm.prior_matches, []),
+ Priors = [{ValidAfter, DstCtx} | Priors0],
+
+ PriorMatches = maps:put(Src, Priors, State#cm.prior_matches),
+ State#cm{ prior_matches = PriorMatches }.
+
+cm_combine_tail(Src, DstCtx, Bool, Acc, State0) ->
+ SrcCtx = match_context_of(Src, State0#cm.definitions),
+
+ %% We replace the source with a context alias as it normally won't be used
+ %% on the happy path after being matched, and the added cost of conversion
+ %% is negligible if it is.
+ Aliases = maps:put(Src, {0, SrcCtx}, State0#cm.match_aliases),
+
+ Renames0 = State0#cm.renames,
+ Renames = Renames0#{ Bool => #b_literal{val=true}, DstCtx => SrcCtx },
+
+ State = State0#cm{ match_aliases = Aliases, renames = Renames },
+
+ {Acc, State}.
+
+%% Lets functions accept match contexts as arguments. The parameter must be
+%% unused before the bs_start_match instruction, and it must be matched in the
+%% first block.
+
+-record(aca, { unused_parameters :: ordsets:ordset(#b_var{}),
+ counter :: non_neg_integer(),
+ parameter_info = #{} :: #{ #b_var{} => param_info() },
+ match_aliases = #{} :: match_alias_map() }).
+
+accept_context_args({Fs, ModInfo}) ->
+ mapfoldl(fun accept_context_args/2, ModInfo, Fs).
+
+accept_context_args(#b_function{bs=Blocks0}=F, ModInfo0) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo0) of
+ true ->
+ Parameters = ordsets:from_list(funcinfo_get(F, parameters, ModInfo0)),
+ State0 = #aca{ unused_parameters = Parameters,
+ counter = F#b_function.cnt },
+
+ {Blocks1, State} = aca_1(Blocks0, State0),
+ {Blocks, Counter} = alias_matched_binaries(Blocks1,
+ State#aca.counter,
+ State#aca.match_aliases),
+
+ ModInfo = funcinfo_set(F, parameter_info, State#aca.parameter_info,
+ ModInfo0),
+
+ {F#b_function{bs=Blocks,cnt=Counter}, ModInfo};
+ false ->
+ {F, ModInfo0}
+ end.
+
+aca_1(Blocks, State) ->
+ %% We only handle block 0 as we don't yet support starting a match after a
+ %% test. This is generally good enough as the sys_core_bsm pass makes the
+ %% match instruction come first if possible, and it's rare for a function
+ %% to binary-match several parameters at once.
+ EntryBlock = maps:get(0, Blocks),
+ aca_enable_reuse(EntryBlock#b_blk.is, EntryBlock, Blocks, [], State).
+
+aca_enable_reuse([#b_set{op=bs_start_match,args=[Src]}=I0 | Rest],
+ EntryBlock, Blocks0, Acc, State0) ->
+ case aca_is_reuse_safe(Src, State0) of
+ true ->
+ {I, Last, Blocks1, State} =
+ aca_reuse_context(I0, EntryBlock, Blocks0, State0),
+
+ Is = reverse([I|Acc]) ++ Rest,
+ Blocks = maps:put(0, EntryBlock#b_blk{is=Is,last=Last}, Blocks1),
+
+ {Blocks, State};
+ false ->
+ {Blocks0, State0}
+ end;
+aca_enable_reuse([I | Is], EntryBlock, Blocks, Acc, State0) ->
+ UnusedParams0 = State0#aca.unused_parameters,
+ case ordsets:intersection(UnusedParams0, beam_ssa:used(I)) of
+ [] ->
+ aca_enable_reuse(Is, EntryBlock, Blocks, [I | Acc], State0);
+ PrematureUses ->
+ UnusedParams = ordsets:subtract(UnusedParams0, PrematureUses),
+
+ %% Mark the offending parameters as unsuitable for context reuse.
+ ParamInfo = foldl(fun(A, Ps) ->
+ maps:put(A, {used_before_match, I}, Ps)
+ end, State0#aca.parameter_info, PrematureUses),
+
+ State = State0#aca{ unused_parameters = UnusedParams,
+ parameter_info = ParamInfo },
+ aca_enable_reuse(Is, EntryBlock, Blocks, [I | Acc], State)
+ end;
+aca_enable_reuse([], _EntryBlock, Blocks, _Acc, State) ->
+ {Blocks, State}.
+
+aca_is_reuse_safe(Src, State) ->
+ %% Context reuse is unsafe unless all uses are dominated by the start_match
+ %% instruction. Since we only process block 0 it's enough to check if
+ %% they're unused so far.
+ ordsets:is_element(Src, State#aca.unused_parameters).
+
+aca_reuse_context(#b_set{dst=Dst, args=[Src]}=I0, Block, Blocks0, State0) ->
+ %% When matching fails on a reused context it needs to be converted back
+ %% to a binary. We only need to do this on the success path since it can't
+ %% be a context on the type failure path, but it's very common for these
+ %% to converge which requires special handling.
+ {State1, Last, Blocks} =
+ aca_handle_convergence(Src, State0, Block#b_blk.last, Blocks0),
+
+ Aliases = maps:put(Src, {Last#b_br.succ, Dst}, State1#aca.match_aliases),
+ ParamInfo = maps:put(Src, suitable_for_reuse, State1#aca.parameter_info),
+
+ State = State1#aca{ match_aliases = Aliases,
+ parameter_info = ParamInfo },
+
+ I = beam_ssa:add_anno(accepts_match_contexts, true, I0),
+
+ {I, Last, Blocks, State}.
+
+aca_handle_convergence(Src, State0, Last0, Blocks0) ->
+ #b_br{fail=Fail0,succ=Succ0} = Last0,
+
+ SuccPath = beam_ssa:rpo([Succ0], Blocks0),
+ FailPath = beam_ssa:rpo([Fail0], Blocks0),
+
+ %% The promotion logic in alias_matched_binaries breaks down if the source
+ %% is used after the fail/success paths converge, as we have no way to tell
+ %% whether the source is a match context or something else past that point.
+ %%
+ %% We could handle this through clever insertion of phi nodes but it's
+ %% far simpler to copy either branch in its entirety. It doesn't matter
+ %% which one as long as they become disjoint.
+ ConvergedPaths = ordsets:intersection(
+ ordsets:from_list(SuccPath),
+ ordsets:from_list(FailPath)),
+
+ case maps:is_key(Src, beam_ssa:uses(ConvergedPaths, Blocks0)) of
+ true ->
+ case shortest(SuccPath, FailPath) of
+ left ->
+ {Succ, Blocks, Counter} =
+ aca_copy_successors(Succ0, Blocks0, State0#aca.counter),
+ State = State0#aca{ counter = Counter },
+ {State, Last0#b_br{succ=Succ}, Blocks};
+ right ->
+ {Fail, Blocks, Counter} =
+ aca_copy_successors(Fail0, Blocks0, State0#aca.counter),
+ State = State0#aca{ counter = Counter },
+ {State, Last0#b_br{fail=Fail}, Blocks}
+ end;
+ false ->
+ {State0, Last0, Blocks0}
+ end.
+
+shortest([_|As], [_|Bs]) -> shortest(As, Bs);
+shortest([], _) -> left;
+shortest(_, []) -> right.
+
+%% Copies all successor blocks of Lbl, returning the label to the entry block
+%% of this copy. Since the copied blocks aren't referenced anywhere else, they
+%% are all guaranteed to be dominated by Lbl.
+aca_copy_successors(Lbl0, Blocks0, Counter0) ->
+ %% Building the block rename map up front greatly simplifies phi node
+ %% handling.
+ Path = beam_ssa:rpo([Lbl0], Blocks0),
+ {BRs, Counter1} = aca_cs_build_brs(Path, Counter0, #{}),
+ {Blocks, Counter} = aca_cs_1(Path, Blocks0, Counter1, #{}, BRs, #{}),
+ Lbl = maps:get(Lbl0, BRs),
+ {Lbl, Blocks, Counter}.
+
+aca_cs_build_brs([Lbl | Path], Counter0, Acc) ->
+ aca_cs_build_brs(Path, Counter0 + 1, maps:put(Lbl, Counter0, Acc));
+aca_cs_build_brs([], Counter, Acc) ->
+ {Acc, Counter}.
+
+aca_cs_1([Lbl0 | Path], Blocks, Counter0, VRs0, BRs, Acc0) ->
+ Block0 = maps:get(Lbl0, Blocks),
+ Lbl = maps:get(Lbl0, BRs),
+ {VRs, Block, Counter} = aca_cs_block(Block0, Counter0, VRs0, BRs),
+ Acc = maps:put(Lbl, Block, Acc0),
+ aca_cs_1(Path, Blocks, Counter, VRs, BRs, Acc);
+aca_cs_1([], Blocks, Counter, _VRs, _BRs, Acc) ->
+ {maps:merge(Blocks, Acc), Counter}.
+
+aca_cs_block(#b_blk{is=Is0,last=Last0}=Block0, Counter0, VRs0, BRs) ->
+ {VRs, Is, Counter} = aca_cs_is(Is0, Counter0, VRs0, BRs, []),
+ Last = aca_cs_last(Last0, VRs, BRs),
+ Block = Block0#b_blk{is=Is,last=Last},
+ {VRs, Block, Counter}.
+
+aca_cs_is([#b_set{op=Op,
+ dst=Dst0,
+ args=Args0}=I0 | Is],
+ Counter0, VRs0, BRs, Acc) ->
+ Args = case Op of
+ phi -> aca_cs_args_phi(Args0, VRs0, BRs);
+ _ -> aca_cs_args(Args0, VRs0)
+ end,
+ Counter = Counter0 + 1,
+ Dst = #b_var{name={'@ssa_bsm_aca',Counter}},
+ I = I0#b_set{dst=Dst,args=Args},
+ VRs = maps:put(Dst0, Dst, VRs0),
+ aca_cs_is(Is, Counter, VRs, BRs, [I | Acc]);
+aca_cs_is([], Counter, VRs, _BRs, Acc) ->
+ {VRs, reverse(Acc), Counter}.
+
+aca_cs_last(#b_switch{arg=Arg0,list=Switch0,fail=Fail0}=Sw, VRs, BRs) ->
+ Switch = [{Literal, maps:get(Lbl, BRs)} || {Literal, Lbl} <- Switch0],
+ Sw#b_switch{arg=aca_cs_arg(Arg0, VRs),
+ fail=maps:get(Fail0, BRs),
+ list=Switch};
+aca_cs_last(#b_br{bool=Arg0,succ=Succ0,fail=Fail0}=Br, VRs, BRs) ->
+ Br#b_br{bool=aca_cs_arg(Arg0, VRs),
+ succ=maps:get(Succ0, BRs),
+ fail=maps:get(Fail0, BRs)};
+aca_cs_last(#b_ret{arg=Arg0}=Ret, VRs, _BRs) ->
+ Ret#b_ret{arg=aca_cs_arg(Arg0, VRs)}.
+
+aca_cs_args_phi([{Arg, Lbl} | Args], VRs, BRs) ->
+ case BRs of
+ #{ Lbl := New } ->
+ [{aca_cs_arg(Arg, VRs), New} | aca_cs_args_phi(Args, VRs, BRs)];
+ #{} ->
+ aca_cs_args_phi(Args, VRs, BRs)
+ end;
+aca_cs_args_phi([], _VRs, _BRs) ->
+ [].
+
+aca_cs_args([Arg | Args], VRs) ->
+ [aca_cs_arg(Arg, VRs) | aca_cs_args(Args, VRs)];
+aca_cs_args([], _VRs) ->
+ [].
+
+aca_cs_arg(#b_remote{mod=Mod0,name=Name0}=Rem, VRs) ->
+ Mod = aca_cs_arg(Mod0, VRs),
+ Name = aca_cs_arg(Name0, VRs),
+ Rem#b_remote{mod=Mod,name=Name};
+aca_cs_arg(Arg, VRs) ->
+ case VRs of
+ #{ Arg := New } -> New;
+ #{} -> Arg
+ end.
+
+%% Allows contexts to pass through "wrapper functions" where the context is
+%% passed directly to a function that accepts match contexts (including other
+%% wrappers).
+%%
+%% This does not alter the function in any way, it only changes parameter info
+%% so that skip_outgoing_tail_extraction is aware that it's safe to pass
+%% contexts to us.
+
+allow_context_passthrough({Fs, ModInfo0}) ->
+ ModInfo =
+ acp_forward_params([{F, beam_ssa:uses(F#b_function.bs)} || F <- Fs],
+ ModInfo0),
+ {Fs, ModInfo}.
+
+acp_forward_params(FsUses, ModInfo0) ->
+ F = fun({#b_function{args=Parameters}=Func, UseMap}, ModInfo) ->
+ ParamInfo =
+ foldl(fun(Param, ParamInfo) ->
+ Uses = maps:get(Param, UseMap, []),
+ acp_1(Param, Uses, ModInfo, ParamInfo)
+ end,
+ funcinfo_get(Func, parameter_info, ModInfo),
+ Parameters),
+ funcinfo_set(Func, parameter_info, ParamInfo, ModInfo)
+ end,
+ %% Allowing context passthrough on one function may make it possible to
+ %% enable it on another, so it needs to be repeated for maximum effect.
+ case foldl(F, ModInfo0, FsUses) of
+ ModInfo0 -> ModInfo0;
+ Changed -> acp_forward_params(FsUses, Changed)
+ end.
+
+%% We have no way to know if an argument is a context, so it's only safe to
+%% forward them if they're passed exactly once in the first block. Any other
+%% uses are unsafe, including function_clause errors.
+acp_1(Param, [{0, #b_set{op=call}=I}], ModInfo, ParamInfo) ->
+ %% We don't need to provide a context chain as our callers make sure that
+ %% multiple arguments never reference the same context.
+ case check_context_call(I, Param, [], ModInfo) of
+ {no_match_on_entry, _} -> ParamInfo;
+ Other -> maps:put(Param, Other, ParamInfo)
+ end;
+acp_1(_Param, _Uses, _ModInfo, ParamInfo) ->
+ ParamInfo.
+
+%% This is conceptually similar to combine_matches but operates across
+%% functions. Whenever a tail binary is passed to a parameter that accepts
+%% match contexts we'll pass the context instead, improving performance by
+%% avoiding the creation of a new match context in the callee.
+%%
+%% We also create an alias to delay extraction until it's needed as an actual
+%% binary, which is often rare on the happy path. The cost of being wrong is
+%% negligible (`bs_test_unit + bs_get_tail` vs `bs_get_binary`) so we're
+%% applying it unconditionally to keep things simple.
+
+-record(sote, { definitions :: beam_ssa:definition_map(),
+ mod_info :: module_info(),
+ match_aliases = #{} :: match_alias_map() }).
+
+skip_outgoing_tail_extraction({Fs0, ModInfo}) ->
+ Fs = map(fun(F) -> skip_outgoing_tail_extraction(F, ModInfo) end, Fs0),
+ {Fs, ModInfo}.
+
+skip_outgoing_tail_extraction(#b_function{bs=Blocks0}=F, ModInfo) ->
+ case funcinfo_get(F, has_bsm_ops, ModInfo) of
+ true ->
+ State0 = #sote{ definitions = beam_ssa:definitions(Blocks0),
+ mod_info = ModInfo },
+
+ {Blocks1, State} = beam_ssa:mapfold_instrs_rpo(
+ fun sote_rewrite_calls/2, [0], State0, Blocks0),
+
+ {Blocks, Counter} = alias_matched_binaries(Blocks1,
+ F#b_function.cnt,
+ State#sote.match_aliases),
+
+ F#b_function{bs=Blocks,cnt=Counter};
+ false ->
+ F
+ end.
+
+sote_rewrite_calls(#b_set{op=call,args=Args}=Call, State) ->
+ sote_rewrite_call(Call, Args, [], State);
+sote_rewrite_calls(I, State) ->
+ {I, State}.
+
+sote_rewrite_call(Call, [], ArgsOut, State) ->
+ {Call#b_set{args=reverse(ArgsOut)}, State};
+sote_rewrite_call(Call0, [Arg | ArgsIn], ArgsOut, State0) ->
+ case is_tail_binary(Arg, State0#sote.definitions) of
+ true ->
+ CtxChain = context_chain_of(Arg, State0#sote.definitions),
+ case check_context_call(Call0, Arg, CtxChain, State0#sote.mod_info) of
+ suitable_for_reuse ->
+ Ctx = match_context_of(Arg, State0#sote.definitions),
+
+ MatchAliases0 = State0#sote.match_aliases,
+ MatchAliases = maps:put(Arg, {0, Ctx}, MatchAliases0),
+ State = State0#sote{ match_aliases = MatchAliases },
+
+ Call = beam_ssa:add_anno(bsm_info, context_reused, Call0),
+ sote_rewrite_call(Call, ArgsIn, [Ctx | ArgsOut], State);
+ Other ->
+ Call = beam_ssa:add_anno(bsm_info, Other, Call0),
+ sote_rewrite_call(Call, ArgsIn, [Arg | ArgsOut], State0)
+ end;
+ false ->
+ sote_rewrite_call(Call0, ArgsIn, [Arg | ArgsOut], State0)
+ end.
+
+%% Adds parameter_type_info annotations to help the validator determine whether
+%% our optimizations were safe.
+
+annotate_context_parameters({Fs, ModInfo}) ->
+ mapfoldl(fun annotate_context_parameters/2, ModInfo, Fs).
+
+annotate_context_parameters(F, ModInfo) ->
+ ParamInfo = funcinfo_get(F, parameter_info, ModInfo),
+ TypeAnno0 = beam_ssa:get_anno(parameter_type_info, F, #{}),
+ TypeAnno = maps:fold(fun(K, _V, Acc) when is_map_key(K, Acc) ->
+ %% Assertion.
+ error(conflicting_parameter_types);
+ (K, suitable_for_reuse, Acc) ->
+ Acc#{ K => match_context };
+ (_K, _V, Acc) ->
+ Acc
+ end, TypeAnno0, ParamInfo),
+ {beam_ssa:add_anno(parameter_type_info, TypeAnno, F), ModInfo}.
+
+%%%
+%%% +bin_opt_info
+%%%
+
+collect_opt_info(Fs) ->
+ foldl(fun(#b_function{bs=Blocks}=F, Acc0) ->
+ UseMap = beam_ssa:uses(Blocks),
+ Where = beam_ssa:get_anno(location, F, []),
+ beam_ssa:fold_instrs_rpo(
+ fun(I, Acc) ->
+ collect_opt_info_1(I, Where, UseMap, Acc)
+ end, [0], Acc0, Blocks)
+ end, [], Fs).
+
+collect_opt_info_1(#b_set{op=Op,anno=Anno,dst=Dst}=I, Where, UseMap, Acc0) ->
+ case is_tail_binary(I) of
+ true when Op =:= bs_match ->
+ %% The uses include when the context is passed raw, so we discard
+ %% everything but the bs_extract instruction to limit warnings to
+ %% unoptimized uses.
+ Uses0 = maps:get(Dst, UseMap, []),
+ case [E || {_, #b_set{op=bs_extract}=E} <- Uses0] of
+ [Use] -> add_unopt_binary_info(Use, false, Where, UseMap, Acc0);
+ [] -> Acc0
+ end;
+ true ->
+ %% Add a warning for each use. Note that we don't do anything
+ %% special if unused as a later pass will remove this instruction
+ %% anyway.
+ Uses = maps:get(Dst, UseMap, []),
+ foldl(fun({_Lbl, Use}, Acc) ->
+ add_unopt_binary_info(Use, false, Where, UseMap, Acc)
+ end, Acc0, Uses);
+ false ->
+ add_opt_info(Anno, Where, Acc0)
+ end;
+collect_opt_info_1(#b_ret{anno=Anno}, Where, _UseMap, Acc) ->
+ add_opt_info(Anno, Where, Acc);
+collect_opt_info_1(_I, _Where, _Uses, Acc) ->
+ Acc.
+
+add_opt_info(Anno, Where, Acc) ->
+ case maps:find(bsm_info, Anno) of
+ {ok, Term} -> [make_warning(Term, Anno, Where) | Acc];
+ error -> Acc
+ end.
+
+%% When an alias is promoted we need to figure out where it goes to ignore
+%% warnings for compiler-generated things, and provide more useful warnings in
+%% general.
+%%
+%% We track whether the binary has been used to build another term because it
+%% can be helpful when there's no line information.
+
+add_unopt_binary_info(#b_set{op=Follow,dst=Dst}, _Nested, Where, UseMap, Acc0)
+ when Follow =:= put_tuple;
+ Follow =:= put_list;
+ Follow =:= put_map ->
+ %% Term-building instructions.
+ {_, Uses} = unzip(maps:get(Dst, UseMap, [])),
+ foldl(fun(Use, Acc) ->
+ add_unopt_binary_info(Use, true, Where, UseMap, Acc)
+ end, Acc0, Uses);
+add_unopt_binary_info(#b_set{op=Follow,dst=Dst}, Nested, Where, UseMap, Acc0)
+ when Follow =:= bs_extract;
+ Follow =:= phi ->
+ %% Non-building instructions that need to be followed.
+ {_, Uses} = unzip(maps:get(Dst, UseMap, [])),
+ foldl(fun(Use, Acc) ->
+ add_unopt_binary_info(Use, Nested, Where, UseMap, Acc)
+ end, Acc0, Uses);
+add_unopt_binary_info(#b_set{op=call,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error}} |
+ _Ignored]},
+ _Nested, _Where, _UseMap, Acc) ->
+ %% There's no nice way to tell compiler-generated exceptions apart from
+ %% user ones so we ignore them all. I doubt anyone cares.
+ Acc;
+add_unopt_binary_info(#b_switch{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_set{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_ret{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc];
+add_unopt_binary_info(#b_br{anno=Anno}=I, Nested, Where, _UseMap, Acc) ->
+ [make_promotion_warning(I, Nested, Anno, Where) | Acc].
+
+make_promotion_warning(I, Nested, Anno, Where) ->
+ make_warning({binary_created, I, Nested}, Anno, Where).
+
+make_warning(Term, Anno, Where) ->
+ {File, Line} = maps:get(location, Anno, Where),
+ {File,[{Line,?MODULE,Term}]}.
+
+format_opt_info(context_reused) ->
+ "OPTIMIZED: match context reused";
+format_opt_info({binary_created, _, _}=Promotion) ->
+ io_lib:format("BINARY CREATED: ~s", [format_opt_info_1(Promotion)]);
+format_opt_info(Other) ->
+ io_lib:format("NOT OPTIMIZED: ~s", [format_opt_info_1(Other)]).
+
+format_opt_info_1({binary_created, #b_set{op=call,args=[Call|_]}, false}) ->
+ io_lib:format("binary is used in call to ~s which doesn't support "
+ "context reuse", [format_call(Call)]);
+format_opt_info_1({binary_created, #b_set{op=call,args=[Call|_]}, true}) ->
+ io_lib:format("binary is used in term passed to ~s",
+ [format_call(Call)]);
+format_opt_info_1({binary_created, #b_set{op={bif, BIF},args=Args}, false}) ->
+ io_lib:format("binary is used in ~p/~p which doesn't support context "
+ "reuse", [BIF, length(Args)]);
+format_opt_info_1({binary_created, #b_set{op={bif, BIF},args=Args}, true}) ->
+ io_lib:format("binary is used in term passed to ~p/~p",
+ [BIF, length(Args)]);
+format_opt_info_1({binary_created, #b_set{op=Op}, false}) ->
+ io_lib:format("binary is used in '~p' which doesn't support context "
+ "reuse", [Op]);
+format_opt_info_1({binary_created, #b_set{op=Op}, true}) ->
+ io_lib:format("binary is used in term passed to '~p'", [Op]);
+format_opt_info_1({binary_created, #b_ret{}, false}) ->
+ io_lib:format("binary is returned from the function", []);
+format_opt_info_1({binary_created, #b_ret{}, true}) ->
+ io_lib:format("binary is used in a term that is returned from the "
+ "function", []);
+format_opt_info_1({unsuitable_call, {Call, Inner}}) ->
+ io_lib:format("binary used in call to ~s, where ~s",
+ [format_call(Call), format_opt_info_1(Inner)]);
+format_opt_info_1({remote_call, Call}) ->
+ io_lib:format("binary is used in remote call to ~s", [format_call(Call)]);
+format_opt_info_1({fun_call, Call}) ->
+ io_lib:format("binary is used in fun call (~s)",
+ [format_call(Call)]);
+format_opt_info_1({multiple_uses_in_call, Call}) ->
+ io_lib:format("binary is passed as multiple arguments to ~s",
+ [format_call(Call)]);
+format_opt_info_1({no_match_on_entry, Call}) ->
+ io_lib:format("binary is used in call to ~s which does not begin with a "
+ "suitable binary match", [format_call(Call)]);
+format_opt_info_1({used_before_match, #b_set{op=call,args=[Call|_]}}) ->
+ io_lib:format("binary is used in call to ~s before being matched",
+ [format_call(Call)]);
+format_opt_info_1({used_before_match, #b_set{op={bif, BIF},args=Args}}) ->
+ io_lib:format("binary is used in ~p/~p before being matched",
+ [BIF, length(Args)]);
+format_opt_info_1({used_before_match, #b_set{op=phi}}) ->
+ io_lib:format("binary is returned from an expression before being "
+ "matched", []);
+format_opt_info_1({used_before_match, #b_set{op=Op}}) ->
+ io_lib:format("binary is used in '~p' before being matched",[Op]);
+format_opt_info_1(Term) ->
+ io_lib:format("~w", [Term]).
+
+format_call(#b_local{name=#b_literal{val=F},arity=A}) ->
+ io_lib:format("~p/~p", [F, A]);
+format_call(#b_remote{mod=#b_literal{val=M},name=#b_literal{val=F},arity=A}) ->
+ io_lib:format("~p:~p/~p", [M, F, A]);
+format_call(Fun) ->
+ io_lib:format("~p", [Fun]).
diff --git a/lib/compiler/src/beam_ssa_codegen.erl b/lib/compiler/src/beam_ssa_codegen.erl
new file mode 100644
index 0000000000..3c14062d0b
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_codegen.erl
@@ -0,0 +1,2034 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Generate BEAM assembly code from the SSA format.
+
+-module(beam_ssa_codegen).
+
+-export([module/2]).
+-export([classify_heap_need/2]). %Called from beam_ssa_pre_codegen.
+
+-export_type([ssa_register/0]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [foldl/3,keymember/3,keysort/2,last/1,map/2,mapfoldl/3,
+ reverse/1,reverse/2,sort/1,splitwith/2,takewhile/2]).
+
+-record(cg, {lcount=1 :: beam_label(), %Label counter
+ functable=#{} :: #{fa()=>beam_label()},
+ labels=#{} :: #{ssa_label()=>0|beam_label()},
+ used_labels=gb_sets:empty() :: gb_sets:set(ssa_label()),
+ regs=#{} :: #{beam_ssa:var_name()=>ssa_register()},
+ ultimate_fail=1 :: beam_label(),
+ catches=gb_sets:empty() :: gb_sets:set(ssa_label())
+ }).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_asm:module_code()}.
+
+module(#b_module{name=Mod,exports=Es,attributes=Attrs,body=Fs}, _Opts) ->
+ {Asm,St} = functions(Fs, {atom,Mod}),
+ {ok,{Mod,Es,Attrs,Asm,St#cg.lcount}}.
+
+-record(need, {h=0 :: non_neg_integer(),
+ f=0 :: non_neg_integer()}).
+
+-record(cg_blk, {anno=#{} :: anno(),
+ is=[] :: [instruction()],
+ last :: terminator()}).
+
+-record(cg_set, {anno=#{} :: anno(),
+ dst :: b_var(),
+ op :: beam_ssa:op(),
+ args :: [beam_ssa:argument() | xreg()]}).
+
+-record(cg_alloc, {anno=#{} :: anno(),
+ stack=none :: 'none' | pos_integer(),
+ words=#need{} :: #need{},
+ live :: 'undefined' | pos_integer(),
+ def_yregs=[] :: [yreg()]
+ }).
+
+-record(cg_br, {bool :: beam_ssa:value(),
+ succ :: ssa_label(),
+ fail :: ssa_label()
+ }).
+-record(cg_ret, {arg :: cg_value(),
+ dealloc=none :: 'none' | pos_integer()
+ }).
+-record(cg_switch, {arg :: cg_value(),
+ fail :: ssa_label(),
+ list :: [sw_list_item()]
+ }).
+
+-type fa() :: {beam_asm:function_name(),arity()}.
+-type ssa_label() :: beam_ssa:label().
+-type beam_label() :: beam_asm:label().
+
+-type anno() :: beam_ssa:anno().
+
+-type b_var() :: beam_ssa:b_var().
+-type b_literal() :: beam_ssa:b_literal().
+
+-type cg_value() :: beam_ssa:value() | xreg().
+
+-type cg_set() :: #cg_set{}.
+-type cg_alloc() :: #cg_alloc{}.
+
+-type instruction() :: cg_set() | cg_alloc().
+
+-type cg_br() :: #cg_br{}.
+-type cg_ret() :: #cg_ret{}.
+-type cg_switch() :: #cg_switch{}.
+-type terminator() :: cg_br() | cg_ret() | cg_switch().
+
+-type sw_list_item() :: {b_literal(),ssa_label()}.
+
+-type reg_num() :: beam_asm:reg_num().
+-type xreg() :: {'x',reg_num()}.
+-type yreg() :: {'y',reg_num()}.
+
+-type ssa_register() :: xreg() | yreg() | {'fr',reg_num()} | {'z',reg_num()}.
+
+functions(Forms, AtomMod) ->
+ mapfoldl(fun (F, St) -> function(F, AtomMod, St) end,
+ #cg{lcount=1}, Forms).
+
+function(#b_function{anno=Anno,bs=Blocks}, AtomMod, St0) ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ try
+ assert_badarg_block(Blocks), %Assertion.
+ Regs = maps:get(registers, Anno),
+ St1 = St0#cg{labels=#{},used_labels=gb_sets:empty(),
+ regs=Regs},
+ {Fi,St2} = new_label(St1), %FuncInfo label
+ {Entry,St3} = local_func_label(Name, Arity, St2),
+ {Ult,St4} = new_label(St3), %Ultimate failure
+ Labels = (St4#cg.labels)#{0=>Entry,?BADARG_BLOCK=>0},
+ St5 = St4#cg{labels=Labels,used_labels=gb_sets:singleton(Entry),
+ ultimate_fail=Ult},
+ {Body,St} = cg_fun(Blocks, St5),
+ Asm = [{label,Fi},line(Anno),
+ {func_info,AtomMod,{atom,Name},Arity}] ++
+ add_parameter_annos(Body, Anno) ++
+ [{label,Ult},if_end],
+ Func = {function,Name,Arity,Entry,Asm},
+ {Func,St}
+ catch
+ Class:Error:Stack ->
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+assert_badarg_block(Blocks) ->
+ %% Assertion: ?BADARG_BLOCK must be the call erlang:error(badarg).
+ case Blocks of
+ #{?BADARG_BLOCK:=Blk} ->
+ #b_blk{is=[#b_set{op=call,dst=Ret,
+ args=[#b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error}},
+ #b_literal{val=badarg}]}],
+ last=#b_ret{arg=Ret}} = Blk,
+ ok;
+ #{} ->
+ %% ?BADARG_BLOCK has been removed because it was never used.
+ ok
+ end.
+
+add_parameter_annos([{label, _}=Entry | Body], Anno) ->
+ ParamInfo = maps:get(parameter_type_info, Anno, #{}),
+ Annos = maps:fold(
+ fun(K, V, Acc) when is_map_key(K, ParamInfo) ->
+ TypeInfo = maps:get(K, ParamInfo),
+ [{'%', {type_info, V, TypeInfo}} | Acc];
+ (_K, _V, Acc) ->
+ Acc
+ end, [], maps:get(registers, Anno)),
+ [Entry | Annos] ++ Body.
+
+cg_fun(Blocks, St0) ->
+ Linear0 = linearize(Blocks),
+ St = collect_catch_labels(Linear0, St0),
+ Linear1 = need_heap(Linear0),
+ Linear2 = prefer_xregs(Linear1, St),
+ Linear3 = liveness(Linear2, St),
+ Linear4 = defined(Linear3, St),
+ Linear = opt_allocate(Linear4, St),
+ cg_linear(Linear, St).
+
+%% collect_catch_labels(Linear, St) -> St.
+%% Collect all catch labels (labels for blocks that begin
+%% with 'landingpad' instructions) for later use.
+
+collect_catch_labels(Linear, St) ->
+ Labels = collect_catch_labels_1(Linear),
+ St#cg{catches=gb_sets:from_list(Labels)}.
+
+collect_catch_labels_1([{L,#cg_blk{is=[#cg_set{op=landingpad}|_]}}|Bs]) ->
+ [L|collect_catch_labels_1(Bs)];
+collect_catch_labels_1([_|Bs]) ->
+ collect_catch_labels_1(Bs);
+collect_catch_labels_1([]) -> [].
+
+%% need_heap([{BlockLabel,Block]) -> [{BlockLabel,Block}].
+%% Insert need_heap instructions in the instruction list. Try to be smart and
+%% collect them together as much as possible.
+
+need_heap(Bs0) ->
+ Bs1 = need_heap_allocs(Bs0, #{}),
+ {Bs,#need{h=0,f=0}} = need_heap_blks(reverse(Bs1), #need{}, []),
+ Bs.
+
+need_heap_allocs([{L,#cg_blk{is=Is0,last=Terminator}=Blk0}|Bs], Counts0) ->
+ Next = next_block(Bs),
+ Successors = successors(Terminator),
+ Counts = foldl(fun(S, Cnts) ->
+ case Cnts of
+ #{S:=C} -> Cnts#{S:=C+1};
+ #{} when S =:= Next -> Cnts#{S=>1};
+ #{} -> Cnts#{S=>42}
+ end
+ end, Counts0, Successors),
+ case Counts of
+ #{L:=1} ->
+ [{L,Blk0}|need_heap_allocs(Bs, Counts)];
+ #{L:=_} ->
+ %% This block has multiple predecessors. Force an allocation
+ %% in this block so that the predecessors don't need to do
+ %% an allocation on behalf of this block.
+ Is = case need_heap_never(Is0) of
+ true -> Is0;
+ false -> [#cg_alloc{}|Is0]
+ end,
+ Blk = Blk0#cg_blk{is=Is},
+ [{L,Blk}|need_heap_allocs(Bs, Counts)];
+ #{} ->
+ [{L,Blk0}|need_heap_allocs(Bs, Counts)]
+ end;
+need_heap_allocs([], _) -> [].
+
+need_heap_never([#cg_alloc{}|_]) -> true;
+need_heap_never([#cg_set{op=recv_next}|_]) -> true;
+need_heap_never([#cg_set{op=wait}|_]) -> true;
+need_heap_never(_) -> false.
+
+need_heap_blks([{L,#cg_blk{is=Is0}=Blk0}|Bs], H0, Acc) ->
+ {Is1,H1} = need_heap_is(reverse(Is0), H0, []),
+ {Ns,H} = need_heap_terminator(Bs, L, H1),
+ Is = Ns ++ Is1,
+ Blk = Blk0#cg_blk{is=Is},
+ need_heap_blks(Bs, H, [{L,Blk}|Acc]);
+need_heap_blks([], H, Acc) ->
+ {Acc,H}.
+
+need_heap_is([#cg_alloc{words=Words}=Alloc0|Is], N, Acc) ->
+ Alloc = Alloc0#cg_alloc{words=add_heap_words(N, Words)},
+ need_heap_is(Is, #need{}, [Alloc|Acc]);
+need_heap_is([#cg_set{anno=Anno,op=bs_init}=I0|Is], N, Acc) ->
+ Alloc = case need_heap_need(N) of
+ [#cg_alloc{words=Need}] -> alloc(Need);
+ [] -> 0
+ end,
+ I = I0#cg_set{anno=Anno#{alloc=>Alloc}},
+ need_heap_is(Is, #need{}, [I|Acc]);
+need_heap_is([#cg_set{op=Op,args=Args}=I|Is], N, Acc) ->
+ case classify_heap_need(Op, Args) of
+ {put,Words} ->
+ %% Pass through adding to needed heap.
+ need_heap_is(Is, add_heap_words(N, Words), [I|Acc]);
+ put_float ->
+ need_heap_is(Is, add_heap_float(N), [I|Acc]);
+ neutral ->
+ need_heap_is(Is, N, [I|Acc]);
+ gc ->
+ need_heap_is(Is, #need{}, [I]++need_heap_need(N)++Acc)
+ end;
+need_heap_is([], N, Acc) ->
+ {Acc,N}.
+
+need_heap_terminator([{_,#cg_blk{last=#cg_br{succ=L,fail=L}}}|_], L, N) ->
+ %% Fallthrough.
+ {[],N};
+need_heap_terminator([{_,#cg_blk{is=Is,last=#cg_br{succ=L}}}|_], L, N) ->
+ case need_heap_need(N) of
+ [] ->
+ {[],#need{}};
+ [_|_]=Alloc ->
+ %% If the preceding instructions are a binary construction,
+ %% hoist the allocation and incorporate into the bs_init
+ %% instruction.
+ case reverse(Is) of
+ [#cg_set{op=succeeded},#cg_set{op=bs_init}|_] ->
+ {[],N};
+ [#cg_set{op=bs_put}|_] ->
+ {[],N};
+ _ ->
+ %% Not binary construction. Must emit an allocation
+ %% instruction in this block.
+ {Alloc,#need{}}
+ end
+ end;
+need_heap_terminator([{_,#cg_blk{}}|_], _, N) ->
+ {need_heap_need(N),#need{}};
+need_heap_terminator([], _, H) ->
+ {need_heap_need(H),#need{}}.
+
+need_heap_need(#need{h=0,f=0}) -> [];
+need_heap_need(#need{}=N) -> [#cg_alloc{words=N}].
+
+add_heap_words(#need{h=H1,f=F1}, #need{h=H2,f=F2}) ->
+ #need{h=H1+H2,f=F1+F2};
+add_heap_words(#need{h=Heap}=N, Words) when is_integer(Words) ->
+ N#need{h=Heap+Words}.
+
+add_heap_float(#need{f=F}=N) ->
+ N#need{f=F+1}.
+
+%% classify_heap_need(Operation, Arguments) ->
+%% gc | neutral | {put,Words} | put_float.
+%% Classify the heap need for this instruction. The return
+%% values have the following meaning.
+%%
+%% {put,Words} means that the instruction will use Words words to build
+%% something on the heap.
+%%
+%% 'put_float' means that the instruction will build one floating point
+%% number on the heap.
+%%
+%% 'gc' means that that the instruction can potentially do a GC or throw an
+%% exception. That means that an allocation instruction for any building
+%% must be placed after this instruction.
+%%
+%% 'neutral' means that the instruction does nothing to disturb the heap.
+
+-spec classify_heap_need(beam_ssa:op(), [beam_ssa:value()]) ->
+ 'gc' | 'neutral' |
+ {'put',non_neg_integer()} | 'put_float'.
+
+classify_heap_need(put_list, _) ->
+ {put,2};
+classify_heap_need(put_tuple_arity, [#b_literal{val=Words}]) ->
+ {put,Words+1};
+classify_heap_need(put_tuple, Elements) ->
+ {put,length(Elements)+1};
+classify_heap_need({bif,Name}, Args) ->
+ case is_gc_bif(Name, Args) of
+ false -> neutral;
+ true -> gc
+ end;
+classify_heap_need({float,Op}, _Args) ->
+ case Op of
+ get -> put_float;
+ _ -> neutral
+ end;
+classify_heap_need(Name, _Args) ->
+ classify_heap_need(Name).
+
+%% classify_heap_need(Operation) -> gc | neutral.
+%% Return either 'gc' or 'neutral'.
+%%
+%% 'gc' means that that the instruction can potentially do a GC or throw an
+%% exception. That means that an allocation instruction for any building
+%% must be placed after this instruction.
+%%
+%% 'neutral' means that the instruction does nothing to disturb the heap.
+%%
+%% Note: Only handle operations in this function that are not handled
+%% by classify_heap_need/2.
+
+classify_heap_need(bs_add) -> gc;
+classify_heap_need(bs_get) -> gc;
+classify_heap_need(bs_get_tail) -> gc;
+classify_heap_need(bs_init) -> gc;
+classify_heap_need(bs_init_writable) -> gc;
+classify_heap_need(bs_match_string) -> gc;
+classify_heap_need(bs_put) -> neutral;
+classify_heap_need(bs_restore) -> neutral;
+classify_heap_need(bs_save) -> neutral;
+classify_heap_need(bs_get_position) -> gc;
+classify_heap_need(bs_set_position) -> neutral;
+classify_heap_need(bs_skip) -> gc;
+classify_heap_need(bs_start_match) -> neutral;
+classify_heap_need(bs_test_tail) -> neutral;
+classify_heap_need(bs_utf16_size) -> neutral;
+classify_heap_need(bs_utf8_size) -> neutral;
+classify_heap_need(build_stacktrace) -> gc;
+classify_heap_need(call) -> gc;
+classify_heap_need(catch_end) -> gc;
+classify_heap_need(copy) -> neutral;
+classify_heap_need(extract) -> gc;
+classify_heap_need(get_hd) -> neutral;
+classify_heap_need(get_map_element) -> neutral;
+classify_heap_need(get_tl) -> neutral;
+classify_heap_need(get_tuple_element) -> neutral;
+classify_heap_need(has_map_field) -> neutral;
+classify_heap_need(is_nonempty_list) -> neutral;
+classify_heap_need(is_tagged_tuple) -> neutral;
+classify_heap_need(kill_try_tag) -> gc;
+classify_heap_need(landingpad) -> gc;
+classify_heap_need(make_fun) -> gc;
+classify_heap_need(new_try_tag) -> gc;
+classify_heap_need(peek_message) -> gc;
+classify_heap_need(put_map) -> gc;
+classify_heap_need(put_tuple_elements) -> neutral;
+classify_heap_need(raw_raise) -> gc;
+classify_heap_need(recv_next) -> gc;
+classify_heap_need(remove_message) -> neutral;
+classify_heap_need(resume) -> gc;
+classify_heap_need(set_tuple_element) -> gc;
+classify_heap_need(succeeded) -> neutral;
+classify_heap_need(timeout) -> gc;
+classify_heap_need(wait) -> gc;
+classify_heap_need(wait_timeout) -> gc.
+
+%%%
+%%% Because beam_ssa_pre_codegen has inserted 'copy' instructions to copy
+%%% variables that must be saved on the stack, a value can for some time
+%%% be in both an X register and a Y register.
+%%%
+%%% Here we will keep track of variables that have the same value and
+%%% rewrite instructions to use the variable that refers to the X
+%%% register instead of the Y register. That could improve performance,
+%%% since the BEAM interpreter have more optimized instructions
+%%% operating on X registers than on Y registers.
+%%%
+%%% 'call' and 'make_fun' are handled somewhat specially. If a value
+%%% already is in the correct X register, the X register will always
+%%% be used instead of the Y register. However, if there are one or more
+%%% values in the wrong X registers, the X registers variables will be
+%%% used only if that does not cause more 'move' instructions to be
+%%% be emitted than if the Y register variables were used.
+%%%
+%%% Here are some examples. The first example shows how a 'move' from
+%%% an Y register is eliminated:
+%%%
+%%% move x0 y1
+%%% move y1 x0 %%Will be eliminated.
+%%%
+%%% call f/1
+%%%
+%%% Here is an example when x0 and x1 must be swapped to load the argument
+%%% registers. Here the 'call' instruction will use the Y registers to
+%%% avoid introducing an extra 'move' insruction:
+%%%
+%%% move x0 y0
+%%% move x1 y1
+%%%
+%%% move y0 x1
+%%% move y1 x0
+%%%
+%%% call f/2
+%%%
+%%% Using the X register to load the argument registers would need
+%%% an extra 'move' instruction like this:
+%%%
+%%% move x0 y0
+%%% move x1 y1
+%%%
+%%% move x1 x2
+%%% move x0 x1
+%%% move x2 x0
+%%%
+%%% call f/2
+%%%
+
+prefer_xregs(Linear, St) ->
+ prefer_xregs(Linear, St, #{0=>#{}}).
+
+prefer_xregs([{L,#cg_blk{is=Is0,last=Last0}=Blk0}|Bs], St, Map0) ->
+ Copies0 = maps:get(L, Map0),
+ {Is,Copies} = prefer_xregs_is(Is0, St, Copies0, []),
+ Last = prefer_xregs_terminator(Last0, Copies, St),
+ Blk = Blk0#cg_blk{is=Is,last=Last},
+ Successors = successors(Last),
+ Map = prefer_xregs_successors(Successors, Copies, Map0),
+ [{L,Blk}|prefer_xregs(Bs, St, Map)];
+prefer_xregs([], _St, _Map) -> [].
+
+prefer_xregs_successors([L|Ls], Copies0, Map0) ->
+ case Map0 of
+ #{L:=Copies1} ->
+ Copies = merge_copies(Copies0, Copies1),
+ Map = Map0#{L:=Copies},
+ prefer_xregs_successors(Ls, Copies0, Map);
+ #{} ->
+ Map = Map0#{L=>Copies0},
+ prefer_xregs_successors(Ls, Copies0, Map)
+ end;
+prefer_xregs_successors([], _, Map) -> Map.
+
+prefer_xregs_is([#cg_alloc{}=I|Is], St, Copies0, Acc) ->
+ Copies = case I of
+ #cg_alloc{stack=none,words=#need{h=0,f=0}} ->
+ Copies0;
+ #cg_alloc{} ->
+ #{}
+ end,
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{op=copy,dst=Dst,args=[Src]}=I|Is], St, Copies0, Acc) ->
+ Copies1 = prefer_xregs_prune(I, Copies0, St),
+ Copies = case beam_args([Src,Dst], St) of
+ [Same,Same] -> Copies1;
+ [_,_] -> Copies1#{Dst=>Src}
+ end,
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{op=call,dst=Dst}=I0|Is], St, Copies, Acc) ->
+ I = prefer_xregs_call(I0, Copies, St),
+ prefer_xregs_is(Is, St, #{Dst=>{x,0}}, [I|Acc]);
+prefer_xregs_is([#cg_set{op=make_fun,dst=Dst}=I0|Is], St, Copies, Acc) ->
+ I = prefer_xregs_call(I0, Copies, St),
+ prefer_xregs_is(Is, St, #{Dst=>{x,0}}, [I|Acc]);
+prefer_xregs_is([#cg_set{op=set_tuple_element}=I|Is], St, Copies, Acc) ->
+ %% FIXME: HiPE translates the following code segment incorrectly:
+ %% {call_ext,3,{extfunc,erlang,setelement,3}}.
+ %% {move,{x,0},{y,3}}.
+ %% {set_tuple_element,{y,1},{y,3},1}.
+ %% Therefore, skip the translation of the arguments for set_tuple_element.
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([#cg_set{args=Args0}=I0|Is], St, Copies0, Acc) ->
+ Args = [do_prefer_xreg(A, Copies0, St) || A <- Args0],
+ I = I0#cg_set{args=Args},
+ Copies = prefer_xregs_prune(I, Copies0, St),
+ prefer_xregs_is(Is, St, Copies, [I|Acc]);
+prefer_xregs_is([], _St, Copies, Acc) ->
+ {reverse(Acc),Copies}.
+
+prefer_xregs_terminator(#cg_br{bool=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_br{bool=Arg};
+prefer_xregs_terminator(#cg_ret{arg=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_ret{arg=Arg};
+prefer_xregs_terminator(#cg_switch{arg=Arg0}=I, Copies, St) ->
+ Arg = do_prefer_xreg(Arg0, Copies, St),
+ I#cg_switch{arg=Arg}.
+
+prefer_xregs_prune(#cg_set{anno=#{clobbers:=true}}, _, _) ->
+ #{};
+prefer_xregs_prune(#cg_set{dst=Dst}, Copies, St) ->
+ DstReg = beam_arg(Dst, St),
+ F = fun(_, Alias) ->
+ beam_arg(Alias, St) =/= DstReg
+ end,
+ maps:filter(F, Copies).
+
+%% prefer_xregs_call(Instruction, Copies, St) -> Instruction.
+%% Given a 'call' or 'make_fun' instruction, minimize the number
+%% of 'move' instructions to set up the argument registers.
+%% Prefer using X registers over Y registers, unless that will
+%% result in more 'move' instructions.
+
+prefer_xregs_call(#cg_set{args=[_]}=I, _Copies, _St) ->
+ I;
+prefer_xregs_call(#cg_set{args=[F|Args0]}=I, Copies, St) ->
+ case Args0 of
+ [A0] ->
+ %% Only one argument. Always prefer the X register
+ %% if available.
+ A = do_prefer_xreg(A0, Copies, St),
+ I#cg_set{args=[F,A]};
+ [_|_] ->
+ %% Two or more arguments. Try rewriting arguments in
+ %% two ways and see which way produces the least
+ %% number of 'move' instructions.
+ Args1 = prefer_xregs_call_1(Args0, Copies, 0, St),
+ Args2 = [do_prefer_xreg(A, Copies, St) || A <- Args0],
+ case {count_moves(Args1, St),count_moves(Args2, St)} of
+ {N1,N2} when N1 < N2 ->
+ %% There will be fewer 'move' instructions if
+ %% we keep using Y registers.
+ I#cg_set{args=[F|Args1]};
+ {_,_} ->
+ %% Always use the values in X registers.
+ I#cg_set{args=[F|Args2]}
+ end
+ end.
+
+count_moves(Args, St) ->
+ length(setup_args(beam_args(Args, St))).
+
+prefer_xregs_call_1([#b_var{}=A|As], Copies, X, St) ->
+ case {beam_arg(A, St),Copies} of
+ {{y,_},#{A:=Other}} ->
+ case beam_arg(Other, St) of
+ {x,X} ->
+ %% This value is already in the correct X register.
+ %% It is always benefical to use the X register variable.
+ [Other|prefer_xregs_call_1(As, Copies, X+1, St)];
+ _ ->
+ %% This value is another X register. Keep using
+ %% the Y register variable.
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)]
+ end;
+ {_,_} ->
+ %% The value is not available in an X register.
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)]
+ end;
+prefer_xregs_call_1([A|As], Copies, X, St) ->
+ [A|prefer_xregs_call_1(As, Copies, X+1, St)];
+prefer_xregs_call_1([], _, _, _) -> [].
+
+do_prefer_xreg(#b_var{}=A, Copies, St) ->
+ case {beam_arg(A, St),Copies} of
+ {{y,_},#{A:=Copy}} ->
+ Copy;
+ {_,_} ->
+ A
+ end;
+do_prefer_xreg(A, _, _) -> A.
+
+merge_copies(Copies0, Copies1) when map_size(Copies0) =< map_size(Copies1) ->
+ maps:filter(fun(K, V) ->
+ case Copies1 of
+ #{K:=V} -> true;
+ #{} -> false
+ end
+ end, Copies0);
+merge_copies(Copies0, Copies1) ->
+ merge_copies(Copies1, Copies0).
+
+
+%%%
+%%% Add annotations for the number of live registers.
+%%%
+
+liveness(Linear, #cg{regs=Regs}) ->
+ liveness(reverse(Linear), #{}, Regs, []).
+
+liveness([{L,#cg_blk{is=Is0,last=Last0}=Blk0}|Bs], LiveMap0, Regs, Acc) ->
+ Successors = liveness_successors(Last0),
+ Live0 = ordsets:union([liveness_get(S, LiveMap0) || S <- Successors]),
+ Live1 = liveness_terminator(Last0, Live0),
+ {Is,Live} = liveness_is(reverse(Is0), Regs, Live1, []),
+ LiveMap = LiveMap0#{L=>Live},
+ Blk = Blk0#cg_blk{is=Is},
+ liveness(Bs, LiveMap, Regs, [{L,Blk}|Acc]);
+liveness([], _LiveMap, _Regs, Acc) -> Acc.
+
+liveness_get(S, LiveMap) ->
+ case LiveMap of
+ #{S:=Live} -> Live;
+ #{} -> []
+ end.
+
+liveness_successors(Terminator) ->
+ successors(Terminator) -- [?BADARG_BLOCK].
+
+liveness_is([#cg_alloc{}=I0|Is], Regs, Live, Acc) ->
+ I = I0#cg_alloc{live=num_live(Live, Regs)},
+ liveness_is(Is, Regs, Live, [I|Acc]);
+liveness_is([#cg_set{dst=Dst,args=Args}=I0|Is], Regs, Live0, Acc) ->
+ Live1 = liveness_clobber(I0, Live0, Regs),
+ I1 = liveness_yregs_anno(I0, Live1, Regs),
+ Live2 = liveness_args(Args, Live1),
+ Live = ordsets:del_element(Dst, Live2),
+ I = liveness_anno(I1, Live, Regs),
+ liveness_is(Is, Regs, Live, [I|Acc]);
+liveness_is([], _, Live, Acc) ->
+ {Acc,Live}.
+
+liveness_terminator(#cg_br{bool=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live);
+liveness_terminator(#cg_switch{arg=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live);
+liveness_terminator(#cg_ret{arg=Arg}, Live) ->
+ liveness_terminator_1(Arg, Live).
+
+liveness_terminator_1(#b_var{}=V, Live) ->
+ ordsets:add_element(V, Live);
+liveness_terminator_1(#b_literal{}, Live) ->
+ Live;
+liveness_terminator_1(Reg, Live) ->
+ _ = verify_beam_register(Reg),
+ ordsets:add_element(Reg, Live).
+
+liveness_args([#b_var{}=V|As], Live) ->
+ liveness_args(As, ordsets:add_element(V, Live));
+liveness_args([#b_remote{mod=Mod,name=Name}|As], Live) ->
+ liveness_args([Mod,Name|As], Live);
+liveness_args([A|As], Live) ->
+ case is_beam_register(A) of
+ true ->
+ liveness_args(As, ordsets:add_element(A, Live));
+ false ->
+ liveness_args(As, Live)
+ end;
+liveness_args([], Live) -> Live.
+
+liveness_anno(#cg_set{op=Op}=I, Live, Regs) ->
+ case need_live_anno(Op) of
+ true ->
+ NumLive = num_live(Live, Regs),
+ Anno = (I#cg_set.anno)#{live=>NumLive},
+ I#cg_set{anno=Anno};
+ false ->
+ I
+ end.
+
+liveness_yregs_anno(#cg_set{op=Op,dst=Dst}=I, Live0, Regs) ->
+ case need_live_anno(Op) of
+ true ->
+ Live = ordsets:del_element(Dst, Live0),
+ LiveYregs = [V || V <- Live, is_yreg(V, Regs)],
+ Anno = (I#cg_set.anno)#{live_yregs=>LiveYregs},
+ I#cg_set{anno=Anno};
+ false ->
+ I
+ end.
+
+liveness_clobber(#cg_set{anno=Anno}, Live, Regs) ->
+ case Anno of
+ #{clobbers:=true} ->
+ [R || R <- Live, is_yreg(R, Regs)];
+ _ ->
+ Live
+ end.
+
+is_yreg(R, Regs) ->
+ case Regs of
+ #{R:={y,_}} -> true;
+ #{} -> false
+ end.
+
+num_live(Live, Regs) ->
+ Rs = ordsets:from_list([get_register(V, Regs) || V <- Live]),
+ num_live_1(Rs, 0).
+
+num_live_1([{x,X}|T], X) ->
+ num_live_1(T, X+1);
+num_live_1([{x,_}|_]=T, X) ->
+ %% error({hole,{x,X},expected,Next});
+ num_live_1(T, X+1);
+num_live_1([{y,_}|_], X) ->
+ X;
+num_live_1([{z,_}|_], X) ->
+ X;
+num_live_1([{fr,_}|T], X) ->
+ num_live_1(T, X);
+num_live_1([], X) ->
+ X.
+
+get_live(#cg_set{anno=#{live:=Live}}) ->
+ Live.
+
+%% need_live_anno(Operation) -> true|false.
+%% Return 'true' if the instruction needs a 'live' annotation with
+%% the number live X registers, or 'false' otherwise.
+
+need_live_anno(Op) ->
+ case Op of
+ {bif,_} -> true;
+ bs_get -> true;
+ bs_init -> true;
+ bs_get_position -> true;
+ bs_get_tail -> true;
+ bs_start_match -> true;
+ bs_skip -> true;
+ call -> true;
+ put_map -> true;
+ _ -> false
+ end.
+
+%%%
+%%% Add annotations for defined Y registers.
+%%%
+
+defined(Linear, #cg{regs=Regs}) ->
+ def(Linear, #{}, Regs).
+
+def([{L,#cg_blk{is=Is0,last=Last}=Blk0}|Bs], DefMap0, Regs) ->
+ Def0 = def_get(L, DefMap0),
+ {Is,Def} = def_is(Is0, Regs, Def0, []),
+ Successors = successors(Last),
+ DefMap = def_successors(Successors, Def, DefMap0),
+ Blk = Blk0#cg_blk{is=Is},
+ [{L,Blk}|def(Bs, DefMap, Regs)];
+def([], _, _) -> [].
+
+def_get(L, DefMap) ->
+ case DefMap of
+ #{L:=Def} -> Def;
+ #{} -> []
+ end.
+
+def_is([#cg_alloc{anno=Anno0}=I0|Is], Regs, Def, Acc) ->
+ I = I0#cg_alloc{anno=Anno0#{def_yregs=>Def}},
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{op=kill_try_tag,args=[#b_var{}=Tag]}=I|Is], Regs, Def0, Acc) ->
+ Def = ordsets:del_element(Tag, Def0),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{op=catch_end,args=[#b_var{}=Tag|_]}=I|Is], Regs, Def0, Acc) ->
+ Def = ordsets:del_element(Tag, Def0),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,op=call,dst=Dst}=I0|Is],
+ Regs, Def0, Acc) ->
+ #{live_yregs:=LiveYregVars} = Anno0,
+ LiveRegs = gb_sets:from_list([maps:get(V, Regs) || V <- LiveYregVars]),
+ Kill0 = ordsets:subtract(Def0, LiveYregVars),
+
+ %% Kill0 is the set of variables that have just died. However, the registers
+ %% used for killed variables may have been reused, so we must check that the
+ %% registers to be killed are not used by other variables.
+ Kill = [K || K <- Kill0, not gb_sets:is_element(maps:get(K, Regs), LiveRegs)],
+ Anno = Anno0#{def_yregs=>Def0,kill_yregs=>Kill},
+ I = I0#cg_set{anno=Anno},
+ Def1 = ordsets:subtract(Def0, Kill),
+ Def = def_add_yreg(Dst, Def1, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,op={bif,Bif},dst=Dst,args=Args}=I0|Is],
+ Regs, Def0, Acc) ->
+ Arity = length(Args),
+ I = case is_gc_bif(Bif, Args) orelse not erl_bifs:is_safe(erlang, Bif, Arity) of
+ true ->
+ I0#cg_set{anno=Anno0#{def_yregs=>Def0}};
+ false ->
+ I0
+ end,
+ Def = def_add_yreg(Dst, Def0, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([#cg_set{anno=Anno0,dst=Dst}=I0|Is], Regs, Def0, Acc) ->
+ I = case need_y_init(I0) of
+ true ->
+ I0#cg_set{anno=Anno0#{def_yregs=>Def0}};
+ false ->
+ I0
+ end,
+ Def = def_add_yreg(Dst, Def0, Regs),
+ def_is(Is, Regs, Def, [I|Acc]);
+def_is([], _, Def, Acc) ->
+ {reverse(Acc),Def}.
+
+def_add_yreg(Dst, Def, Regs) ->
+ case is_yreg(Dst, Regs) of
+ true -> ordsets:add_element(Dst, Def);
+ false -> Def
+ end.
+
+def_successors([S|Ss], Def0, DefMap) ->
+ case DefMap of
+ #{S:=Def1} ->
+ Def = ordsets:intersection(Def0, Def1),
+ def_successors(Ss, Def0, DefMap#{S:=Def});
+ #{} ->
+ def_successors(Ss, Def0, DefMap#{S=>Def0})
+ end;
+def_successors([], _, DefMap) -> DefMap.
+
+%% need_y_init(#cg_set{}) -> true|false.
+%% Return true if this instructions needs initialized Y registers
+%% (because the instruction may do a GC or cause an exception
+%% so that the stack will be scanned), or false otherwise.
+
+need_y_init(#cg_set{anno=#{clobbers:=Clobbers}}) -> Clobbers;
+need_y_init(#cg_set{op=bs_get}) -> true;
+need_y_init(#cg_set{op=bs_get_position}) -> true;
+need_y_init(#cg_set{op=bs_get_tail}) -> true;
+need_y_init(#cg_set{op=bs_init}) -> true;
+need_y_init(#cg_set{op=bs_skip,args=[#b_literal{val=Type}|_]}) ->
+ case Type of
+ utf8 -> true;
+ utf16 -> true;
+ utf32 -> true;
+ _ -> false
+ end;
+need_y_init(#cg_set{op=bs_start_match}) -> true;
+need_y_init(#cg_set{op=put_map}) -> true;
+need_y_init(#cg_set{}) -> false.
+
+%% opt_allocate([{BlockLabel,Block}], #st{}) -> [BeamInstruction].
+%% Update the def_yregs field of each #cg_alloc{} that allocates
+%% a stack frame. #cg_alloc.def_yregs will list all Y registers
+%% that will be initialized by the subsequent code (thus, the
+%% listed Y registers don't require init/1 instructions).
+
+opt_allocate(Linear, #cg{regs=Regs}) ->
+ opt_allocate_1(Linear, Regs).
+
+opt_allocate_1([{L,#cg_blk{is=[#cg_alloc{stack=Stk}=I0|Is]}=Blk0}|Bs]=Bs0, Regs)
+ when is_integer(Stk) ->
+ Yregs = opt_alloc_def(Bs0, gb_sets:singleton(L), []),
+ I = I0#cg_alloc{def_yregs=Yregs},
+ [{L,Blk0#cg_blk{is=[I|Is]}}|opt_allocate_1(Bs, Regs)];
+opt_allocate_1([B|Bs], Regs) ->
+ [B|opt_allocate_1(Bs, Regs)];
+opt_allocate_1([], _) -> [].
+
+opt_alloc_def([{L,#cg_blk{is=Is,last=Last}}|Bs], Ws0, Def0) ->
+ case gb_sets:is_member(L, Ws0) of
+ false ->
+ opt_alloc_def(Bs, Ws0, Def0);
+ true ->
+ case opt_allocate_is(Is) of
+ none ->
+ Succ = successors(Last),
+ Ws = gb_sets:union(Ws0, gb_sets:from_list(Succ)),
+ opt_alloc_def(Bs, Ws, Def0);
+ Def1 when is_list(Def1) ->
+ Def = [Def1|Def0],
+ opt_alloc_def(Bs, Ws0, Def)
+ end
+ end;
+opt_alloc_def([], _, Def) ->
+ ordsets:intersection(Def).
+
+opt_allocate_is([#cg_set{anno=Anno}|Is]) ->
+ case Anno of
+ #{def_yregs:=Yregs} ->
+ Yregs;
+ #{} ->
+ opt_allocate_is(Is)
+ end;
+opt_allocate_is([#cg_alloc{anno=#{def_yregs:=Yregs},stack=none}|_]) ->
+ Yregs;
+opt_allocate_is([#cg_alloc{}|Is]) ->
+ opt_allocate_is(Is);
+opt_allocate_is([]) -> none.
+
+%%%
+%%% Here follows the main code generation functions.
+%%%
+
+%% cg_linear([{BlockLabel,Block}]) -> [BeamInstruction].
+%% Generate BEAM instructions.
+
+cg_linear([{L,#cg_blk{anno=#{recv_set:=L}=Anno0}=B0}|Bs], St0) ->
+ Anno = maps:remove(recv_set, Anno0),
+ B = B0#cg_blk{anno=Anno},
+ {Is,St1} = cg_linear([{L,B}|Bs], St0),
+ {Fail,St} = use_block_label(L, St1),
+ {[{recv_set,Fail}|Is],St};
+cg_linear([{L,#cg_blk{is=Is0,last=Last}}|Bs], St0) ->
+ Next = next_block(Bs),
+ St1 = new_block_label(L, St0),
+ {Is1,St2} = cg_block(Is0, Last, Next, St1),
+ {Is2,St} = cg_linear(Bs, St2),
+ {def_block_label(L, St)++Is1++Is2,St};
+cg_linear([], St) -> {[],St}.
+
+cg_block([#cg_set{op=recv_next}], #cg_br{succ=Lr0}, _Next, St0) ->
+ {Lr,St} = use_block_label(Lr0, St0),
+ {[{loop_rec_end,Lr}],St};
+cg_block([#cg_set{op=wait}], #cg_br{succ=Lr0}, _Next, St0) ->
+ {Lr,St} = use_block_label(Lr0, St0),
+ {[{wait,Lr}],St};
+cg_block(Is0, Last, Next, St0) ->
+ case Last of
+ #cg_br{succ=Next,fail=Next} ->
+ cg_block(Is0, none, St0);
+ #cg_br{succ=Same,fail=Same} ->
+ {Fail,St1} = use_block_label(Same, St0),
+ {Is,St} = cg_block(Is0, none, St1),
+ {Is++[jump(Fail)],St};
+ #cg_br{bool=Bool,succ=Next,fail=Fail0} ->
+ {Fail,St1} = use_block_label(Fail0, St0),
+ {Is,St} = cg_block(Is0, {Bool,Fail}, St1),
+ {Is,St};
+ #cg_br{bool=Bool,succ=Succ0,fail=Fail0} ->
+ {[Succ,Fail],St1} = use_block_labels([Succ0,Fail0], St0),
+ {Is,St} = cg_block(Is0, {Bool,Fail}, St1),
+ {Is++[jump(Succ)],St};
+ #cg_ret{arg=Src0,dealloc=N} ->
+ Src = beam_arg(Src0, St0),
+ cg_block(Is0, {return,Src,N}, St0);
+ #cg_switch{} ->
+ cg_switch(Is0, Last, St0)
+ end.
+
+cg_switch(Is0, Last, St0) ->
+ #cg_switch{arg=Src0,fail=Fail0,list=List0} = Last,
+ Src = beam_arg(Src0, St0),
+ {Fail1,St1} = use_block_label(Fail0, St0),
+ Fail = ensure_label(Fail1, St1),
+ {List1,St2} =
+ flatmapfoldl(fun({V,L}, S0) ->
+ {Lbl,S} = use_block_label(L, S0),
+ {[beam_arg(V, S),Lbl],S}
+ end, St1, List0),
+ {Is1,St} = cg_block(Is0, none, St2),
+ case reverse(Is1) of
+ [{bif,tuple_size,_,[Tuple],{z,_}=Src}|More] ->
+ List = map(fun({integer,Arity}) -> Arity;
+ ({f,_}=F) -> F
+ end, List1),
+ Is = reverse(More, [{select_tuple_arity,Tuple,Fail,{list,List}}]),
+ {Is,St};
+ _ ->
+ SelectVal = {select_val,Src,Fail,{list,List1}},
+ {Is1 ++ [SelectVal],St}
+ end.
+
+jump({f,_}=Fail) ->
+ {jump,Fail};
+jump({catch_tag,Fail}) ->
+ {jump,Fail}.
+
+bif_fail({f,_}=Fail) -> Fail;
+bif_fail({catch_tag,_}) -> {f,0}.
+
+next_block([]) -> none;
+next_block([{Next,_}|_]) -> Next.
+
+ensure_label(Fail0, #cg{ultimate_fail=Lbl}) ->
+ case bif_fail(Fail0) of
+ {f,0} -> {f,Lbl};
+ {f,_}=Fail -> Fail
+ end.
+
+cg_block([#cg_set{anno=#{recv_mark:=L}=Anno0}=I0|T], Context, St0) ->
+ Anno = maps:remove(recv_mark, Anno0),
+ I = I0#cg_set{anno=Anno},
+ {Is,St1} = cg_block([I|T], Context, St0),
+ {Fail,St} = use_block_label(L, St1),
+ {[{recv_mark,Fail}|Is],St};
+cg_block([#cg_set{op=new_try_tag,dst=Tag,args=Args}], {Tag,Fail0}, St) ->
+ {catch_tag,Fail} = Fail0,
+ [Reg,{atom,Kind}] = beam_args([Tag|Args], St),
+ {[{Kind,Reg,Fail}],St};
+cg_block([#cg_set{anno=Anno,op={bif,Name},dst=Dst0,args=Args0}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail0}, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ Line0 = call_line(body, {extfunc,erlang,Name,length(Args)}, Anno),
+ Fail = bif_fail(Fail0),
+ Line = case Fail of
+ {f,0} -> Line0;
+ {f,_} -> []
+ end,
+ case is_gc_bif(Name, Args) of
+ true ->
+ Live = get_live(I),
+ Kill = kill_yregs(Anno, St),
+ {Kill++Line++[{gc_bif,Name,Fail,Live,Args,Dst}],St};
+ false ->
+ {Line++[{bif,Name,Fail,Args,Dst}],St}
+ end;
+cg_block([#cg_set{op={bif,tuple_size},dst=Arity0,args=[Tuple0]},
+ #cg_set{op={bif,'=:='},dst=Bool,args=[Arity0,#b_literal{val=Ar}]}=Eq],
+ {Bool,Fail}=Context, St0) ->
+ Tuple = beam_arg(Tuple0, St0),
+ case beam_arg(Arity0, St0) of
+ {z,_} ->
+ %% The size will only be used once. Combine to a test_arity instruction.
+ Test = {test,test_arity,ensure_label(Fail, St0),[Tuple,Ar]},
+ {[Test],St0};
+ Arity ->
+ %% The size will be used more than once. Must do an explicit
+ %% BIF call followed by the '==' test.
+ TupleSize = {bif,tuple_size,{f,0},[Tuple],Arity},
+ {Is,St} = cg_block([Eq], Context, St0),
+ {[TupleSize|Is],St}
+ end;
+cg_block([#cg_set{op={bif,Name},dst=Dst0,args=Args0}]=Is0, {Dst0,Fail}, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ case Dst of
+ {z,_} ->
+ %% The result of the BIF call will only be used once. Convert to
+ %% a test instruction.
+ Test = bif_to_test(Name, Args, ensure_label(Fail, St0)),
+ {Test,St0};
+ _ ->
+ %% Must explicitly call the BIF since the result will be used
+ %% more than once.
+ {Is1,St1} = cg_block(Is0, none, St0),
+ {Is2,St} = cg_block([], {Dst0,Fail}, St1),
+ {Is1++Is2,St}
+ end;
+cg_block([#cg_set{anno=Anno,op={bif,Name},dst=Dst0,args=Args0}=I|T],
+ Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ {Is0,St} = cg_block(T, Context, St0),
+ case is_gc_bif(Name, Args) of
+ true ->
+ Line = call_line(body, {extfunc,erlang,Name,length(Args)}, Anno),
+ Live = get_live(I),
+ Kill = kill_yregs(Anno, St),
+ Is = Kill++Line++[{gc_bif,Name,{f,0},Live,Args,Dst}|Is0],
+ {Is,St};
+ false ->
+ Is = [{bif,Name,{f,0},Args,Dst}|Is0],
+ {Is,St}
+ end;
+cg_block([#cg_set{op=bs_init,dst=Dst0,args=Args0,anno=Anno}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail0}, St) ->
+ Fail = bif_fail(Fail0),
+ Line = line(Anno),
+ Alloc = map_get(alloc, Anno),
+ [#b_literal{val=Kind}|Args1] = Args0,
+ case Kind of
+ new ->
+ [Dst,Size,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Live = get_live(I),
+ {[Line|cg_bs_init(Dst, Size, Alloc, Unit, Live, Fail)],St};
+ private_append ->
+ [Dst,Src,Bits,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Flags = {field_flags,[]},
+ Is = [Line,{bs_private_append,Fail,Bits,Unit,Src,Flags,Dst}],
+ {Is,St};
+ append ->
+ [Dst,Src,Bits,{integer,Unit}] = beam_args([Dst0|Args1], St),
+ Flags = {field_flags,[]},
+ Live = get_live(I),
+ Is = [Line,{bs_append,Fail,Bits,Alloc,Live,Unit,Src,Flags,Dst}],
+ {Is,St}
+ end;
+cg_block([#cg_set{anno=Anno,op=bs_start_match,dst=Ctx0,args=[Bin0]}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ [Dst,Bin1] = beam_args([Ctx0,Bin0], St),
+ {Bin,Pre} = force_reg(Bin1, Dst),
+ Live = get_live(I),
+ %% num_slots is only set when using the old instructions.
+ case maps:find(num_slots, Anno) of
+ {ok, Slots} ->
+ Is = Pre ++ [{test,bs_start_match2,Fail,Live,[Bin,Slots],Dst}],
+ {Is,St};
+ error ->
+ Is = Pre ++ [{test,bs_start_match3,Fail,Live,[Bin],Dst}],
+ {Is,St}
+ end;
+cg_block([#cg_set{op=bs_get}=Set,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ {cg_bs_get(Fail, Set, St),St};
+cg_block([#cg_set{op=bs_match_string,args=[CtxVar,#b_literal{val=String}]},
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ CtxReg = beam_arg(CtxVar, St),
+ Is = [{test,bs_match_string,Fail,[CtxReg,String]}],
+ {Is,St};
+cg_block([#cg_set{dst=Dst0,op=landingpad,args=Args0}|T], Context, St0) ->
+ [Dst,{atom,Kind},Tag] = beam_args([Dst0|Args0], St0),
+ case Kind of
+ 'catch' ->
+ cg_catch(Dst, T, Context, St0);
+ 'try' ->
+ cg_try(Dst, Tag, T, Context, St0)
+ end;
+cg_block([#cg_set{op=kill_try_tag,args=Args0}|Is], Context, St0) ->
+ [Reg] = beam_args(Args0, St0),
+ {Is0,St} = cg_block(Is, Context, St0),
+ {[{try_end,Reg}|Is0],St};
+cg_block([#cg_set{op=catch_end,dst=Dst0,args=Args0}|Is], Context, St0) ->
+ [Dst,Reg,{x,0}] = beam_args([Dst0|Args0], St0),
+ {Is0,St} = cg_block(Is, Context, St0),
+ {[{catch_end,Reg}|copy({x,0}, Dst)++Is0],St};
+cg_block([#cg_set{op=call}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,_Fail}, St) ->
+ %% A call in try/catch block.
+ cg_block([I], none, St);
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=I,
+ #cg_set{op=succeeded,dst=Bool}], {Bool,Fail}, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ {cg_test(Op, bif_fail(Fail), Args, Dst, I),St};
+cg_block([#cg_set{op=bs_put,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ Args = beam_args(Args0, St),
+ {cg_bs_put(bif_fail(Fail), Args),St};
+cg_block([#cg_set{op=bs_test_tail,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Ctx,{integer,Bits}] = beam_args(Args0, St),
+ {[{test,bs_test_tail2,bif_fail(Fail),[Ctx,Bits]}],St};
+cg_block([#cg_set{op={float,checkerror},dst=Bool}], {Bool,Fail}, St) ->
+ {[{fcheckerror,bif_fail(Fail)}],St};
+cg_block([#cg_set{op=is_tagged_tuple,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Src,{integer,Arity},Tag] = beam_args(Args0, St),
+ {[{test,is_tagged_tuple,ensure_label(Fail, St),[Src,Arity,Tag]}],St};
+cg_block([#cg_set{op=is_nonempty_list,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ Args = beam_args(Args0, St),
+ {[{test,is_nonempty_list,ensure_label(Fail, St),Args}],St};
+cg_block([#cg_set{op=has_map_field,dst=Bool,args=Args0}], {Bool,Fail}, St) ->
+ [Src,Key] = beam_args(Args0, St),
+ {[{test,has_map_fields,Fail,Src,{list,[Key]}}],St};
+cg_block([#cg_set{op=call}=Call], {_Bool,_Fail}=Context, St0) ->
+ {Is0,St1} = cg_call(Call, body, none, St0),
+ {Is1,St} = cg_block([], Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=call,dst=Dst0}=Call], Context, St) ->
+ Dst = beam_arg(Dst0, St),
+ case Context of
+ {return,Dst,_} ->
+ cg_call(Call, tail, Context, St);
+ _ ->
+ cg_call(Call, body, Context, St)
+ end;
+cg_block([#cg_set{op=call}=Call|T], Context, St0) ->
+ {Is0,St1} = cg_call(Call, body, none, St0),
+ {Is1,St} = cg_block(T, Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=make_fun,dst=Dst0,args=[Local|Args0]}|T],
+ Context, St0) ->
+ #b_local{name=#b_literal{val=Func},arity=Arity} = Local,
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ {FuncLbl,St1} = local_func_label(Func, Arity, St0),
+ Is0 = setup_args(Args) ++
+ [{make_fun2,{f,FuncLbl},0,0,length(Args)}|copy({x,0}, Dst)],
+ {Is1,St} = cg_block(T, Context, St1),
+ {Is0++Is1,St};
+cg_block([#cg_set{op=copy}|_]=T0, Context, St0) ->
+ {Is0,T} = cg_copy(T0, St0),
+ {Is1,St} = cg_block(T, Context, St0),
+ Is = Is0 ++ Is1,
+ case is_call(T) of
+ {yes,Arity} ->
+ {opt_call_moves(Is, Arity),St};
+ no ->
+ {Is,St}
+ end;
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=Set], none, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ Is = cg_instr(Op, Args, Dst, Set),
+ {Is,St};
+cg_block([#cg_set{op=Op,dst=Dst0,args=Args0}=Set|T], Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ Is0 = cg_instr(Op, Args, Dst, Set),
+ {Is1,St} = cg_block(T, Context, St0),
+ {Is0++Is1,St};
+cg_block([#cg_alloc{}=Alloc|T], Context, St0) ->
+ Is0 = cg_alloc(Alloc, St0),
+ {Is1,St} = cg_block(T, Context, St0),
+ {Is0++Is1,St};
+cg_block([], {return,Arg,none}, St) ->
+ Is = copy(Arg, {x,0}) ++ [return],
+ {Is,St};
+cg_block([], {return,Arg,N}, St) ->
+ Is = copy(Arg, {x,0}) ++ [{deallocate,N},return],
+ {Is,St};
+cg_block([], none, St) ->
+ {[],St};
+cg_block([], {Bool0,Fail}, St) ->
+ [Bool] = beam_args([Bool0], St),
+ {[{test,is_eq_exact,Fail,[Bool,{atom,true}]}],St}.
+
+cg_copy(T0, St) ->
+ {Copies,T} = splitwith(fun(#cg_set{op=copy}) -> true;
+ (_) -> false
+ end, T0),
+ Moves0 = cg_copy_1(Copies, St),
+ Moves1 = [Move || {move,Src,Dst}=Move <- Moves0, Src =/= Dst],
+ Scratch = {x,1022},
+ Moves = order_moves(Moves1, Scratch),
+ {Moves,T}.
+
+cg_copy_1([#cg_set{dst=Dst0,args=Args}|T], St) ->
+ [Dst,Src] = beam_args([Dst0|Args], St),
+ Copies = cg_copy_1(T, St),
+ case keymember(Dst, 3, Copies) of
+ true ->
+ %% Will be overwritten. Don't generate a move instruction.
+ Copies;
+ false ->
+ [{move,Src,Dst}|Copies]
+ end;
+cg_copy_1([], _St) -> [].
+
+-define(IS_LITERAL(Val), (Val =:= nil orelse
+ element(1, Val) =:= integer orelse
+ element(1, Val) =:= float orelse
+ element(1, Val) =:= atom orelse
+ element(1, Val) =:= literal)).
+
+bif_to_test('and', [V1,V2], Fail) ->
+ [{test,is_eq_exact,Fail,[V1,{atom,true}]},
+ {test,is_eq_exact,Fail,[V2,{atom,true}]}];
+bif_to_test('or', [V1,V2], {f,Lbl}=Fail) when Lbl =/= 0 ->
+ %% Labels are spaced 2 apart. We can create a new
+ %% label by incrementing the Fail label.
+ SuccLabel = Lbl + 1,
+ [{test,is_eq_exact,{f,SuccLabel},[V1,{atom,false}]},
+ {test,is_eq_exact,Fail,[V2,{atom,true}]},
+ {label,SuccLabel}];
+bif_to_test('not', [Var], Fail) ->
+ [{test,is_eq_exact,Fail,[Var,{atom,false}]}];
+bif_to_test(Name, Args, Fail) ->
+ [bif_to_test_1(Name, Args, Fail)].
+
+bif_to_test_1(is_atom, [_]=Ops, Fail) ->
+ {test,is_atom,Fail,Ops};
+bif_to_test_1(is_boolean, [_]=Ops, Fail) ->
+ {test,is_boolean,Fail,Ops};
+bif_to_test_1(is_binary, [_]=Ops, Fail) ->
+ {test,is_binary,Fail,Ops};
+bif_to_test_1(is_bitstring,[_]=Ops, Fail) ->
+ {test,is_bitstr,Fail,Ops};
+bif_to_test_1(is_float, [_]=Ops, Fail) ->
+ {test,is_float,Fail,Ops};
+bif_to_test_1(is_function, [_]=Ops, Fail) ->
+ {test,is_function,Fail,Ops};
+bif_to_test_1(is_function, [_,_]=Ops, Fail) ->
+ {test,is_function2,Fail,Ops};
+bif_to_test_1(is_integer, [_]=Ops, Fail) ->
+ {test,is_integer,Fail,Ops};
+bif_to_test_1(is_list, [_]=Ops, Fail) ->
+ {test,is_list,Fail,Ops};
+bif_to_test_1(is_map, [_]=Ops, Fail) ->
+ {test,is_map,Fail,Ops};
+bif_to_test_1(is_number, [_]=Ops, Fail) ->
+ {test,is_number,Fail,Ops};
+bif_to_test_1(is_pid, [_]=Ops, Fail) ->
+ {test,is_pid,Fail,Ops};
+bif_to_test_1(is_port, [_]=Ops, Fail) ->
+ {test,is_port,Fail,Ops};
+bif_to_test_1(is_reference, [_]=Ops, Fail) ->
+ {test,is_reference,Fail,Ops};
+bif_to_test_1(is_tuple, [_]=Ops, Fail) ->
+ {test,is_tuple,Fail,Ops};
+bif_to_test_1('=<', [A,B], Fail) ->
+ {test,is_ge,Fail,[B,A]};
+bif_to_test_1('>', [A,B], Fail) ->
+ {test,is_lt,Fail,[B,A]};
+bif_to_test_1('<', [_,_]=Ops, Fail) ->
+ {test,is_lt,Fail,Ops};
+bif_to_test_1('>=', [_,_]=Ops, Fail) ->
+ {test,is_ge,Fail,Ops};
+bif_to_test_1('==', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_eq,Fail,[A,C]};
+bif_to_test_1('==', [_,_]=Ops, Fail) ->
+ {test,is_eq,Fail,Ops};
+bif_to_test_1('/=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_ne,Fail,[A,C]};
+bif_to_test_1('/=', [_,_]=Ops, Fail) ->
+ {test,is_ne,Fail,Ops};
+bif_to_test_1('=:=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_eq_exact,Fail,[A,C]};
+bif_to_test_1('=:=', [_,_]=Ops, Fail) ->
+ {test,is_eq_exact,Fail,Ops};
+bif_to_test_1('=/=', [C,A], Fail) when ?IS_LITERAL(C) ->
+ {test,is_ne_exact,Fail,[A,C]};
+bif_to_test_1('=/=', [_,_]=Ops, Fail) ->
+ {test,is_ne_exact,Fail,Ops}.
+
+opt_call_moves(Is0, Arity) ->
+ {Moves0,Is} = splitwith(fun({move,_,_}) -> true;
+ ({kill,_}) -> true;
+ (_) -> false
+ end, Is0),
+ Moves = opt_call_moves_1(Moves0, Arity),
+ Moves ++ Is.
+
+opt_call_moves_1([{move,Src,{x,_}=Tmp}=M1|[{kill,_}|_]=Is], Arity) ->
+ %% There could be a {move,Tmp,{x,0}} instruction after the
+ %% kill/1 instructions (moved to there by opt_move_to_x0/1).
+ case splitwith(fun({kill,_}) -> true;
+ (_) -> false
+ end, Is) of
+ {Kills,[{move,{x,_}=Tmp,{x,0}}=M2]} ->
+ %% The two move/2 instructions (M1 and M2) can be combined
+ %% to one. The question is, though, is it safe to place
+ %% them after the kill/1 instructions?
+ case is_killed(Src, Kills, Arity) of
+ true ->
+ %% Src (a Y register) is killed by one of the
+ %% kill/1 instructions. Thus M1 and M2
+ %% must be placed before the kill/1 instructions
+ %% (essentially undoing what opt_move_to_x0/1
+ %% did, which turned out to be a pessimization
+ %% in this case).
+ opt_call_moves_1([M1,M2|Kills], Arity);
+ false ->
+ %% Src is not killed by any of the kill/1
+ %% instructions. Thus it is safe to place
+ %% M1 and M2 after the kill/1 instructions.
+ opt_call_moves_1(Kills++[M1,M2], Arity)
+ end;
+ {_,_} ->
+ [M1|Is]
+ end;
+opt_call_moves_1([{move,Src,{x,_}=Tmp}=M1,{move,Tmp,Dst}=M2|Is], Arity) ->
+ case is_killed(Tmp, Is, Arity) of
+ true ->
+ %% The X register Tmp is never used again. We can collapse
+ %% the two move instruction into one.
+ [{move,Src,Dst}|opt_call_moves_1(Is, Arity)];
+ false ->
+ [M1|opt_call_moves_1([M2|Is], Arity)]
+ end;
+opt_call_moves_1([M|Ms], Arity) ->
+ [M|opt_call_moves_1(Ms, Arity)];
+opt_call_moves_1([], _Arity) -> [].
+
+is_killed(Y, [{kill,Y}|_], _) ->
+ true;
+is_killed(R, [{kill,_}|Is], Arity) ->
+ is_killed(R, Is, Arity);
+is_killed(R, [{move,R,_}|_], _) ->
+ false;
+is_killed(R, [{move,_,R}|_], _) ->
+ true;
+is_killed(R, [{move,_,_}|Is], Arity) ->
+ is_killed(R, Is, Arity);
+is_killed({x,X}, [], Arity) ->
+ X >= Arity;
+is_killed({y,_}, [], _) ->
+ false.
+
+cg_alloc(#cg_alloc{stack=none,words=#need{h=0,f=0}}, _St) ->
+ [];
+cg_alloc(#cg_alloc{stack=none,words=Need,live=Live}, _St) ->
+ [{test_heap,alloc(Need),Live}];
+cg_alloc(#cg_alloc{stack=Stk,words=Need,live=Live,def_yregs=DefYregs},
+ #cg{regs=Regs}) when is_integer(Stk) ->
+ Alloc = alloc(Need),
+ All = [{y,Y} || Y <- lists:seq(0, Stk-1)],
+ Def = ordsets:from_list([maps:get(V, Regs) || V <- DefYregs]),
+ NeedInit = ordsets:subtract(All, Def),
+ NoZero = length(Def)*2 > Stk,
+ I = case {NoZero,Alloc} of
+ {true,0} -> {allocate,Stk,Live};
+ {true,_} -> {allocate_heap,Stk,Alloc,Live};
+ {false,0} -> {allocate_zero,Stk,Live};
+ {false,_} -> {allocate_heap_zero,Stk,Alloc,Live}
+ end,
+ [I|case NoZero of
+ true -> [{init,Y} || Y <- NeedInit];
+ false -> []
+ end].
+
+alloc(#need{h=Words,f=0}) ->
+ Words;
+alloc(#need{h=Words,f=Floats}) ->
+ {alloc,[{words,Words},{floats,Floats}]}.
+
+is_call([#cg_set{op=call,args=[#b_var{}|Args]}|_]) ->
+ {yes,1+length(Args)};
+is_call([#cg_set{op=call,args=[_|Args]}|_]) ->
+ {yes,length(Args)};
+is_call([#cg_set{op=make_fun,args=[_|Args]}|_]) ->
+ {yes,length(Args)};
+is_call(_) ->
+ no.
+
+cg_call(#cg_set{anno=Anno,op=call,dst=Dst0,args=[#b_local{}=Func0|Args0]},
+ Where, Context, St0) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St0),
+ #b_local{name=Name0,arity=Arity} = Func0,
+ {atom,Name} = beam_arg(Name0, St0),
+ {FuncLbl,St} = local_func_label(Name, Arity, St0),
+ Line = call_line(Where, local, Anno),
+ Call = build_call(call, Arity, {f,FuncLbl}, Context, Dst),
+ Is = setup_args(Args, Anno, Context, St) ++ Line ++ Call,
+ {Is,St};
+cg_call(#cg_set{anno=Anno0,op=call,dst=Dst0,args=[#b_remote{}=Func0|Args0]},
+ Where, Context, St) ->
+ [Dst|Args] = beam_args([Dst0|Args0], St),
+ #b_remote{mod=Mod0,name=Name0,arity=Arity} = Func0,
+ case {beam_arg(Mod0, St),beam_arg(Name0, St)} of
+ {{atom,Mod},{atom,Name}} ->
+ Func = {extfunc,Mod,Name,Arity},
+ Line = call_line(Where, Func, Anno0),
+ Call = build_call(call_ext, Arity, Func, Context, Dst),
+ Anno = case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ true ->
+ %% There is no need to kill Y registers
+ %% before calling an exit BIF.
+ maps:remove(kill_yregs, Anno0);
+ false ->
+ Anno0
+ end,
+ Is = setup_args(Args, Anno, Context, St) ++ Line ++ Call,
+ {Is,St};
+ {Mod,Name} ->
+ Apply = build_apply(Arity, Context, Dst),
+ Is = setup_args(Args++[Mod,Name], Anno0, Context, St) ++
+ [line(Anno0)] ++ Apply,
+ {Is,St}
+ end;
+cg_call(#cg_set{anno=Anno,op=call,dst=Dst0,args=Args0},
+ Where, Context, St) ->
+ [Dst,Func|Args] = beam_args([Dst0|Args0], St),
+ Line = call_line(Where, Func, Anno),
+ Arity = length(Args),
+ Call = build_call(call_fun, Arity, Func, Context, Dst),
+ Is = setup_args(Args++[Func], Anno, Context, St) ++ Line ++ Call,
+ {Is,St}.
+
+build_call(call_fun, Arity, _Func, none, Dst) ->
+ [{call_fun,Arity}|copy({x,0}, Dst)];
+build_call(call_fun, Arity, _Func, {return,Dst,N}, Dst) when is_integer(N) ->
+ [{call_fun,Arity},{deallocate,N},return];
+build_call(call_fun, Arity, _Func, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{call_fun,Arity},{move,Val,{x,0}},{deallocate,N},return];
+build_call(call_ext, 2, {extfunc,erlang,'!',2}, none, Dst) ->
+ [send|copy({x,0}, Dst)];
+build_call(call_ext, 2, {extfunc,erlang,'!',2}, {return,Dst,N}, Dst)
+ when is_integer(N) ->
+ [send,{deallocate,N},return];
+build_call(Prefix, Arity, Func, {return,Dst,none}, Dst) ->
+ I = case Prefix of
+ call -> call_only;
+ call_ext -> call_ext_only
+ end,
+ [{I,Arity,Func}];
+build_call(call_ext, Arity, {extfunc,Mod,Name,Arity}=Func, {return,_,none}, _Dst) ->
+ true = erl_bifs:is_exit_bif(Mod, Name, Arity), %Assertion.
+ [{call_ext_only,Arity,Func}];
+build_call(Prefix, Arity, Func, {return,Dst,N}, Dst) when is_integer(N) ->
+ I = case Prefix of
+ call -> call_last;
+ call_ext -> call_ext_last
+ end,
+ [{I,Arity,Func,N}];
+build_call(I, Arity, Func, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{I,Arity,Func}|copy(Val, {x,0})++[{deallocate,N},return]];
+build_call(I, Arity, Func, none, Dst) ->
+ [{I,Arity,Func}|copy({x,0}, Dst)].
+
+build_apply(Arity, {return,Dst,N}, Dst) when is_integer(N) ->
+ [{apply_last,Arity,N}];
+build_apply(Arity, {return,Val,N}, _Dst) when is_integer(N) ->
+ [{apply,Arity}|copy(Val, {x,0})++[{deallocate,N},return]];
+build_apply(Arity, none, Dst) ->
+ [{apply,Arity}|copy({x,0}, Dst)].
+
+cg_instr(put_map, [{atom,assoc},SrcMap|Ss], Dst, Set) ->
+ Live = get_live(Set),
+ [{put_map_assoc,{f,0},SrcMap,Dst,Live,{list,Ss}}];
+cg_instr(bs_get_tail, [Src], Dst, Set) ->
+ Live = get_live(Set),
+ [{bs_get_tail,Src,Dst,Live}];
+cg_instr(bs_get_position, [Ctx], Dst, Set) ->
+ Live = get_live(Set),
+ [{bs_get_position,Ctx,Dst,Live}];
+cg_instr(Op, Args, Dst, _Set) ->
+ cg_instr(Op, Args, Dst).
+
+cg_instr(bs_init_writable, Args, Dst) ->
+ setup_args(Args) ++ [bs_init_writable|copy({x,0}, Dst)];
+cg_instr(bs_restore, [Ctx,Slot], _Dst) ->
+ case Slot of
+ {integer,N} ->
+ [{bs_restore2,Ctx,N}];
+ {atom,start} ->
+ [{bs_restore2,Ctx,Slot}]
+ end;
+cg_instr(bs_save, [Ctx,Slot], _Dst) ->
+ {integer,N} = Slot,
+ [{bs_save2,Ctx,N}];
+cg_instr(bs_set_position, [Ctx,Pos], _Dst) ->
+ [{bs_set_position,Ctx,Pos}];
+cg_instr(build_stacktrace, Args, Dst) ->
+ setup_args(Args) ++ [build_stacktrace|copy({x,0}, Dst)];
+cg_instr(set_tuple_element=Op, [New,Tuple,{integer,Index}], _Dst) ->
+ [{Op,New,Tuple,Index}];
+cg_instr({float,clearerror}, [], _Dst) ->
+ [fclearerror];
+cg_instr({float,get}, [Src], Dst) ->
+ [{fmove,Src,Dst}];
+cg_instr({float,put}, [Src], Dst) ->
+ [{fmove,Src,Dst}];
+cg_instr(get_hd=Op, [Src], Dst) ->
+ [{Op,Src,Dst}];
+cg_instr(get_tl=Op, [Src], Dst) ->
+ [{Op,Src,Dst}];
+cg_instr(get_tuple_element=Op, [Src,{integer,N}], Dst) ->
+ [{Op,Src,N,Dst}];
+cg_instr(put_list=Op, [Hd,Tl], Dst) ->
+ [{Op,Hd,Tl,Dst}];
+cg_instr(put_tuple, Elements, Dst) ->
+ [{put_tuple2,Dst,{list,Elements}}];
+cg_instr(put_tuple_arity, [{integer,Arity}], Dst) ->
+ [{put_tuple,Arity,Dst}];
+cg_instr(put_tuple_elements, Elements, _Dst) ->
+ [{put,E} || E <- Elements];
+cg_instr(raw_raise, Args, Dst) ->
+ setup_args(Args) ++ [raw_raise|copy({x,0}, Dst)];
+cg_instr(remove_message, [], _Dst) ->
+ [remove_message];
+cg_instr(resume, [A,B], _Dst) ->
+ [{bif,raise,{f,0},[A,B],{x,0}}];
+cg_instr(timeout, [], _Dst) ->
+ [timeout].
+
+cg_test(bs_add=Op, Fail, [Src1,Src2,{integer,Unit}], Dst, _I) ->
+ [{Op,Fail,[Src1,Src2,Unit],Dst}];
+cg_test(bs_skip, Fail, Args, _Dst, I) ->
+ cg_bs_skip(Fail, Args, I);
+cg_test(bs_utf8_size=Op, Fail, [Src], Dst, _I) ->
+ [{Op,Fail,Src,Dst}];
+cg_test(bs_utf16_size=Op, Fail, [Src], Dst, _I) ->
+ [{Op,Fail,Src,Dst}];
+cg_test({float,convert}, Fail, [Src], Dst, _I) ->
+ {f,0} = Fail, %Assertion.
+ [{fconv,Src,Dst}];
+cg_test({float,Op0}, Fail, Args, Dst, #cg_set{anno=Anno}) ->
+ Op = case Op0 of
+ '+' -> fadd;
+ '-' when length(Args) =:= 2 -> fsub;
+ '-' -> fnegate;
+ '*' -> fmul;
+ '/' -> fdiv
+ end,
+ [line(Anno),{bif,Op,Fail,Args,Dst}];
+cg_test(get_map_element, Fail, [Map,Key], Dst, _I) ->
+ [{get_map_elements,Fail,Map,{list,[Key,Dst]}}];
+cg_test(peek_message, Fail, [], Dst, _I) ->
+ [{loop_rec,Fail,{x,0}}|copy({x,0}, Dst)];
+cg_test(put_map, Fail, [{atom,exact},SrcMap|Ss], Dst, Set) ->
+ Live = get_live(Set),
+ [{put_map_exact,Fail,SrcMap,Dst,Live,{list,Ss}}];
+cg_test(wait_timeout, Fail, [Timeout], _Dst, _) ->
+ case Timeout of
+ {atom,infinity} ->
+ [{wait,Fail}];
+ _ ->
+ [{wait_timeout,Fail,Timeout}]
+ end.
+
+cg_bs_get(Fail, #cg_set{dst=Dst0,args=[#b_literal{val=Type}|Ss0]}=Set, St) ->
+ Op = case Type of
+ integer -> bs_get_integer2;
+ float -> bs_get_float2;
+ binary -> bs_get_binary2;
+ utf8 -> bs_get_utf8;
+ utf16 -> bs_get_utf16;
+ utf32 -> bs_get_utf32
+ end,
+ [Dst|Ss1] = beam_args([Dst0|Ss0], St),
+ Ss = case Ss1 of
+ [Ctx,{literal,Flags},Size,{integer,Unit}] ->
+ %% Plain integer/float/binary.
+ [Ctx,Size,Unit,field_flags(Flags, Set)];
+ [Ctx,{literal,Flags}] ->
+ %% Utf8/16/32.
+ [Ctx,field_flags(Flags, Set)]
+ end,
+ Live = get_live(Set),
+ [{test,Op,Fail,Live,Ss,Dst}].
+
+cg_bs_skip(Fail, [{atom,Type}|Ss0], Set) ->
+ Op = case Type of
+ utf8 -> bs_skip_utf8;
+ utf16 -> bs_skip_utf16;
+ utf32 -> bs_skip_utf32;
+ _ -> bs_skip_bits2
+ end,
+ Live = get_live(Set),
+ Ss = case Ss0 of
+ [Ctx,{literal,Flags},Size,{integer,Unit}] ->
+ %% Plain integer/float/binary.
+ [Ctx,Size,Unit,field_flags(Flags, Set)];
+ [Ctx,{literal,Flags}] ->
+ %% Utf8/16/32.
+ [Ctx,Live,field_flags(Flags, Set)]
+ end,
+ case {Type,Ss} of
+ {binary,[_,{atom,all},1,_]} ->
+ [];
+ {binary,[R,{atom,all},U,_]} ->
+ [{test,bs_test_unit,Fail,[R,U]}];
+ {_,_} ->
+ [{test,Op,Fail,Ss}]
+ end.
+
+field_flags(Flags, #cg_set{anno=#{location:={File,Line}}}) ->
+ {field_flags,[{anno,[Line,{file,File}]}|Flags]};
+field_flags(Flags, _) ->
+ {field_flags,Flags}.
+
+cg_bs_put(Fail, [{atom,Type},{literal,Flags}|Args]) ->
+ Op = case Type of
+ integer -> bs_put_integer;
+ float -> bs_put_float;
+ binary -> bs_put_binary;
+ utf8 -> bs_put_utf8;
+ utf16 -> bs_put_utf16;
+ utf32 -> bs_put_utf32
+ end,
+ case Args of
+ [Src,Size,{integer,Unit}] ->
+ [{Op,Fail,Size,Unit,{field_flags,Flags},Src}];
+ [Src] ->
+ [{Op,Fail,{field_flags,Flags},Src}]
+ end.
+
+cg_bs_init(Dst, Size0, Alloc, Unit, Live, Fail) ->
+ Op = case Unit of
+ 1 -> bs_init_bits;
+ 8 -> bs_init2
+ end,
+ Size = cg_bs_init_size(Size0),
+ [{Op,Fail,Size,Alloc,Live,{field_flags,[]},Dst}].
+
+cg_bs_init_size({x,_}=R) -> R;
+cg_bs_init_size({y,_}=R) -> R;
+cg_bs_init_size({integer,Int}) -> Int.
+
+cg_catch(Agg, T0, Context, St0) ->
+ {Moves,T1} = cg_extract(T0, Agg, St0),
+ {T,St} = cg_block(T1, Context, St0),
+ {Moves++T,St}.
+
+cg_try(Agg, Tag, T0, Context, St0) ->
+ {Moves0,T1} = cg_extract(T0, Agg, St0),
+ Moves = order_moves(Moves0, {x,3}),
+ [#cg_set{op=kill_try_tag}|T2] = T1,
+ {T,St} = cg_block(T2, Context, St0),
+ {[{try_case,Tag}|Moves++T],St}.
+
+cg_extract([#cg_set{op=extract,dst=Dst0,args=Args0}|Is0], Agg, St) ->
+ [Dst,Agg,{integer,X}] = beam_args([Dst0|Args0], St),
+ {Ds,Is} = cg_extract(Is0, Agg, St),
+ case keymember(Dst, 3, Ds) of
+ true ->
+ %% This destination will be overwritten.
+ {Ds,Is};
+ false ->
+ {copy({x,X}, Dst)++Ds,Is}
+ end;
+cg_extract(Is, _, _) ->
+ {[],Is}.
+
+copy(Src, Src) -> [];
+copy(Src, Dst) -> [{move,Src,Dst}].
+
+force_reg({literal,_}=Lit, Reg) ->
+ {Reg,[{move,Lit,Reg}]};
+force_reg({Kind,_}=R, _) when Kind =:= x; Kind =:= y ->
+ {R,[]}.
+
+%% successors(Terminator) -> [Successor].
+%% Return an ordset of all successors for the given terminator.
+
+successors(#cg_br{succ=Succ,fail=Fail}) ->
+ ordsets:from_list([Succ,Fail]);
+successors(#cg_switch{fail=Fail,list=List}) ->
+ ordsets:from_list([Fail|[Lbl || {_,Lbl} <- List]]);
+successors(#cg_ret{}) -> [].
+
+%% linearize(Blocks) -> [{BlockLabel,#cg_blk{}}].
+%% Linearize the intermediate representation of the code. Also
+%% translate blocks from the SSA records to internal record types
+%% used only in this module.
+
+linearize(Blocks) ->
+ Linear = beam_ssa:linearize(Blocks),
+ linearize_1(Linear, Blocks).
+
+linearize_1([{?BADARG_BLOCK,_}|Ls], Blocks) ->
+ linearize_1(Ls, Blocks);
+linearize_1([{L,Block0}|Ls], Blocks) ->
+ Block = translate_block(L, Block0, Blocks),
+ [{L,Block}|linearize_1(Ls, Blocks)];
+linearize_1([], _Blocks) -> [].
+
+%% translate_block(BlockLabel, #b_blk{}, Blocks) -> #cg_blk{}.
+%% Translate a block to the internal records used in this module.
+%% Also eliminate phi nodes, replacing them with 'copy' instructions
+%% in the predecessor blocks.
+
+translate_block(L, #b_blk{anno=Anno,is=Is0,last=Last0}, Blocks) ->
+ Last = translate_terminator(Last0),
+ PhiCopies = translate_phis(L, Last, Blocks),
+ Is1 = translate_is(Is0, PhiCopies),
+ Is = case Anno of
+ #{frame_size:=Size} ->
+ Alloc = #cg_alloc{stack=Size},
+ [Alloc|Is1];
+ #{} -> Is1
+ end,
+ #cg_blk{anno=Anno,is=Is,last=Last}.
+
+translate_is([#b_set{op=phi}|Is], Tail) ->
+ translate_is(Is, Tail);
+translate_is([#b_set{anno=Anno0,op=Op,dst=Dst,args=Args}=I|Is], Tail) ->
+ Anno = case beam_ssa:clobbers_xregs(I) of
+ true -> Anno0#{clobbers=>true};
+ false -> Anno0
+ end,
+ [#cg_set{anno=Anno,op=Op,dst=Dst,args=Args}|translate_is(Is, Tail)];
+translate_is([], Tail) -> Tail.
+
+translate_terminator(#b_ret{anno=Anno,arg=Arg}) ->
+ Dealloc = case Anno of
+ #{deallocate:=N} -> N;
+ #{} -> none
+ end,
+ #cg_ret{arg=Arg,dealloc=Dealloc};
+translate_terminator(#b_br{bool=#b_literal{val=true},succ=Succ}) ->
+ #cg_br{bool=#b_literal{val=true},succ=Succ,fail=Succ};
+translate_terminator(#b_br{bool=#b_literal{val=false},fail=Fail}) ->
+ #cg_br{bool=#b_literal{val=true},succ=Fail,fail=Fail};
+translate_terminator(#b_br{bool=Bool,succ=Succ,fail=Fail}) ->
+ #cg_br{bool=Bool,succ=Succ,fail=Fail};
+translate_terminator(#b_switch{arg=Bool,fail=Fail,list=List}) ->
+ #cg_switch{arg=Bool,fail=Fail,list=List}.
+
+translate_phis(L, #cg_br{succ=Target,fail=Target}, Blocks) ->
+ #b_blk{is=Is} = maps:get(Target, Blocks),
+ Phis = takewhile(fun(#b_set{op=phi}) -> true;
+ (#b_set{}) -> false
+ end, Is),
+ phi_copies(Phis, L);
+translate_phis(_, _, _) -> [].
+
+phi_copies([#b_set{dst=Dst,args=PhiArgs}|Sets], L) ->
+ CopyArgs = [V || {V,Target} <- PhiArgs, Target =:= L],
+ [#cg_set{op=copy,dst=Dst,args=CopyArgs}|phi_copies(Sets, L)];
+phi_copies([], _) -> [].
+
+%% opt_move_to_x0([Instruction]) -> [Instruction].
+%% Simple peep-hole optimization to move a {move,Any,{x,0}} past
+%% any kill up to the next call instruction. (To give the loader
+%% an opportunity to combine the 'move' and the 'call' instructions.)
+
+opt_move_to_x0(Moves) ->
+ opt_move_to_x0(Moves, []).
+
+opt_move_to_x0([{move,_,{x,0}}=I|Is0], Acc0) ->
+ case move_past_kill(Is0, I, Acc0) of
+ impossible -> opt_move_to_x0(Is0, [I|Acc0]);
+ {Is,Acc} -> opt_move_to_x0(Is, Acc)
+ end;
+opt_move_to_x0([I|Is], Acc) ->
+ opt_move_to_x0(Is, [I|Acc]);
+opt_move_to_x0([], Acc) -> reverse(Acc).
+
+move_past_kill([{kill,Src}|_], {move,Src,_}, _) ->
+ impossible;
+move_past_kill([{kill,_}=I|Is], Move, Acc) ->
+ move_past_kill(Is, Move, [I|Acc]);
+move_past_kill(Is, Move, Acc) ->
+ {Is,[Move|Acc]}.
+
+%% setup_args(Args, Anno, Context) -> [Instruction].
+%% setup_args(Args) -> [Instruction].
+%% Set up X registers for a call.
+
+setup_args(Args, Anno, none, St) ->
+ case {setup_args(Args),kill_yregs(Anno, St)} of
+ {Moves,[]} ->
+ Moves;
+ {Moves,Kills} ->
+ opt_move_to_x0(Moves ++ Kills)
+ end;
+setup_args(Args, _, _, _) ->
+ setup_args(Args).
+
+setup_args([]) ->
+ [];
+setup_args([_|_]=Args) ->
+ Moves = gen_moves(Args, 0, []),
+ Scratch = {x,1+last(sort([length(Args)-1|[X || {x,X} <- Args]]))},
+ order_moves(Moves, Scratch).
+
+%% kill_yregs(Anno, #cg{}) -> [{kill,{y,Y}}].
+%% Kill Y registers that will not be used again.
+
+kill_yregs(#{kill_yregs:=Kill}, #cg{regs=Regs}) ->
+ ordsets:from_list([{kill,maps:get(V, Regs)} || V <- Kill]);
+kill_yregs(#{}, #cg{}) -> [].
+
+%% gen_moves(As, I, Acc)
+%% Generate the basic move instruction to move the arguments
+%% to their proper registers. The list will be sorted on
+%% destinations. (I.e. the move to {x,0} will be first --
+%% see the comment to order_moves/2.)
+
+gen_moves([A|As], I, Acc) ->
+ gen_moves(As, I+1, copy(A, {x,I}) ++ Acc);
+gen_moves([], _, Acc) ->
+ keysort(3, Acc).
+
+%% order_moves([Move], ScratchReg) -> [Move]
+%% Orders move instruction so that source registers are not
+%% destroyed before they are used. If there are cycles
+%% (such as {move,{x,0},{x,1}}, {move,{x,1},{x,1}}),
+%% the scratch register is used to break up the cycle.
+%% If possible, the first move of the input list is placed
+%% last in the result list (to make the move to {x,0} occur
+%% just before the call to allow the Beam loader to coalesce
+%% the instructions).
+
+order_moves(Ms, Scr) -> order_moves(Ms, Scr, []).
+
+order_moves([{move,_,_}=M|Ms0], ScrReg, Acc0) ->
+ {Chain,Ms} = collect_chain(Ms0, [M], ScrReg),
+ Acc = reverse(Chain, Acc0),
+ order_moves(Ms, ScrReg, Acc);
+order_moves([], _, Acc) -> Acc.
+
+collect_chain(Ms, Path, ScrReg) ->
+ collect_chain(Ms, Path, [], ScrReg).
+
+collect_chain([{move,Src,Same}=M|Ms0], [{move,Same,_}|_]=Path, Others, ScrReg) ->
+ case keymember(Src, 3, Path) of
+ false ->
+ collect_chain(reverse(Others, Ms0), [M|Path], [], ScrReg);
+ true ->
+ %% There is a cycle, which we must break up.
+ {break_up_cycle(M, Path, ScrReg),reverse(Others, Ms0)}
+ end;
+collect_chain([M|Ms], Path, Others, ScrReg) ->
+ collect_chain(Ms, Path, [M|Others], ScrReg);
+collect_chain([], Path, Others, _) ->
+ {Path,Others}.
+
+break_up_cycle({move,Src,_}=M, Path, ScrReg) ->
+ [{move,ScrReg,Src},M|break_up_cycle1(Src, Path, ScrReg)].
+
+break_up_cycle1(Dst, [{move,Src,Dst}|Path], ScrReg) ->
+ [{move,Src,ScrReg}|Path];
+break_up_cycle1(Dst, [M|Path], LastMove) ->
+ [M|break_up_cycle1(Dst, Path, LastMove)].
+
+%%%
+%%% General utility functions.
+%%%
+
+verify_beam_register({x,_}=Reg) -> Reg.
+
+is_beam_register({x,_}) -> true;
+is_beam_register(_) -> false.
+
+get_register(V, Regs) ->
+ case is_beam_register(V) of
+ true -> V;
+ false -> maps:get(V, Regs)
+ end.
+
+beam_args(As, St) ->
+ [beam_arg(A, St) || A <- As].
+
+beam_arg(#b_var{}=Name, #cg{regs=Regs}) ->
+ maps:get(Name, Regs);
+beam_arg(#b_literal{val=Val}, _) ->
+ if
+ is_atom(Val) -> {atom,Val};
+ is_float(Val) -> {float,Val};
+ is_integer(Val) -> {integer,Val};
+ Val =:= [] -> nil;
+ true -> {literal,Val}
+ end;
+beam_arg(Reg, _) ->
+ verify_beam_register(Reg).
+
+new_block_label(L, St0) ->
+ {_Lbl,St} = label_for_block(L, St0),
+ St.
+
+def_block_label(L, #cg{labels=Labels,used_labels=Used}) ->
+ Lbl = maps:get(L, Labels),
+ case gb_sets:is_member(Lbl, Used) of
+ false -> [];
+ true -> [{label,Lbl}]
+ end.
+
+use_block_labels(Ls, St) ->
+ mapfoldl(fun use_block_label/2, St, Ls).
+
+use_block_label(L, #cg{used_labels=Used,catches=Catches}=St0) ->
+ {Lbl,St} = label_for_block(L, St0),
+ case gb_sets:is_member(L, Catches) of
+ true ->
+ {{catch_tag,{f,Lbl}},
+ St#cg{used_labels=gb_sets:add(Lbl, Used)}};
+ false ->
+ {{f,Lbl},St#cg{used_labels=gb_sets:add(Lbl, Used)}}
+ end.
+
+label_for_block(L, #cg{labels=Labels0}=St0) ->
+ case Labels0 of
+ #{L:=Lbl} ->
+ {Lbl,St0};
+ #{} ->
+ {Lbl,St} = new_label(St0),
+ Labels = Labels0#{L=>Lbl},
+ {Lbl,St#cg{labels=Labels}}
+ end.
+
+%% local_func_label(Name, Arity, State) -> {Label,State'}
+%% local_func_label({Name,Arity}, State) -> {Label,State'}
+%% Get the function entry label for a local function.
+
+local_func_label(Name, Arity, St) ->
+ local_func_label({Name,Arity}, St).
+
+local_func_label(Key, #cg{functable=Map}=St0) ->
+ case Map of
+ #{Key := Label} ->
+ {Label,St0};
+ _ ->
+ {Label,St} = new_label(St0),
+ {Label,St#cg{functable=Map#{Key => Label}}}
+ end.
+
+%% is_gc_bif(Name, Args) -> true|false.
+%% Determines whether the BIF Name/Arity might do a GC.
+
+-spec is_gc_bif(atom(), [beam_ssa:value()]) -> boolean().
+
+is_gc_bif(hd, [_]) -> false;
+is_gc_bif(tl, [_]) -> false;
+is_gc_bif(self, []) -> false;
+is_gc_bif(node, []) -> false;
+is_gc_bif(node, [_]) -> false;
+is_gc_bif(element, [_,_]) -> false;
+is_gc_bif(get, [_]) -> false;
+is_gc_bif(is_map_key, [_,_]) -> false;
+is_gc_bif(map_get, [_,_]) -> false;
+is_gc_bif(tuple_size, [_]) -> false;
+is_gc_bif(Bif, Args) ->
+ Arity = length(Args),
+ not (erl_internal:bool_op(Bif, Arity) orelse
+ erl_internal:new_type_test(Bif, Arity) orelse
+ erl_internal:comp_op(Bif, Arity)).
+
+%% new_label(St) -> {L,St}.
+
+new_label(#cg{lcount=Next}=St) ->
+ %% Advance the label counter by 2 to allow us to create
+ %% a label for 'or' by incrementing an existing label.
+ {Next,St#cg{lcount=Next+2}}.
+
+%% call_line(tail|body, Func, Anno) -> [] | [{line,...}].
+%% Produce a line instruction if it will be needed by the
+%% call to Func.
+
+call_line(_Context, {extfunc,Mod,Name,Arity}, Anno) ->
+ case erl_bifs:is_safe(Mod, Name, Arity) of
+ false ->
+ %% The call could be to a BIF.
+ %% We'll need a line instruction in case the
+ %% BIF call fails.
+ [line(Anno)];
+ true ->
+ %% Call to a safe BIF. Since it cannot fail,
+ %% we don't need any line instruction here.
+ []
+ end;
+call_line(body, _, Anno) ->
+ [line(Anno)];
+call_line(tail, local, _) ->
+ %% Tail-recursive call to a local function. A line
+ %% instruction will not be useful.
+ [];
+call_line(tail, _, Anno) ->
+ %% Call to a fun.
+ [line(Anno)].
+
+%% line(Le) -> {line,[] | {location,File,Line}}
+%% Create a line instruction, containing information about
+%% the current filename and line number. A line information
+%% instruction should be placed before any operation that could
+%% cause an exception.
+
+line(#{location:={File,Line}}) ->
+ {line,[{location,File,Line}]};
+line(#{}) ->
+ {line,[]}.
+
+flatmapfoldl(F, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = F(Hd, Accu0),
+ {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
+ {R++Rs,Accu2};
+flatmapfoldl(_, Accu, []) -> {[],Accu}.
diff --git a/lib/compiler/src/beam_ssa_dead.erl b/lib/compiler/src/beam_ssa_dead.erl
new file mode 100644
index 0000000000..c20652580d
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_dead.erl
@@ -0,0 +1,1001 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Dead code is code that is executed but has no effect. This
+%% optimization pass either removes dead code or jumps around it,
+%% potentially making it unreachable so that it can be dropped
+%% the next time beam_ssa:linearize/1 is called.
+%%
+
+-module(beam_ssa_dead).
+-export([opt/1]).
+
+-include("beam_ssa.hrl").
+-import(lists, [append/1,last/1,member/2,takewhile/2,reverse/1]).
+
+-type used_vars() :: #{beam_ssa:label():=ordsets:ordset(beam_ssa:var_name())}.
+
+-type basic_type_test() :: atom() | {'is_tagged_tuple',pos_integer(),atom()}.
+-type type_test() :: basic_type_test() | {'not',basic_type_test()}.
+-type op_name() :: atom().
+-type basic_rel_op() :: {op_name(),beam_ssa:b_var(),beam_ssa:value()} |
+ {basic_type_test(),beam_ssa:value()}.
+-type rel_op() :: {op_name(),beam_ssa:b_var(),beam_ssa:value()} |
+ {type_test(),beam_ssa:value()}.
+
+-record(st,
+ {bs :: beam_ssa:block_map(),
+ us :: used_vars(),
+ skippable :: #{beam_ssa:label():='true'},
+ rel_op=none :: 'none' | rel_op(),
+ target=any :: 'any' | 'one_way' | beam_ssa:label()
+ }).
+
+-spec opt([{Label0,Block0}]) -> [{Label,Block}] when
+ Label0 :: beam_ssa:label(),
+ Block0 :: beam_ssa:b_blk(),
+ Label :: beam_ssa:label(),
+ Block :: beam_ssa:b_blk().
+
+opt(Linear) ->
+ {Used,Skippable} = used_vars(Linear),
+ Blocks0 = maps:from_list(Linear),
+ St0 = #st{bs=Blocks0,us=Used,skippable=Skippable},
+ St = shortcut_opt(St0),
+ #st{bs=Blocks} = combine_eqs(St),
+ beam_ssa:linearize(Blocks).
+
+%%%
+%%% Shortcut br/switch targets.
+%%%
+%%% A br/switch may branch to another br/switch that in turn always
+%%% branches to another target. Rewrite br/switch to refer to the
+%%% ultimate targets directly. That will save execution time, but
+%%% could also reduce the size of the code if some of the original
+%%% targets become unreachable and be deleted.
+%%%
+%%% When rewriting branches, we must be careful not to skip instructions
+%%% that have side effects or that bind variables that will be used
+%%% at the new target.
+%%%
+%%% We must also avoid branching to phi nodes. The reason is
+%%% twofold. First, we might create a critical edge which is strictly
+%%% forbidden. Second, there will be a branch from a block that is not
+%%% listed in the list of predecessors in the phi node. Those
+%%% limitations could probably be overcome, but it is not clear how
+%%% much that would improve the code.
+%%%
+
+shortcut_opt(#st{bs=Blocks}=St) ->
+ %% Processing the blocks in reverse post order seems to give more
+ %% opportunities for optimizations compared to post order. (Based on
+ %% running scripts/diffable with both PO and RPO and looking at
+ %% the diff.)
+ Ls = beam_ssa:rpo(Blocks),
+ shortcut_opt(Ls, #{from=>0}, St).
+
+shortcut_opt([L|Ls], Bs0, #st{bs=Blocks0}=St) ->
+ #b_blk{is=Is,last=Last0} = Blk0 = get_block(L, St),
+ Bs = Bs0#{from:=L},
+ case shortcut_terminator(Last0, Is, Bs, St) of
+ Last0 ->
+ %% No change. No need to update the block.
+ shortcut_opt(Ls, Bs, St);
+ Last ->
+ %% The terminator was simplified in some way.
+ %% Update the block.
+ Blk = Blk0#b_blk{last=Last},
+ Blocks = Blocks0#{L=>Blk},
+ shortcut_opt(Ls, Bs, St#st{bs=Blocks})
+ end;
+shortcut_opt([], _, St) -> St.
+
+shortcut_terminator(#b_br{bool=#b_literal{val=true},succ=Succ0},
+ _Is, Bs, St0) ->
+ St = St0#st{rel_op=none},
+ shortcut(Succ0, Bs, St);
+shortcut_terminator(#b_br{bool=#b_var{}=Bool,succ=Succ0,fail=Fail0}=Br,
+ Is, Bs, St0) ->
+ St = St0#st{target=one_way},
+ RelOp = get_rel_op(Bool, Is),
+ SuccBs = bind_var(Bool, #b_literal{val=true}, Bs),
+ BrSucc = shortcut(Succ0, SuccBs, St#st{rel_op=RelOp}),
+ FailBs = bind_var(Bool, #b_literal{val=false}, Bs),
+ BrFail = shortcut(Fail0, FailBs, St#st{rel_op=invert_op(RelOp)}),
+ case {BrSucc,BrFail} of
+ {#b_br{bool=#b_literal{val=true},succ=Succ},
+ #b_br{bool=#b_literal{val=true},succ=Fail}}
+ when Succ =/= Succ0; Fail =/= Fail0 ->
+ %% One or both of the targets were cut short.
+ beam_ssa:normalize(Br#b_br{succ=Succ,fail=Fail});
+ {_,_} ->
+ %% No change.
+ Br
+ end;
+shortcut_terminator(#b_switch{arg=Bool,list=List0}=Sw, _Is, Bs, St) ->
+ List = shortcut_switch(List0, Bool, Bs, St),
+ beam_ssa:normalize(Sw#b_switch{list=List});
+shortcut_terminator(Last, _Is, _Bs, _St) ->
+ Last.
+
+shortcut_switch([{Lit,L0}|T], Bool, Bs, St0) ->
+ St = St0#st{rel_op=normalize_op({bif,'=:='}, [Bool,Lit])},
+ #b_br{bool=#b_literal{val=true},succ=L} =
+ shortcut(L0, bind_var(Bool, Lit, Bs), St#st{target=one_way}),
+ [{Lit,L}|shortcut_switch(T, Bool, Bs, St0)];
+shortcut_switch([], _, _, _) -> [].
+
+shortcut(L, Bs, St) ->
+ shortcut_1(L, Bs, ordsets:new(), St).
+
+shortcut_1(L, Bs0, UnsetVars0, St) ->
+ case shortcut_2(L, Bs0, UnsetVars0, St) of
+ none ->
+ %% No more shortcuts found. Package up the previous
+ %% label in an unconditional branch.
+ #b_br{bool=#b_literal{val=true},succ=L,fail=L};
+ {#b_br{bool=#b_var{}}=Br,_,_} ->
+ %% This is a two-way branch. We can't do any better.
+ Br;
+ {#b_br{bool=#b_literal{val=true},succ=Succ},Bs,UnsetVars} ->
+ %% This is a safe `br`, but try to find a better one.
+ shortcut_1(Succ, Bs#{from:=L}, UnsetVars, St)
+ end.
+
+%% Try to shortcut this block, branching to a successor.
+shortcut_2(L, Bs0, UnsetVars0, St) ->
+ #b_blk{is=Is,last=Last} = get_block(L, St),
+ case eval_is(Is, Bs0, St) of
+ none ->
+ %% It is not safe to avoid this block because it
+ %% has instructions with potential side effects.
+ none;
+ Bs ->
+ %% The instructions in the block (if any) don't
+ %% have any side effects and can be skipped.
+ %% Evaluate the terminator.
+ case eval_terminator(Last, Bs, St) of
+ none ->
+ %% The terminator is not suitable (could be
+ %% because it is a switch that can't be simplified
+ %% or it is a ret instruction).
+ none;
+ #b_br{}=Br ->
+ %% We have a potentially suitable br.
+ %% Now update the set of variables that will never
+ %% be set if this block will be skipped.
+ UnsetVars1 = [V || #b_set{dst=V} <- Is],
+ UnsetVars = ordsets:union(UnsetVars0,
+ ordsets:from_list(UnsetVars1)),
+
+ %% Continue checking whether this br is suitable.
+ shortcut_3(Br, Bs#{from:=L}, UnsetVars, St)
+ end
+ end.
+
+shortcut_3(Br, Bs, UnsetVars, #st{target=Target}=St) ->
+ case is_br_safe(UnsetVars, Br, St) of
+ false ->
+ %% Branching using this `br` is unsafe, either because it
+ %% is an unconditional branch to a phi node, or because
+ %% one or more of the variables that are not set will be
+ %% used. Try to follow branches of this `br`, to find a
+ %% safe `br`.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ case Target of
+ L ->
+ %% We have reached the forced target, and it
+ %% is unsafe. Give up.
+ none;
+ _ ->
+ %% Try following this branch to see whether it
+ %% leads to a safe `br`.
+ shortcut_2(L, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{},succ=Succ,fail=Fail} ->
+ case {Succ,Fail} of
+ {L,Target} ->
+ %% The failure label is the forced target.
+ %% Try following the success label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, Bs, UnsetVars, St);
+ {Target,L} ->
+ %% The success label is the forced target.
+ %% Try following the failure label to see
+ %% whether it also ultimately ends up at the
+ %% forced target.
+ shortcut_2(L, Bs, UnsetVars, St);
+ {_,_} ->
+ case Target of
+ any ->
+ %% This two-way branch is unsafe. Try reducing
+ %% it to a one-way branch.
+ shortcut_two_way(Br, Bs, UnsetVars, St);
+ one_way ->
+ %% This two-way branch is unsafe. Try reducing
+ %% it to a one-way branch.
+ shortcut_two_way(Br, Bs, UnsetVars, St);
+ _ when is_integer(Target) ->
+ %% This two-way branch is unsafe, and
+ %% there already is a forced target.
+ %% Give up.
+ none
+ end
+ end
+ end;
+ true ->
+ %% This `br` instruction is safe. It does not
+ %% branch to a phi node, and all variables that
+ %% will be used are guaranteed to be defined.
+ case Br of
+ #b_br{bool=#b_literal{val=true},succ=L} ->
+ %% This is a one-way branch.
+ case Target of
+ any ->
+ %% No forced target. Success!
+ {Br,Bs,UnsetVars};
+ one_way ->
+ %% The target must be a one-way branch, which this
+ %% `br` is. Success!
+ {Br,Bs,UnsetVars};
+ L when is_integer(Target) ->
+ %% The forced target is L. Success!
+ {Br,Bs,UnsetVars};
+ _ when is_integer(Target) ->
+ %% Wrong forced target. Try following this branch
+ %% to see if it ultimately ends up at the forced
+ %% target.
+ shortcut_2(L, Bs, UnsetVars, St)
+ end;
+ #b_br{bool=#b_var{}} ->
+ %% This is a two-way branch.
+ if
+ Target =:= any; Target =:= one_way ->
+ %% No specific forced target. Try to reduce the
+ %% two-way branch to an one-way branch.
+ case shortcut_two_way(Br, Bs, UnsetVars, St) of
+ none when Target =:= any ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. Return the `br` as-is.
+ {Br,Bs,UnsetVars};
+ none when Target =:= one_way ->
+ %% This `br` can't be reduced to a one-way
+ %% branch. The caller wants a one-way branch.
+ %% Give up.
+ none;
+ {_,_,_}=Res ->
+ %% This `br` was successfully reduced to a
+ %% one-way branch.
+ Res
+ end;
+ is_integer(Target) ->
+ %% There is a forced target, which can't
+ %% be reached because this `br` is a two-way
+ %% branch. Give up.
+ none
+ end
+ end
+ end.
+
+shortcut_two_way(#b_br{succ=Succ,fail=Fail}, Bs0, UnsetVars0, St) ->
+ case shortcut_2(Succ, Bs0, UnsetVars0, St#st{target=Fail}) of
+ {#b_br{bool=#b_literal{},succ=Fail},_,_}=Res ->
+ Res;
+ none ->
+ case shortcut_2(Fail, Bs0, UnsetVars0, St#st{target=Succ}) of
+ {#b_br{bool=#b_literal{},succ=Succ},_,_}=Res ->
+ Res;
+ none ->
+ none
+ end
+ end.
+
+get_block(L, St) ->
+ #st{bs=#{L:=Blk}} = St,
+ Blk.
+
+is_br_safe(UnsetVars, Br, #st{us=Us}=St) ->
+ %% Check that none of the unset variables will be used.
+ case Br of
+ #b_br{bool=#b_var{}=V,succ=Succ,fail=Fail} ->
+ #{Succ:=Used0,Fail:=Used1} = Us,
+
+ %% A two-way branch never branches to a phi node, so there
+ %% is no need to check for phi nodes here.
+ not member(V, UnsetVars) andalso
+ ordsets:is_disjoint(Used0, UnsetVars) andalso
+ ordsets:is_disjoint(Used1, UnsetVars);
+ #b_br{succ=Same,fail=Same} ->
+ %% An unconditional branch must not jump to
+ %% a phi node.
+ not is_forbidden(Same, St) andalso
+ ordsets:is_disjoint(map_get(Same, Us), UnsetVars)
+ end.
+
+is_forbidden(L, St) ->
+ case get_block(L, St) of
+ #b_blk{is=[#b_set{op=phi}|_]} -> true;
+ #b_blk{is=[#b_set{op=peek_message}|_]} -> true;
+ #b_blk{} -> false
+ end.
+
+
+%% Evaluate the instructions in the block.
+%% Return the updated bindings, or 'none' if there is
+%% any instruction with potential side effects.
+
+eval_is([#b_set{op=phi,dst=Dst,args=Args}|Is], Bs0, St) ->
+ From = maps:get(from, Bs0),
+ [Val] = [Val || {Val,Pred} <- Args, Pred =:= From],
+ Bs = bind_var(Dst, Val, Bs0),
+ eval_is(Is, Bs, St);
+eval_is([#b_set{op={bif,_},dst=Dst}=I0|Is], Bs, St) ->
+ I = sub(I0, Bs),
+ case eval_bif(I, St) of
+ #b_literal{}=Val ->
+ eval_is(Is, bind_var(Dst, Val, Bs), St);
+ none ->
+ eval_is(Is, Bs, St)
+ end;
+eval_is([#b_set{op=Op,dst=Dst}=I|Is], Bs, St)
+ when Op =:= is_tagged_tuple; Op =:= is_nonempty_list ->
+ #b_set{args=Args} = sub(I, Bs),
+ case eval_rel_op(Op, Args, St) of
+ #b_literal{}=Val ->
+ eval_is(Is, bind_var(Dst, Val, Bs), St);
+ none ->
+ eval_is(Is, Bs, St)
+ end;
+eval_is([#b_set{}=I|Is], Bs, St) ->
+ case beam_ssa:no_side_effect(I) of
+ true ->
+ %% This instruction has no side effects. It can
+ %% safely be omitted.
+ eval_is(Is, Bs, St);
+ false ->
+ %% This instruction may have some side effect.
+ %% It is not safe to avoid this instruction.
+ none
+ end;
+eval_is([], Bs, _St) -> Bs.
+
+eval_terminator(#b_br{bool=#b_var{}=Bool}=Br, Bs, _St) ->
+ Val = get_value(Bool, Bs),
+ beam_ssa:normalize(Br#b_br{bool=Val});
+eval_terminator(#b_br{bool=#b_literal{}}=Br, _Bs, _St) ->
+ beam_ssa:normalize(Br);
+eval_terminator(#b_switch{arg=Arg,fail=Fail,list=List}=Sw, Bs, St) ->
+ case get_value(Arg, Bs) of
+ #b_literal{}=Val ->
+ %% Literal argument. Simplify to a `br`.
+ beam_ssa:normalize(Sw#b_switch{arg=Val});
+ #b_var{} ->
+ case St of
+ #st{rel_op=none} ->
+ %% No previous relational operator is stored.
+ %% Give up.
+ none;
+ #st{} ->
+ %% There is a previous relational operator stored.
+ %% Try optimizing the switch.
+ case eval_switch(List, Arg, St, Fail) of
+ none ->
+ none;
+ To when is_integer(To) ->
+ %% Either one of the values in the switch
+ %% matched a previous value in a '=:=' test, or
+ %% none of the values matched a previous test.
+ #b_br{bool=#b_literal{val=true},succ=To,fail=To}
+ end
+ end
+ end;
+eval_terminator(#b_ret{}, _Bs, _St) ->
+ none.
+
+eval_switch([{Lit,Lbl}|T], Arg, St, Fail) ->
+ case eval_rel_op({bif,'=:='}, [Arg,Lit], St) of
+ none ->
+ %% This label could be reached.
+ eval_switch(T, Arg, St, none);
+ #b_literal{val=false} ->
+ %% This branch will never be taken.
+ eval_switch(T, Arg, St, Fail);
+ #b_literal{val=true} ->
+ %% Success. This branch will always be taken.
+ Lbl
+ end;
+eval_switch([], _Arg, _St, Fail) ->
+ %% Fail is now either the failure label or 'none'.
+ Fail.
+
+bind_var(Var, Val0, Bs) ->
+ Val = get_value(Val0, Bs),
+ Bs#{Var=>Val}.
+
+get_value(#b_var{}=Var, Bs) ->
+ case Bs of
+ #{Var:=Val} -> get_value(Val, Bs);
+ #{} -> Var
+ end;
+get_value(#b_literal{}=Lit, _Bs) -> Lit.
+
+eval_bif(#b_set{op={bif,Bif},args=Args}, St) ->
+ Arity = length(Args),
+ case erl_bifs:is_pure(erlang, Bif, Arity) of
+ false ->
+ none;
+ true ->
+ case [Lit || #b_literal{val=Lit} <- Args] of
+ LitArgs when length(LitArgs) =:= Arity ->
+ try apply(erlang, Bif, LitArgs) of
+ Val -> #b_literal{val=Val}
+ catch
+ error:_ -> none
+ end;
+ _ ->
+ %% Not literal arguments. Try to evaluate
+ %% it based on a previous relational operator.
+ eval_rel_op({bif,Bif}, Args, St)
+ end
+ end.
+
+%%%
+%%% Handling of relational operators.
+%%%
+
+get_rel_op(Bool, [_|_]=Is) ->
+ case last(Is) of
+ #b_set{op=Op,dst=Bool,args=Args} ->
+ normalize_op(Op, Args);
+ #b_set{} ->
+ none
+ end;
+get_rel_op(_, []) -> none.
+
+%% normalize_op(Instruction) -> {Normalized,FailLabel} | error
+%% Normalized = {Operator,Variable,Variable|Literal} |
+%% {TypeTest,Variable}
+%% Operation = '<' | '=<' | '=:=' | '=/=' | '>=' | '>'
+%% TypeTest = is_atom | is_integer ...
+%% Variable = #b_var{}
+%% Literal = #b_literal{}
+%%
+%% Normalize a relational operator to facilitate further
+%% comparisons between operators. Always make the register
+%% operand the first operand. If there are two registers,
+%% order the registers in lexical order.
+%%
+%% For example, this instruction:
+%%
+%% #b_set{op={bif,=<},args=[#b_literal{}, #b_var{}}
+%%
+%% will be normalized to:
+%%
+%% {'=<',#b_var{},#b_literal{}}
+
+-spec normalize_op(Op, Args) -> NormalizedOp | 'none' when
+ Op :: beam_ssa:op(),
+ Args :: [beam_ssa:value()],
+ NormalizedOp :: basic_rel_op().
+
+normalize_op(is_tagged_tuple, [Arg,#b_literal{val=Size},#b_literal{val=Tag}])
+ when is_integer(Size), is_atom(Tag) ->
+ {{is_tagged_tuple,Size,Tag},Arg};
+normalize_op(is_nonempty_list, [Arg]) ->
+ {is_nonempty_list,Arg};
+normalize_op({bif,Bif}, [Arg]) ->
+ case erl_internal:new_type_test(Bif, 1) of
+ true -> {Bif,Arg};
+ false -> none
+ end;
+normalize_op({bif,Bif}, [_,_]=Args) ->
+ case erl_internal:comp_op(Bif, 2) of
+ true ->
+ normalize_op_1(Bif, Args);
+ false ->
+ none
+ end;
+normalize_op(_, _) -> none.
+
+normalize_op_1(Bif, Args) ->
+ case Args of
+ [#b_literal{}=Arg1,#b_var{}=Arg2] ->
+ {turn_op(Bif),Arg2,Arg1};
+ [#b_var{}=Arg1,#b_literal{}=Arg2] ->
+ {Bif,Arg1,Arg2};
+ [#b_var{}=A,#b_var{}=B] ->
+ if A < B -> {Bif,A,B};
+ true -> {turn_op(Bif),B,A}
+ end;
+ [#b_literal{},#b_literal{}] ->
+ none
+ end.
+
+-spec invert_op(basic_rel_op() | 'none') -> rel_op() | 'none'.
+
+invert_op({Op,Arg1,Arg2}) ->
+ {invert_op_1(Op),Arg1,Arg2};
+invert_op({TypeTest,Arg}) ->
+ {{'not',TypeTest},Arg};
+invert_op(none) -> none.
+
+invert_op_1('>=') -> '<';
+invert_op_1('<') -> '>=';
+invert_op_1('=<') -> '>';
+invert_op_1('>') -> '=<';
+invert_op_1('=:=') -> '=/=';
+invert_op_1('=/=') -> '=:=';
+invert_op_1('==') -> '/=';
+invert_op_1('/=') -> '=='.
+
+turn_op('<') -> '>';
+turn_op('=<') -> '>=';
+turn_op('>') -> '<';
+turn_op('>=') -> '=<';
+turn_op('=:='=Op) -> Op;
+turn_op('=/='=Op) -> Op;
+turn_op('=='=Op) -> Op;
+turn_op('/='=Op) -> Op.
+
+eval_rel_op(_Bif, _Args, #st{rel_op=none}) ->
+ none;
+eval_rel_op(Bif, Args, #st{rel_op=Prev}) ->
+ case normalize_op(Bif, Args) of
+ none ->
+ none;
+ RelOp ->
+ case will_succeed(Prev, RelOp) of
+ yes -> #b_literal{val=true};
+ no -> #b_literal{val=false};
+ maybe -> none
+ end
+ end.
+
+%% will_succeed(PrevCondition, Condition) -> yes | no | maybe
+%% PrevCondition is a condition known to be true. This function
+%% will tell whether Condition will succeed.
+
+will_succeed({_Op,_Var,_Value}=Same, {_Op,_Var,_Value}=Same) ->
+ %% Repeated test.
+ yes;
+will_succeed({Op1,Var,#b_literal{val=A}}, {Op2,Var,#b_literal{val=B}}) ->
+ will_succeed_1(Op1, A, Op2, B);
+will_succeed({Op1,Var,#b_var{}=A}, {Op2,Var,#b_var{}=B}) ->
+ will_succeed_vars(Op1, A, Op2, B);
+will_succeed({'=:=',Var,#b_literal{val=A}}, {TypeTest,Var}) ->
+ eval_type_test(TypeTest, A);
+will_succeed({_,_}=Same, {_,_}=Same) ->
+ %% Repeated type test.
+ yes;
+will_succeed({Test1,Var}, {Test2,Var}) ->
+ will_succeed_test(Test1, Test2);
+will_succeed({_,_}, {_,_}) ->
+ maybe;
+will_succeed({_,_}, {_,_,_}) ->
+ maybe;
+will_succeed({_,_,_}, {_,_}) ->
+ maybe;
+will_succeed({_,_,_}, {_,_,_}) ->
+ maybe.
+
+will_succeed_test({'not',Test1}, Test2) ->
+ case Test1 =:= Test2 of
+ true -> no;
+ false -> maybe
+ end;
+will_succeed_test(is_tuple, {is_tagged_tuple,_,_}) ->
+ maybe;
+will_succeed_test({is_tagged_tuple,_,_}, is_tuple) ->
+ yes;
+will_succeed_test(is_list, is_nonempty_list) ->
+ maybe;
+will_succeed_test(is_nonempty_list, is_list) ->
+ yes;
+will_succeed_test(T1, T2) ->
+ case is_numeric_test(T1) andalso is_numeric_test(T2) of
+ true -> maybe;
+ false -> no
+ end.
+
+will_succeed_1('=:=', A, '<', B) ->
+ if
+ B =< A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '=<', B) ->
+ if
+ B < A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '=:=', B) when A =/= B ->
+ no;
+will_succeed_1('=:=', A, '=/=', B) ->
+ if
+ A =:= B -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '>=', B) ->
+ if
+ B > A -> no;
+ true -> yes
+ end;
+will_succeed_1('=:=', A, '>', B) ->
+ if
+ B >= A -> no;
+ true -> yes
+ end;
+
+will_succeed_1('=/=', A, '=:=', B) when A =:= B -> no;
+
+will_succeed_1('<', A, '=:=', B) when B >= A -> no;
+will_succeed_1('<', A, '=/=', B) when B >= A -> yes;
+will_succeed_1('<', A, '<', B) when B >= A -> yes;
+will_succeed_1('<', A, '=<', B) when B > A -> yes;
+will_succeed_1('<', A, '>=', B) when B > A -> no;
+will_succeed_1('<', A, '>', B) when B >= A -> no;
+
+will_succeed_1('=<', A, '=:=', B) when B > A -> no;
+will_succeed_1('=<', A, '=/=', B) when B > A -> yes;
+will_succeed_1('=<', A, '<', B) when B > A -> yes;
+will_succeed_1('=<', A, '=<', B) when B >= A -> yes;
+will_succeed_1('=<', A, '>=', B) when B > A -> no;
+will_succeed_1('=<', A, '>', B) when B >= A -> no;
+
+will_succeed_1('>=', A, '=:=', B) when B < A -> no;
+will_succeed_1('>=', A, '=/=', B) when B < A -> yes;
+will_succeed_1('>=', A, '<', B) when B =< A -> no;
+will_succeed_1('>=', A, '=<', B) when B < A -> no;
+will_succeed_1('>=', A, '>=', B) when B =< A -> yes;
+will_succeed_1('>=', A, '>', B) when B < A -> yes;
+
+will_succeed_1('>', A, '=:=', B) when B =< A -> no;
+will_succeed_1('>', A, '=/=', B) when B =< A -> yes;
+will_succeed_1('>', A, '<', B) when B =< A -> no;
+will_succeed_1('>', A, '=<', B) when B < A -> no;
+will_succeed_1('>', A, '>=', B) when B =< A -> yes;
+will_succeed_1('>', A, '>', B) when B < A -> yes;
+
+will_succeed_1('==', A, '==', B) ->
+ if
+ A == B -> yes;
+ true -> no
+ end;
+will_succeed_1('==', A, '/=', B) ->
+ if
+ A == B -> no;
+ true -> yes
+ end;
+will_succeed_1('/=', A, '/=', B) when A == B -> yes;
+will_succeed_1('/=', A, '==', B) when A == B -> no;
+
+will_succeed_1(_, _, _, _) -> maybe.
+
+will_succeed_vars('=/=', Val, '=:=', Val) -> no;
+will_succeed_vars('=:=', Val, '=/=', Val) -> no;
+will_succeed_vars('=:=', Val, '>=', Val) -> yes;
+will_succeed_vars('=:=', Val, '=<', Val) -> yes;
+
+will_succeed_vars('/=', Val1, '==', Val2) when Val1 == Val2 -> no;
+will_succeed_vars('==', Val1, '/=', Val2) when Val1 == Val2 -> no;
+
+will_succeed_vars(_, _, _, _) -> maybe.
+
+is_numeric_test(is_float) -> true;
+is_numeric_test(is_integer) -> true;
+is_numeric_test(is_number) -> true;
+is_numeric_test(_) -> false.
+
+eval_type_test(Test, Arg) ->
+ case eval_type_test_1(Test, Arg) of
+ true -> yes;
+ false -> no
+ end.
+
+eval_type_test_1(is_nonempty_list, Arg) ->
+ case Arg of
+ [_|_] -> true;
+ _ -> false
+ end;
+eval_type_test_1({is_tagged_tuple,Sz,Tag}, Arg) ->
+ if
+ tuple_size(Arg) =:= Sz, element(1, Arg) =:= Tag ->
+ true;
+ true ->
+ false
+ end;
+eval_type_test_1(Test, Arg) ->
+ erlang:Test(Arg).
+
+%%%
+%%% Combine bif:'=:=' and switch instructions
+%%% to switch instructions.
+%%%
+%%% Consider this code:
+%%%
+%%% 0:
+%%% @ssa_bool = bif:'=:=' Var, literal 1
+%%% br @ssa_bool, label 2, label 3
+%%%
+%%% 2:
+%%% ret literal a
+%%%
+%%% 3:
+%%% @ssa_bool:7 = bif:'=:=' Var, literal 2
+%%% br @ssa_bool:7, label 4, label 999
+%%%
+%%% 4:
+%%% ret literal b
+%%%
+%%% 999:
+%%% .
+%%% .
+%%% .
+%%%
+%%% The two bif:'=:=' instructions can be combined
+%%% to a switch:
+%%%
+%%% 0:
+%%% switch Var, label 999, [ { literal 1, label 2 },
+%%% { literal 2, label 3 } ]
+%%%
+%%% 2:
+%%% ret literal a
+%%%
+%%% 4:
+%%% ret literal b
+%%%
+%%% 999:
+%%% .
+%%% .
+%%% .
+%%%
+
+combine_eqs(#st{bs=Blocks}=St) ->
+ Ls = reverse(beam_ssa:rpo(Blocks)),
+ combine_eqs_1(Ls, St).
+
+combine_eqs_1([L|Ls], #st{bs=Blocks0}=St0) ->
+ case comb_get_sw(L, St0) of
+ none ->
+ combine_eqs_1(Ls, St0);
+ {_,Arg,_,Fail0,List0} ->
+ case comb_get_sw(Fail0, St0) of
+ {true,Arg,Fail1,Fail,List1} ->
+ %% Another switch/br with the same arguments was
+ %% found. Try combining them.
+ case combine_lists(Fail1, List0, List1, Blocks0) of
+ none ->
+ %% Different types of literals in the lists,
+ %% or the success cases in the first switch
+ %% could branch to the second switch
+ %% (increasing code size and repeating tests).
+ combine_eqs_1(Ls, St0);
+ List ->
+ %% Everything OK! Combine the lists.
+ Sw0 = #b_switch{arg=Arg,fail=Fail,list=List},
+ Sw = beam_ssa:normalize(Sw0),
+ Blk0 = maps:get(L, Blocks0),
+ Blk = Blk0#b_blk{last=Sw},
+ Blocks = Blocks0#{L:=Blk},
+ St = St0#st{bs=Blocks},
+ combine_eqs_1(Ls, St)
+ end;
+ {true,_OtherArg,_,_,_} ->
+ %% The other switch/br uses a different Arg.
+ combine_eqs_1(Ls, St0);
+ {false,_,_,_,_} ->
+ %% Not safe: Bindings of variables that will be used
+ %% or execution of instructions with potential
+ %% side effects will be skipped.
+ combine_eqs_1(Ls, St0);
+ none ->
+ %% No switch/br at this label.
+ combine_eqs_1(Ls, St0)
+ end
+ end;
+combine_eqs_1([], St) -> St.
+
+comb_get_sw(L, Blocks) ->
+ comb_get_sw(L, true, Blocks).
+
+comb_get_sw(L, Safe0, #st{bs=Blocks,skippable=Skippable}=St) ->
+ #b_blk{is=Is,last=Last} = maps:get(L, Blocks),
+ Safe1 = Safe0 andalso is_map_key(L, Skippable),
+ case Last of
+ #b_ret{} ->
+ none;
+ #b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail} ->
+ case comb_is(Is, Bool, Safe1) of
+ {none,_} ->
+ none;
+ {#b_set{op={bif,'=:='},args=[#b_var{}=Arg,#b_literal{}=Lit]},Safe} ->
+ {Safe,Arg,L,Fail,[{Lit,Succ}]};
+ {#b_set{},_} ->
+ none
+ end;
+ #b_br{bool=#b_literal{val=true},succ=Succ} ->
+ comb_get_sw(Succ, Safe1, St);
+ #b_switch{arg=#b_var{}=Arg,fail=Fail,list=List} ->
+ {none,Safe} = comb_is(Is, none, Safe1),
+ {Safe,Arg,L,Fail,List}
+ end.
+
+comb_is([#b_set{dst=#b_var{}=Bool}=I], Bool, Safe) ->
+ {I,Safe};
+comb_is([#b_set{}=I|Is], Bool, Safe0) ->
+ Safe = Safe0 andalso beam_ssa:no_side_effect(I),
+ comb_is(Is, Bool, Safe);
+comb_is([], _Bool, Safe) ->
+ {none,Safe}.
+
+%% combine_list(Fail, List1, List2, Blocks) -> List|none.
+%% Try to combine two switch lists, returning the combined
+%% list or 'none' if not possible.
+%%
+%% The values in the two lists must be all of the same type.
+%%
+%% The code reached from the labels in the first list must
+%% not reach the failure label (if they do, tests could
+%% be repeated).
+%%
+
+combine_lists(Fail, L1, L2, Blocks) ->
+ Ls = beam_ssa:rpo([Lbl || {_,Lbl} <- L1], Blocks),
+ case member(Fail, Ls) of
+ true ->
+ %% One or more of labels in the first list
+ %% could reach the failure label. That
+ %% means that the second switch/br instruction
+ %% will be retained, increasing code size and
+ %% potentially also execution time.
+ none;
+ false ->
+ %% The combined switch will replace both original
+ %% br/switch instructions, leading to a reduction in code
+ %% size and potentially also in execution time.
+ combine_lists_1(L1, L2)
+ end.
+
+combine_lists_1(List0, List1) ->
+ case are_lists_compatible(List0, List1) of
+ true ->
+ First = maps:from_list(List0),
+ List0 ++ [{Val,Lbl} || {Val,Lbl} <- List1,
+ not is_map_key(Val, First)];
+ false ->
+ none
+ end.
+
+are_lists_compatible([{#b_literal{val=Val1},_}|_],
+ [{#b_literal{val=Val2},_}|_]) ->
+ case lit_type(Val1) of
+ none -> false;
+ Type -> Type =:= lit_type(Val2)
+ end.
+
+lit_type(Val) ->
+ if
+ is_atom(Val) -> atom;
+ is_float(Val) -> float;
+ is_integer(Val) -> integer;
+ true -> none
+ end.
+
+%%%
+%%% Calculate used variables for each block.
+%%%
+
+used_vars(Linear) ->
+ used_vars(reverse(Linear), #{}, #{}).
+
+used_vars([{L,#b_blk{is=Is}=Blk}|Bs], UsedVars0, Skip0) ->
+ %% Calculate the variables used by each block and its
+ %% successors. This information is used by
+ %% shortcut_opt/1.
+
+ Successors = beam_ssa:successors(Blk),
+ Used0 = used_vars_succ(Successors, L, UsedVars0),
+ Used = used_vars_blk(Blk, Used0),
+ UsedVars = used_vars_phis(Is, L, Used, UsedVars0),
+
+ %% combine_eqs/1 needs different variable usage
+ %% information than shortcut_opt/1. The Skip
+ %% map will have an entry for each block that
+ %% can be skipped (does not bind any variable used
+ %% in successor).
+
+ Defined0 = [Def || #b_set{dst=Def} <- Is],
+ Defined = ordsets:from_list(Defined0),
+ MaySkip = ordsets:is_disjoint(Defined, Used0),
+ case MaySkip of
+ true ->
+ Skip = Skip0#{L=>true},
+ used_vars(Bs, UsedVars, Skip);
+ false ->
+ used_vars(Bs, UsedVars, Skip0)
+ end;
+used_vars([], UsedVars, Skip) ->
+ {UsedVars,Skip}.
+
+used_vars_succ([S|Ss], L, UsedVars) ->
+ Live0 = used_vars_succ(Ss, L, UsedVars),
+ Key = {S,L},
+ case UsedVars of
+ #{Key:=Live} ->
+ ordsets:union(Live, Live0);
+ #{S:=Live} ->
+ ordsets:union(Live, Live0);
+ #{} ->
+ Live0
+ end;
+used_vars_succ([], _, _) ->
+ ordsets:new().
+
+used_vars_phis(Is, L, Live0, UsedVars0) ->
+ UsedVars = UsedVars0#{L=>Live0},
+ Phis = takewhile(fun(#b_set{op=Op}) -> Op =:= phi end, Is),
+ case Phis of
+ [] ->
+ UsedVars;
+ [_|_] ->
+ PhiArgs = append([Args || #b_set{args=Args} <- Phis]),
+ case [{P,V} || {#b_var{}=V,P} <- PhiArgs] of
+ [_|_]=PhiVars ->
+ PhiLive0 = rel2fam(PhiVars),
+ PhiLive = [{{L,P},ordsets:union(ordsets:from_list(Vs), Live0)} ||
+ {P,Vs} <- PhiLive0],
+ maps:merge(UsedVars, maps:from_list(PhiLive));
+ [] ->
+ %% There were only literals in the phi node(s).
+ UsedVars
+ end
+ end.
+
+used_vars_blk(#b_blk{is=Is,last=Last}, Used0) ->
+ Used = ordsets:union(Used0, beam_ssa:used(Last)),
+ used_vars_is(reverse(Is), Used).
+
+used_vars_is([#b_set{op=phi}|Is], Used) ->
+ used_vars_is(Is, Used);
+used_vars_is([#b_set{dst=Dst}=I|Is], Used0) ->
+ Used1 = ordsets:union(Used0, beam_ssa:used(I)),
+ Used = ordsets:del_element(Dst, Used1),
+ used_vars_is(Is, Used);
+used_vars_is([], Used) ->
+ Used.
+
+%%%
+%%% Common utilities.
+%%%
+
+sub(#b_set{args=Args}=I, Sub) ->
+ I#b_set{args=[sub_arg(A, Sub) || A <- Args]}.
+
+sub_arg(Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
diff --git a/lib/compiler/src/beam_ssa_funs.erl b/lib/compiler/src/beam_ssa_funs.erl
new file mode 100644
index 0000000000..38df50fd74
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_funs.erl
@@ -0,0 +1,149 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%%
+%%% If a fun is defined locally and only used for calls, it can be replaced
+%%% with direct calls to the relevant function. This greatly speeds up "named
+%%% functions" (which rely on make_fun to recreate themselves) and macros that
+%%% wrap their body in a fun.
+%%%
+
+-module(beam_ssa_funs).
+
+-export([module/2]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [foldl/3]).
+
+-spec module(Module, Options) -> Result when
+ Module :: beam_ssa:b_module(),
+ Options :: [compile:option()],
+ Result :: {ok, beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, _Opts) ->
+ Trampolines = foldl(fun find_trampolines/2, #{}, Fs0),
+ Fs = [lfo(F, Trampolines) || F <- Fs0],
+ {ok, Module#b_module{body=Fs}}.
+
+%% If a function does absolutely nothing beyond calling another function with
+%% the same arguments in the same order, we can shave off a call by short-
+%% circuiting it.
+find_trampolines(#b_function{args=Args,bs=Blocks}=F, Trampolines) ->
+ case maps:get(0, Blocks) of
+ #b_blk{is=[#b_set{op=call,
+ args=[#b_local{}=Actual | Args],
+ dst=Dst}],
+ last=#b_ret{arg=Dst}} ->
+ {_, Name, Arity} = beam_ssa:get_anno(func_info, F),
+ Trampoline = #b_local{name=#b_literal{val=Name},arity=Arity},
+ maps:put(Trampoline, Actual, Trampolines);
+ _ ->
+ Trampolines
+ end.
+
+lfo(#b_function{bs=Blocks0}=F, Trampolines) ->
+ Linear0 = beam_ssa:linearize(Blocks0),
+ Linear = lfo_optimize(Linear0, lfo_analyze(Linear0, #{}), Trampolines),
+ F#b_function{bs=maps:from_list(Linear)}.
+
+%% Gather a map of the locally defined funs that are only used for calls.
+lfo_analyze([{_L,#b_blk{is=Is,last=Last}}|Bs], LFuns0) ->
+ LFuns = lfo_analyze_last(Last, lfo_analyze_is(Is, LFuns0)),
+ lfo_analyze(Bs, LFuns);
+lfo_analyze([], LFuns) ->
+ LFuns.
+
+lfo_analyze_is([#b_set{op=make_fun,
+ dst=Dst,
+ args=[#b_local{} | FreeVars]}=Def | Is],
+ LFuns0) ->
+ LFuns = maps:put(Dst, Def, maps:without(FreeVars, LFuns0)),
+ lfo_analyze_is(Is, LFuns);
+lfo_analyze_is([#b_set{op=call,
+ args=[Fun | CallArgs]} | Is],
+ LFuns) when is_map_key(Fun, LFuns) ->
+ #b_set{args=[#b_local{arity=Arity} | FreeVars]} = maps:get(Fun, LFuns),
+ case length(CallArgs) + length(FreeVars) of
+ Arity ->
+ lfo_analyze_is(Is, maps:without(CallArgs, LFuns));
+ _ ->
+ %% This will `badarity` at runtime, and it's easier to disable the
+ %% optimization than to simulate it.
+ lfo_analyze_is(Is, maps:without([Fun | CallArgs], LFuns))
+ end;
+lfo_analyze_is([#b_set{args=Args} | Is], LFuns) when map_size(LFuns) =/= 0 ->
+ %% We disqualify funs that are used outside calls because this forces them
+ %% to be created anyway, and the slight performance gain from direct calls
+ %% is not enough to offset the potential increase in stack frame size (the
+ %% free variables need to be kept alive until the call).
+ %%
+ %% This is also a kludge to make HiPE work, as the latter will generate
+ %% code with the assumption that the functions referenced in a make_fun
+ %% will only be used by funs, which will not be the case if we mix it with
+ %% direct calls. See cerl_cconv.erl for details.
+ %%
+ %% Future optimizations like delaying fun creation until use may require us
+ %% to copy affected functions so that HiPE gets its own to play with (until
+ %% HiPE is fixed anyway).
+ lfo_analyze_is(Is, maps:without(Args, LFuns));
+lfo_analyze_is([_ | Is], LFuns) ->
+ lfo_analyze_is(Is, LFuns);
+lfo_analyze_is([], LFuns) ->
+ LFuns.
+
+lfo_analyze_last(#b_switch{arg=Arg}, LFuns) ->
+ maps:remove(Arg, LFuns);
+lfo_analyze_last(#b_ret{arg=Arg}, LFuns) ->
+ maps:remove(Arg, LFuns);
+lfo_analyze_last(_, LFuns) ->
+ LFuns.
+
+%% Replace all calls of suitable funs with a direct call to their
+%% implementation. Liveness optimization will get rid of the make_fun
+%% instruction.
+lfo_optimize(Linear, LFuns, _Trampolines) when map_size(LFuns) =:= 0 ->
+ Linear;
+lfo_optimize(Linear, LFuns, Trampolines) ->
+ lfo_optimize_1(Linear, LFuns, Trampolines).
+
+lfo_optimize_1([{L,#b_blk{is=Is0}=Blk}|Bs], LFuns, Trampolines) ->
+ Is = lfo_optimize_is(Is0, LFuns, Trampolines),
+ [{L,Blk#b_blk{is=Is}} | lfo_optimize_1(Bs, LFuns, Trampolines)];
+lfo_optimize_1([], _LFuns, _Trampolines) ->
+ [].
+
+lfo_optimize_is([#b_set{op=call,
+ args=[Fun | CallArgs]}=Call0 | Is],
+ LFuns, Trampolines) when is_map_key(Fun, LFuns) ->
+ #b_set{args=[Local | FreeVars]} = maps:get(Fun, LFuns),
+ Args = [lfo_short_circuit(Local, Trampolines) | CallArgs ++ FreeVars],
+ Call = beam_ssa:add_anno(local_fun_opt, Fun, Call0#b_set{args=Args}),
+ [Call | lfo_optimize_is(Is, LFuns, Trampolines)];
+lfo_optimize_is([I | Is], LFuns, Trampolines) ->
+ [I | lfo_optimize_is(Is, LFuns, Trampolines)];
+lfo_optimize_is([], _LFuns, _Trampolines) ->
+ [].
+
+lfo_short_circuit(Call, Trampolines) ->
+ case maps:find(Call, Trampolines) of
+ {ok, Other} -> lfo_short_circuit(Other, Trampolines);
+ error -> Call
+ end.
diff --git a/lib/compiler/src/beam_ssa_lint.erl b/lib/compiler/src/beam_ssa_lint.erl
new file mode 100644
index 0000000000..a003607dab
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_lint.erl
@@ -0,0 +1,349 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Internal consistency checks for the beam_ssa format.
+
+-module(beam_ssa_lint).
+
+-export([module/2, format_error/1]).
+
+-import(lists, [append/1, foldl/3, foreach/2]).
+
+-include("beam_ssa.hrl").
+
+-spec module(#b_module{}, [compile:option()]) ->
+ {'ok',#b_module{}} | {'error',list()}.
+module(#b_module{body=Fs,name=Name}=Mod0, _Options) ->
+ Es0 = append([validate_function(F) || F <- Fs]),
+ case [{?MODULE,E} || E <- Es0] of
+ [] ->
+ {ok, Mod0};
+ [_|_]=Es ->
+ {error,[{atom_to_list(Name), Es}]}
+ end.
+
+-spec format_error(term()) -> iolist().
+format_error({{_M,F,A},{redefined_variable, Name, Old, I}}) ->
+ io_lib:format("~p/~p: Variable ~ts (~ts) redefined by ~ts",
+ [F, A, format_var(Name), format_instr(Old), format_instr(I)]);
+format_error({{_M,F,A},{missing_phi_paths, Paths, I}}) ->
+ io_lib:format("~p/~p: Phi node ~ts doesn't define a value for these "
+ "branches: ~w",
+ [F, A, format_instr(I), Paths]);
+format_error({{_M,F,A},{garbage_phi_paths, Paths, I}}) ->
+ io_lib:format("~p/~p: Phi node ~ts defines a value for these unreachable "
+ "or non-existent branches: ~w",
+ [F, A, format_instr(I), Paths]);
+format_error({{_M,F,A},{unknown_phi_variable, Name, {From, _To}, I}}) ->
+ io_lib:format("~p/~p: Variable ~ts used in phi node ~ts is undefined on "
+ "branch ~w",
+ [F, A, format_var(Name), format_instr(I), From]);
+format_error({{_M,F,A},{unknown_block, Label, I}}) ->
+ io_lib:format("~p/~p: Unknown block ~p referenced in ~ts",
+ [F, A, Label, I]);
+format_error({{_M,F,A},{unknown_variable, Name, I}}) ->
+ io_lib:format("~p/~p: Unbound variable ~ts used in ~ts",
+ [F, A, format_var(Name), format_instr(I)]);
+format_error({{_M,F,A},{phi_inside_block, Name, Id}}) ->
+ io_lib:format("~p/~p: Phi node defining ~ts is not at start of block ~p",
+ [F, A, format_var(Name), Id]);
+format_error({{_M,F,A},{undefined_label_in_phi, Label, I}}) ->
+ io_lib:format("~p/~p: Unknown block label ~p in phi node ~ts",
+ [F, A, Label, format_instr(I)]).
+
+format_instr(I) ->
+ [$',beam_ssa_pp:format_instr(I),$'].
+
+format_var(V) ->
+ beam_ssa_pp:format_var(#b_var{name=V}).
+
+validate_function(F) ->
+ try
+ validate_variables(F),
+ []
+ catch
+ throw:Reason ->
+ #{func_info:=MFA} = F#b_function.anno,
+ [{MFA,Reason}];
+ Class:Error:Stack ->
+ io:fwrite("Function: ~p\n", [F#b_function.anno]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+-type defined_vars() :: gb_sets:set(beam_ssa:var_name()).
+
+-record(vvars,
+ {blocks :: #{ beam_ssa:label() => beam_ssa:b_blk() },
+ branch_def_vars :: #{
+ %% Describes the variable state at the time of this exact branch (phi
+ %% node validation).
+ {From :: beam_ssa:label(), To :: beam_ssa:label()} => defined_vars(),
+ %% Describes the variable state common to all branches leading to this
+ %% label (un/redefined variable validation).
+ beam_ssa:label() => defined_vars() },
+ defined_vars :: defined_vars()}).
+
+-spec validate_variables(beam_ssa:b_function()) -> ok.
+validate_variables(#b_function{ args = Args, bs = Blocks }) ->
+ %% Prefill the mapping with function arguments.
+ ArgNames = vvars_get_varnames(Args),
+ DefVars = gb_sets:from_list(ArgNames),
+ Entry = 0,
+
+ State = #vvars{blocks = Blocks,
+ branch_def_vars = #{ Entry => DefVars },
+ defined_vars = DefVars},
+ ok = vvars_assert_unique(Blocks, ArgNames),
+ vvars_phi_nodes(vvars_block(Entry, State)).
+
+%% Checks the uniqueness of all variables across all blocks.
+-spec vvars_assert_unique(Blocks, [beam_ssa:var_name()]) -> ok when
+ Blocks :: #{ beam_ssa:label() => beam_ssa:b_blk() }.
+vvars_assert_unique(Blocks, Args) ->
+ BlockIs = [Is || #b_blk{is=Is} <- maps:values(Blocks)],
+ Defined0 = maps:from_list([{V,argument} || V <- Args]),
+ _ = foldl(fun(Is, Defined) ->
+ vvars_assert_unique_1(Is, Defined)
+ end, Defined0, BlockIs),
+ ok.
+
+-spec vvars_assert_unique_1(Is, Defined) -> ok when
+ Is :: list(beam_ssa:b_set()),
+ Defined :: #{ beam_ssa:var_name() => beam_ssa:b_set() }.
+vvars_assert_unique_1([#b_set{dst=#b_var{name=DstName}}=I|Is], Defined) ->
+ case Defined of
+ #{DstName:=Old} -> throw({redefined_variable, DstName, Old, I});
+ _ -> vvars_assert_unique_1(Is, Defined#{DstName=>I})
+ end;
+vvars_assert_unique_1([], Defined) ->
+ Defined.
+
+-spec vvars_phi_nodes(State :: #vvars{}) -> ok.
+vvars_phi_nodes(#vvars{ blocks = Blocks }=State) ->
+ _ = [vvars_phi_nodes_1(Is, Id, State) ||
+ {Id, #b_blk{ is = Is }} <- maps:to_list(Blocks)],
+ ok.
+
+-spec vvars_phi_nodes_1(Is, Id, State) -> ok when
+ Is :: list(beam_ssa:b_set()),
+ Id :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_phi_nodes_1([#b_set{ op = phi, args = Phis }=I | Is], Id, State) ->
+ ok = vvars_assert_phi_paths(Phis, I, Id, State),
+ ok = vvars_assert_phi_vars(Phis, I, Id, State),
+ vvars_phi_nodes_1(Is, Id, State);
+vvars_phi_nodes_1([_ | Is], Id, _State) ->
+ case [Dst || #b_set{op=phi,dst=#b_var{name=Dst}} <- Is] of
+ [Name|_] ->
+ throw({phi_inside_block, Name, Id});
+ [] ->
+ ok
+ end;
+vvars_phi_nodes_1([], _Id, _State) ->
+ ok.
+
+%% Checks whether all paths leading to this phi node are represented, and that
+%% it doesn't reference any non-existent paths.
+-spec vvars_assert_phi_paths(Phis, I, Id, State) -> ok when
+ Phis :: list({beam_ssa:argument(), beam_ssa:label()}),
+ Id :: beam_ssa:label(),
+ I :: beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_phi_paths(Phis, I, Id, State) ->
+ BranchKeys = maps:keys(State#vvars.branch_def_vars),
+ RequiredPaths = ordsets:from_list([From || {From, To} <- BranchKeys, To =:= Id]),
+ ProvidedPaths = ordsets:from_list([From || {_Value, From} <- Phis]),
+ case ordsets:subtract(RequiredPaths, ProvidedPaths) of
+ [_|_]=MissingPaths -> throw({missing_phi_paths, MissingPaths, I});
+ [] -> ok
+ end.
+ %% %% The following test is sometimes useful to find missing optimizations.
+ %% %% It is commented out, though, because it can be triggered by
+ %% %% by weird but legal code.
+ %% case ordsets:subtract(ProvidedPaths, RequiredPaths) of
+ %% [_|_]=GarbagePaths -> throw({garbage_phi_paths, GarbagePaths, I});
+ %% [] -> ok
+ %% end.
+
+%% Checks whether all variables used in this phi node are defined in the branch
+%% they arrived on.
+-spec vvars_assert_phi_vars(Phis, I, Id, State) -> ok when
+ Phis :: list({beam_ssa:argument(), beam_ssa:label()}),
+ Id :: beam_ssa:label(),
+ I :: beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_phi_vars(Phis, I, Id, #vvars{blocks=Blocks,
+ branch_def_vars=BranchDefVars}) ->
+ Vars = [{Var, From} || {#b_var{}=Var, From} <- Phis],
+ foreach(fun({#b_var{name=VarName}, From}) ->
+ BranchKey = {From, Id},
+ case BranchDefVars of
+ #{BranchKey:=DefVars} ->
+ case gb_sets:is_member(VarName, DefVars) of
+ true -> ok;
+ false -> throw({unknown_variable, VarName, I})
+ end;
+ #{} ->
+ throw({unknown_phi_variable, VarName, BranchKey, I})
+ end
+ end, Vars),
+ Labels = [From || {#b_literal{},From} <- Phis],
+ foreach(fun(Label) ->
+ case Blocks of
+ #{Label:=_} ->
+ ok;
+ #{} ->
+ throw({undefined_label_in_phi, Label, I})
+ end
+ end, Labels).
+
+-spec vvars_block(Id, State) -> #vvars{} when
+ Id :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_block(Id, State0) ->
+ #{ Id := #b_blk{ is = Is, last = Terminator} } = State0#vvars.blocks,
+ #{ Id := DefVars } = State0#vvars.branch_def_vars,
+ State = State0#vvars{ defined_vars = DefVars },
+ vvars_terminator(Terminator, Id, vvars_block_1(Is, State)).
+
+-spec vvars_block_1(Blocks, State) -> #vvars{} when
+ Blocks :: list(beam_ssa:b_blk()),
+ State :: #vvars{}.
+vvars_block_1([], State) ->
+ State;
+vvars_block_1([#b_set{ dst = #b_var{ name = DstName }, op = phi } | Is], State0) ->
+ %% We don't check phi node arguments at this point since we may not have
+ %% visited their definition yet. They'll be handled later on in
+ %% vvars_phi_nodes/1 after all blocks are processed.
+ vvars_block_1(Is, vvars_save_var(DstName, State0));
+vvars_block_1([#b_set{ dst = #b_var{ name = DstName }, args = Args }=I | Is], State0) ->
+ ok = vvars_assert_args(Args, I, State0),
+ vvars_block_1(Is, vvars_save_var(DstName, State0)).
+
+-spec vvars_terminator(Terminator, From, State) -> #vvars{} when
+ Terminator :: beam_ssa:terminator(),
+ From :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_terminator(#b_ret{ arg = Arg }=I, _From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ State;
+vvars_terminator(#b_switch{arg=Arg,fail=Fail,list=Switch}=I, From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ ok = vvars_assert_args([A || {A,_Lbl} <- Switch], I, State),
+ Labels = [Fail | [Lbl || {_Arg, Lbl} <- Switch]],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{bool=#b_literal{val=true},succ=Succ}=I, From, State) ->
+ Labels = [Succ],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{bool=#b_literal{val=false},fail=Fail}=I, From, State) ->
+ Labels = [Fail],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State);
+vvars_terminator(#b_br{ bool = Arg, succ = Succ, fail = Fail }=I, From, State) ->
+ ok = vvars_assert_args([Arg], I, State),
+ Labels = [Fail, Succ],
+ ok = vvars_assert_labels(Labels, I, State),
+ vvars_terminator_1(Labels, From, State).
+
+-spec vvars_terminator_1(Labels, From, State) -> #vvars{} when
+ Labels :: list(beam_ssa:label()),
+ From :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_terminator_1(Labels0, From, State0) ->
+ %% Filter out all branches that have already been taken. This should result
+ %% in either all of Labels0 or an empty list.
+ Labels = [To || To <- Labels0,
+ not maps:is_key({From, To}, State0#vvars.branch_def_vars)],
+ true = Labels =:= Labels0 orelse Labels =:= [], %Assertion
+ State1 = foldl(fun(To, State) ->
+ vvars_save_branch(From, To, State)
+ end, State0, Labels),
+ foldl(fun(To, State) ->
+ vvars_block(To, State)
+ end, State1, Labels).
+
+%% Gets all variable names in args, ignoring literals etc
+-spec vvars_get_varnames(Args) -> list(beam_ssa:var_name()) when
+ Args :: list(beam_ssa:argument()).
+vvars_get_varnames(Args) ->
+ [Name || #b_var{ name = Name } <- Args].
+
+%% Checks that all variables in Args are defined in all paths leading to the
+%% current State.
+-spec vvars_assert_args(Args, I, State) -> ok when
+ Args :: list(beam_ssa:argument()),
+ I :: beam_ssa:terminator() | beam_ssa:b_set(),
+ State :: #vvars{}.
+vvars_assert_args(Args, I, #vvars{defined_vars=DefVars}=State) ->
+ foreach(fun(#b_remote{mod=Mod,name=Name}) ->
+ vvars_assert_args([Mod,Name], I, State);
+ (#b_var{name=Name}) ->
+ case gb_sets:is_member(Name, DefVars) of
+ true -> ok;
+ false -> throw({unknown_variable,Name,I})
+ end;
+ (_) -> ok
+ end, Args).
+
+%% Checks that all given labels are defined in State.
+-spec vvars_assert_labels(Labels, I, State) -> ok when
+ Labels :: list(beam_ssa:label()),
+ I :: beam_ssa:terminator(),
+ State :: #vvars{}.
+vvars_assert_labels(Labels, I, #vvars{blocks=Blocks}) ->
+ foreach(fun(Label) ->
+ case maps:is_key(Label, Blocks) of
+ false -> throw({unknown_block, Label, I});
+ true -> ok
+ end
+ end, Labels).
+
+-spec vvars_save_branch(From, To, State) -> #vvars{} when
+ From :: beam_ssa:label(),
+ To :: beam_ssa:label(),
+ State :: #vvars{}.
+vvars_save_branch(From, To, State) ->
+ DefVars = State#vvars.defined_vars,
+ Branches0 = State#vvars.branch_def_vars,
+ case Branches0 of
+ #{ To := LblDefVars } ->
+ MergedVars = vvars_merge_branches(DefVars, LblDefVars),
+
+ Branches = Branches0#{ To => MergedVars, {From, To} => DefVars },
+ State#vvars { branch_def_vars = Branches };
+ _ ->
+ Branches = Branches0#{ To => DefVars, {From, To} => DefVars },
+ State#vvars { branch_def_vars = Branches }
+ end.
+
+-spec vvars_merge_branches(New, Existing) -> defined_vars() when
+ New :: defined_vars(),
+ Existing :: defined_vars().
+vvars_merge_branches(New, Existing) ->
+ gb_sets:intersection(New, Existing).
+
+-spec vvars_save_var(VarName, State) -> #vvars{} when
+ VarName :: beam_ssa:var_name(),
+ State :: #vvars{}.
+vvars_save_var(VarName, State0) ->
+ %% vvars_assert_unique guarantees that variables are never set twice.
+ DefVars = gb_sets:insert(VarName, State0#vvars.defined_vars),
+ State0#vvars{ defined_vars = DefVars }.
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
new file mode 100644
index 0000000000..ac2d943fef
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -0,0 +1,1765 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_ssa_opt).
+-export([module/2]).
+
+-include("beam_ssa.hrl").
+-import(lists, [all/2,append/1,foldl/3,keyfind/3,member/2,reverse/1,reverse/2,
+ splitwith/2,takewhile/2,unzip/1]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, Opts) ->
+ Ps = passes(Opts),
+ Fs = functions(Fs0, Ps),
+ {ok,Module#b_module{body=Fs}}.
+
+functions([F|Fs], Ps) ->
+ [function(F, Ps)|functions(Fs, Ps)];
+functions([], _Ps) -> [].
+
+-type b_blk() :: beam_ssa:b_blk().
+-type b_var() :: beam_ssa:b_var().
+-type label() :: beam_ssa:label().
+
+-record(st, {ssa :: beam_ssa:block_map() | [{label(),b_blk()}],
+ args :: [b_var()],
+ cnt :: label()}).
+-define(PASS(N), {N,fun N/1}).
+
+passes(Opts0) ->
+ Ps = [?PASS(ssa_opt_split_blocks),
+ ?PASS(ssa_opt_coalesce_phis),
+ ?PASS(ssa_opt_element),
+ ?PASS(ssa_opt_linearize),
+ ?PASS(ssa_opt_record),
+
+ %% Run ssa_opt_cse twice, because it will help ssa_opt_dead,
+ %% and ssa_opt_dead will help ssa_opt_cse. Run ssa_opt_live
+ %% twice, because it will help ssa_opt_dead and ssa_opt_dead
+ %% will help ssa_opt_live.
+ ?PASS(ssa_opt_cse),
+ ?PASS(ssa_opt_type),
+ ?PASS(ssa_opt_live),
+ ?PASS(ssa_opt_dead),
+ ?PASS(ssa_opt_cse), %Second time.
+ ?PASS(ssa_opt_float),
+ ?PASS(ssa_opt_live), %Second time.
+
+ ?PASS(ssa_opt_bsm),
+ ?PASS(ssa_opt_bsm_units),
+ ?PASS(ssa_opt_bsm_shortcut),
+ ?PASS(ssa_opt_misc),
+ ?PASS(ssa_opt_tuple_size),
+ ?PASS(ssa_opt_sw),
+ ?PASS(ssa_opt_blockify),
+ ?PASS(ssa_opt_sink),
+ ?PASS(ssa_opt_merge_blocks),
+ ?PASS(ssa_opt_trim_unreachable)],
+ Negations = [{list_to_atom("no_"++atom_to_list(N)),N} ||
+ {N,_} <- Ps],
+ Opts = proplists:substitute_negations(Negations, Opts0),
+ [case proplists:get_value(Name, Opts, true) of
+ true ->
+ P;
+ false ->
+ {NoName,Name} = keyfind(Name, 2, Negations),
+ {NoName,fun(S) -> S end}
+ end || {Name,_}=P <- Ps].
+
+function(#b_function{anno=Anno,bs=Blocks0,args=Args,cnt=Count0}=F, Ps) ->
+ try
+ St = #st{ssa=Blocks0,args=Args,cnt=Count0},
+ #st{ssa=Blocks,cnt=Count} = compile:run_sub_passes(Ps, St),
+ F#b_function{bs=Blocks,cnt=Count}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+%%%
+%%% Trivial sub passes.
+%%%
+
+ssa_opt_dead(#st{ssa=Linear}=St) ->
+ St#st{ssa=beam_ssa_dead:opt(Linear)}.
+
+ssa_opt_linearize(#st{ssa=Blocks}=St) ->
+ St#st{ssa=beam_ssa:linearize(Blocks)}.
+
+ssa_opt_type(#st{ssa=Linear,args=Args}=St) ->
+ St#st{ssa=beam_ssa_type:opt(Linear, Args)}.
+
+ssa_opt_blockify(#st{ssa=Linear}=St) ->
+ St#st{ssa=maps:from_list(Linear)}.
+
+ssa_opt_trim_unreachable(#st{ssa=Blocks}=St) ->
+ St#st{ssa=beam_ssa:trim_unreachable(Blocks)}.
+
+%%%
+%%% Split blocks before certain instructions to enable more optimizations.
+%%%
+%%% Splitting before element/2 enables the optimization that swaps
+%%% element/2 instructions.
+%%%
+%%% Splitting before call and make_fun instructions gives more opportunities
+%%% for sinking get_tuple_element instructions.
+%%%
+
+ssa_opt_split_blocks(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ P = fun(#b_set{op={bif,element}}) -> true;
+ (#b_set{op=call}) -> true;
+ (#b_set{op=make_fun}) -> true;
+ (_) -> false
+ end,
+ {Blocks,Count} = beam_ssa:split_blocks(P, Blocks0, Count0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+%%%
+%%% Coalesce phi nodes.
+%%%
+%%% Nested cases can led to code such as this:
+%%%
+%%% 10:
+%%% _1 = phi {literal value1, label 8}, {Var, label 9}
+%%% br 11
+%%%
+%%% 11:
+%%% _2 = phi {_1, label 10}, {literal false, label 3}
+%%%
+%%% The phi nodes can be coalesced like this:
+%%%
+%%% 11:
+%%% _2 = phi {literal value1, label 8}, {Var, label 9}, {literal false, label 3}
+%%%
+%%% Coalescing can help other optimizations, and can in some cases reduce register
+%%% shuffling (if the phi variables for two phi nodes happens to be allocated to
+%%% different registers).
+%%%
+
+ssa_opt_coalesce_phis(#st{ssa=Blocks0}=St) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ Blocks = c_phis_1(Ls, Blocks0),
+ St#st{ssa=Blocks}.
+
+c_phis_1([L|Ls], Blocks0) ->
+ case maps:get(L, Blocks0) of
+ #b_blk{is=[#b_set{op=phi}|_]}=Blk ->
+ Blocks = c_phis_2(L, Blk, Blocks0),
+ c_phis_1(Ls, Blocks);
+ #b_blk{} ->
+ c_phis_1(Ls, Blocks0)
+ end;
+c_phis_1([], Blocks) -> Blocks.
+
+c_phis_2(L, #b_blk{is=Is0}=Blk0, Blocks0) ->
+ case c_phis_args(Is0, Blocks0) of
+ none ->
+ Blocks0;
+ {_,_,Preds}=Info ->
+ Is = c_rewrite_phis(Is0, Info),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ c_fix_branches(Preds, L, Blocks)
+ end.
+
+c_phis_args([#b_set{op=phi,args=Args0}|Is], Blocks) ->
+ case c_phis_args_1(Args0, Blocks) of
+ none ->
+ c_phis_args(Is, Blocks);
+ Res ->
+ Res
+ end;
+c_phis_args(_, _Blocks) -> none.
+
+c_phis_args_1([{Var,Pred}|As], Blocks) ->
+ case c_get_pred_vars(Var, Pred, Blocks) of
+ none ->
+ c_phis_args_1(As, Blocks);
+ Result ->
+ Result
+ end;
+c_phis_args_1([], _Blocks) -> none.
+
+c_get_pred_vars(Var, Pred, Blocks) ->
+ case maps:get(Pred, Blocks) of
+ #b_blk{is=[#b_set{op=phi,dst=Var,args=Args}]} ->
+ {Var,Pred,Args};
+ #b_blk{} ->
+ none
+ end.
+
+c_rewrite_phis([#b_set{op=phi,args=Args0}=I|Is], Info) ->
+ Args = c_rewrite_phi(Args0, Info),
+ [I#b_set{args=Args}|c_rewrite_phis(Is, Info)];
+c_rewrite_phis(Is, _Info) -> Is.
+
+c_rewrite_phi([{Var,Pred}|As], {Var,Pred,Values}) ->
+ Values ++ As;
+c_rewrite_phi([{Value,Pred}|As], {_,Pred,Values}) ->
+ [{Value,P} || {_,P} <- Values] ++ As;
+c_rewrite_phi([A|As], Info) ->
+ [A|c_rewrite_phi(As, Info)];
+c_rewrite_phi([], _Info) -> [].
+
+c_fix_branches([{_,Pred}|As], L, Blocks0) ->
+ #b_blk{last=Last0} = Blk0 = maps:get(Pred, Blocks0),
+ #b_br{bool=#b_literal{val=true}} = Last0, %Assertion.
+ Last = Last0#b_br{bool=#b_literal{val=true},succ=L,fail=L},
+ Blk = Blk0#b_blk{last=Last},
+ Blocks = Blocks0#{Pred:=Blk},
+ c_fix_branches(As, L, Blocks);
+c_fix_branches([], _, Blocks) -> Blocks.
+
+%%%
+%%% Order element/2 calls.
+%%%
+%%% Order an unbroken chain of element/2 calls for the same tuple
+%%% with the same failure label so that the highest element is
+%%% retrieved first. That will allow the other element/2 calls to
+%%% be replaced with get_tuple_element/3 instructions.
+%%%
+
+ssa_opt_element(#st{ssa=Blocks}=St) ->
+ %% Collect the information about element instructions in this
+ %% function.
+ GetEls = collect_element_calls(beam_ssa:linearize(Blocks)),
+
+ %% Collect the element instructions into chains. The
+ %% element calls in each chain are ordered in reverse
+ %% execution order.
+ Chains = collect_chains(GetEls, []),
+
+ %% For each chain, swap the first element call with the
+ %% element call with the highest index.
+ St#st{ssa=swap_element_calls(Chains, Blocks)}.
+
+collect_element_calls([{L,#b_blk{is=Is0,last=Last}}|Bs]) ->
+ case {Is0,Last} of
+ {[#b_set{op={bif,element},dst=Element,
+ args=[#b_literal{val=N},#b_var{}=Tuple]},
+ #b_set{op=succeeded,dst=Bool,args=[Element]}],
+ #b_br{bool=Bool,succ=Succ,fail=Fail}} ->
+ Info = {L,Succ,{Tuple,Fail},N},
+ [Info|collect_element_calls(Bs)];
+ {_,_} ->
+ collect_element_calls(Bs)
+ end;
+collect_element_calls([]) -> [].
+
+collect_chains([{This,_,V,_}=El|Els], [{_,This,V,_}|_]=Chain) ->
+ %% Add to the previous chain.
+ collect_chains(Els, [El|Chain]);
+collect_chains([El|Els], [_,_|_]=Chain) ->
+ %% Save the previous chain and start a new chain.
+ [Chain|collect_chains(Els, [El])];
+collect_chains([El|Els], _Chain) ->
+ %% The previous chain is too short; discard it and start a new.
+ collect_chains(Els, [El]);
+collect_chains([], [_,_|_]=Chain) ->
+ %% Save the last chain.
+ [Chain];
+collect_chains([], _) -> [].
+
+swap_element_calls([[{L,_,_,N}|_]=Chain|Chains], Blocks0) ->
+ Blocks = swap_element_calls_1(Chain, {N,L}, Blocks0),
+ swap_element_calls(Chains, Blocks);
+swap_element_calls([], Blocks) -> Blocks.
+
+swap_element_calls_1([{L1,_,_,N1}], {N2,L2}, Blocks) when N2 > N1 ->
+ %% We have reached the end of the chain, and the first
+ %% element instrution to be executed. Its index is lower
+ %% than the maximum index found while traversing the chain,
+ %% so we will need to swap the instructions.
+ #{L1:=Blk1,L2:=Blk2} = Blocks,
+ [#b_set{dst=Dst1}=GetEl1,Succ1] = Blk1#b_blk.is,
+ [#b_set{dst=Dst2}=GetEl2,Succ2] = Blk2#b_blk.is,
+ Is1 = [GetEl2,Succ1#b_set{args=[Dst2]}],
+ Is2 = [GetEl1,Succ2#b_set{args=[Dst1]}],
+ Blocks#{L1:=Blk1#b_blk{is=Is1},L2:=Blk2#b_blk{is=Is2}};
+swap_element_calls_1([{L,_,_,N1}|Els], {N2,_}, Blocks) when N1 > N2 ->
+ swap_element_calls_1(Els, {N2,L}, Blocks);
+swap_element_calls_1([_|Els], Highest, Blocks) ->
+ swap_element_calls_1(Els, Highest, Blocks);
+swap_element_calls_1([], _, Blocks) ->
+ %% Nothing to do. The element call with highest index
+ %% is already the first one to be executed.
+ Blocks.
+
+%%%
+%%% Record optimization.
+%%%
+%%% Replace tuple matching with an is_tagged_tuple instruction
+%%% when applicable.
+%%%
+
+ssa_opt_record(#st{ssa=Linear}=St) ->
+ Blocks = maps:from_list(Linear),
+ St#st{ssa=record_opt(Linear, Blocks)}.
+
+record_opt([{L,#b_blk{is=Is0,last=Last}=Blk0}|Bs], Blocks) ->
+ Is = record_opt_is(Is0, Last, Blocks),
+ Blk = Blk0#b_blk{is=Is},
+ [{L,Blk}|record_opt(Bs, Blocks)];
+record_opt([], _Blocks) -> [].
+
+record_opt_is([#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}=Set],
+ Last, Blocks) ->
+ case is_tagged_tuple(Tuple, Bool, Last, Blocks) of
+ {yes,Size,Tag} ->
+ Args = [Tuple,Size,Tag],
+ [Set#b_set{op=is_tagged_tuple,args=Args}];
+ no ->
+ [Set]
+ end;
+record_opt_is([I|Is], Last, Blocks) ->
+ [I|record_opt_is(Is, Last, Blocks)];
+record_opt_is([], _Last, _Blocks) -> [].
+
+is_tagged_tuple(#b_var{}=Tuple, Bool,
+ #b_br{bool=Bool,succ=Succ,fail=Fail},
+ Blocks) ->
+ SuccBlk = maps:get(Succ, Blocks),
+ is_tagged_tuple_1(SuccBlk, Tuple, Fail, Blocks);
+is_tagged_tuple(_, _, _, _) -> no.
+
+is_tagged_tuple_1(#b_blk{is=Is,last=Last}, Tuple, Fail, Blocks) ->
+ case Is of
+ [#b_set{op={bif,tuple_size},dst=ArityVar,
+ args=[#b_var{}=Tuple]},
+ #b_set{op={bif,'=:='},
+ dst=Bool,
+ args=[ArityVar, #b_literal{val=ArityVal}=Arity]}]
+ when is_integer(ArityVal) ->
+ case Last of
+ #b_br{bool=Bool,succ=Succ,fail=Fail} ->
+ SuccBlk = maps:get(Succ, Blocks),
+ case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of
+ no ->
+ no;
+ {yes,Tag} ->
+ {yes,Arity,Tag}
+ end;
+ _ ->
+ no
+ end;
+ _ ->
+ no
+ end.
+
+is_tagged_tuple_2(#b_blk{is=Is,
+ last=#b_br{bool=#b_var{}=Bool,fail=Fail}},
+ Tuple, Fail) ->
+ is_tagged_tuple_3(Is, Bool, Tuple);
+is_tagged_tuple_2(#b_blk{}, _, _) -> no.
+
+is_tagged_tuple_3([#b_set{op=get_tuple_element,
+ dst=TagVar,
+ args=[#b_var{}=Tuple,#b_literal{val=0}]}|Is],
+ Bool, Tuple) ->
+ is_tagged_tuple_4(Is, Bool, TagVar);
+is_tagged_tuple_3([_|Is], Bool, Tuple) ->
+ is_tagged_tuple_3(Is, Bool, Tuple);
+is_tagged_tuple_3([], _, _) -> no.
+
+is_tagged_tuple_4([#b_set{op={bif,'=:='},dst=Bool,
+ args=[#b_var{}=TagVar,
+ #b_literal{val=TagVal}=Tag]}],
+ Bool, TagVar) when is_atom(TagVal) ->
+ {yes,Tag};
+is_tagged_tuple_4([_|Is], Bool, TagVar) ->
+ is_tagged_tuple_4(Is, Bool, TagVar);
+is_tagged_tuple_4([], _, _) -> no.
+
+%%%
+%%% Common subexpression elimination (CSE).
+%%%
+%%% Eliminate repeated evaluation of identical expressions. To avoid
+%%% increasing the size of the stack frame, we don't eliminate
+%%% subexpressions across instructions that clobber the X registers.
+%%%
+
+ssa_opt_cse(#st{ssa=Linear}=St) ->
+ M = #{0=>#{}},
+ St#st{ssa=cse(Linear, #{}, M)}.
+
+cse([{L,#b_blk{is=Is0,last=Last0}=Blk}|Bs], Sub0, M0) ->
+ Es0 = maps:get(L, M0),
+ {Is1,Es,Sub} = cse_is(Is0, Es0, Sub0, []),
+ Last = sub(Last0, Sub),
+ M = cse_successors(Is1, Blk, Es, M0),
+ Is = reverse(Is1),
+ [{L,Blk#b_blk{is=Is,last=Last}}|cse(Bs, Sub, M)];
+cse([], _, _) -> [].
+
+cse_successors([#b_set{op=succeeded,args=[Src]},Bif|_], Blk, EsSucc, M0) ->
+ case cse_suitable(Bif) of
+ true ->
+ %% The previous instruction only has a valid value at the success branch.
+ %% We must remove the substitution for Src from the failure branch.
+ #b_blk{last=#b_br{succ=Succ,fail=Fail}} = Blk,
+ M = cse_successors_1([Succ], EsSucc, M0),
+ EsFail = maps:filter(fun(_, Val) -> Val =/= Src end, EsSucc),
+ cse_successors_1([Fail], EsFail, M);
+ false ->
+ %% There can't be any replacement for Src in EsSucc. No need for
+ %% any special handling.
+ cse_successors_1(beam_ssa:successors(Blk), EsSucc, M0)
+ end;
+cse_successors(_Is, Blk, Es, M) ->
+ cse_successors_1(beam_ssa:successors(Blk), Es, M).
+
+cse_successors_1([L|Ls], Es0, M) ->
+ case M of
+ #{L:=Es1} when map_size(Es1) =:= 0 ->
+ %% The map is already empty. No need to do anything
+ %% since the intersection will be empty.
+ cse_successors_1(Ls, Es0, M);
+ #{L:=Es1} ->
+ %% Calculate the intersection of the two maps.
+ %% Both keys and values must match.
+ Es = maps:filter(fun(Key, Value) ->
+ case Es1 of
+ #{Key:=Value} -> true;
+ #{} -> false
+ end
+ end, Es0),
+ cse_successors_1(Ls, Es0, M#{L:=Es});
+ #{} ->
+ cse_successors_1(Ls, Es0, M#{L=>Es0})
+ end;
+cse_successors_1([], _, M) -> M.
+
+cse_is([#b_set{op=succeeded,dst=Bool,args=[Src]}=I0|Is], Es, Sub0, Acc) ->
+ I = sub(I0, Sub0),
+ case I of
+ #b_set{args=[Src]} ->
+ cse_is(Is, Es, Sub0, [I|Acc]);
+ #b_set{} ->
+ %% The previous instruction has been eliminated. Eliminate the
+ %% 'succeeded' instruction too.
+ Sub = Sub0#{Bool=>#b_literal{val=true}},
+ cse_is(Is, Es, Sub, Acc)
+ end;
+cse_is([#b_set{dst=Dst}=I0|Is], Es0, Sub0, Acc) ->
+ I = sub(I0, Sub0),
+ case beam_ssa:clobbers_xregs(I) of
+ true ->
+ %% Retaining the expressions map across calls and other
+ %% clobbering instructions would work, but it would cause
+ %% the common subexpressions to be saved to Y registers,
+ %% which would probably increase the size of the stack
+ %% frame.
+ cse_is(Is, #{}, Sub0, [I|Acc]);
+ false ->
+ case cse_expr(I) of
+ none ->
+ %% Not suitable for CSE.
+ cse_is(Is, Es0, Sub0, [I|Acc]);
+ {ok,ExprKey} ->
+ case Es0 of
+ #{ExprKey:=Src} ->
+ Sub = Sub0#{Dst=>Src},
+ cse_is(Is, Es0, Sub, Acc);
+ #{} ->
+ Es = Es0#{ExprKey=>Dst},
+ cse_is(Is, Es, Sub0, [I|Acc])
+ end
+ end
+ end;
+cse_is([], Es, Sub, Acc) ->
+ {Acc,Es,Sub}.
+
+cse_expr(#b_set{op=Op,args=Args}=I) ->
+ case cse_suitable(I) of
+ true -> {ok,{Op,Args}};
+ false -> none
+ end.
+
+cse_suitable(#b_set{op=get_hd}) -> true;
+cse_suitable(#b_set{op=get_tl}) -> true;
+cse_suitable(#b_set{op=put_list}) -> true;
+cse_suitable(#b_set{op=put_tuple}) -> true;
+cse_suitable(#b_set{op={bif,tuple_size}}) ->
+ %% Doing CSE for tuple_size/1 can prevent the
+ %% creation of test_arity and select_tuple_arity
+ %% instructions. That could decrease performance
+ %% and beam_validator could fail to understand
+ %% that tuple operations that follow are safe.
+ false;
+cse_suitable(#b_set{anno=Anno,op={bif,Name},args=Args}) ->
+ %% Doing CSE for floating point operators is unsafe.
+ %% Doing CSE for comparison operators would prevent
+ %% creation of 'test' instructions.
+ Arity = length(Args),
+ not (is_map_key(float_op, Anno) orelse
+ erl_internal:new_type_test(Name, Arity) orelse
+ erl_internal:comp_op(Name, Arity) orelse
+ erl_internal:bool_op(Name, Arity));
+cse_suitable(#b_set{}) -> false.
+
+%%%
+%%% Using floating point instructions.
+%%%
+%%% Use the special floating points version of arithmetic
+%%% instructions, if the operands are known to be floats or the result
+%%% of the operation will be a float.
+%%%
+%%% The float instructions were never used in guards before, so we
+%%% will take special care to keep not using them in guards. Using
+%%% them in guards would require a new version of the 'fconv'
+%%% instruction that would take a failure label. Since it is unlikely
+%%% that using float instructions in guards would be benefical, why
+%%% bother implementing a new instruction? Also, implementing float
+%%% instructions in guards in HiPE could turn out to be a lot of work.
+%%%
+
+-record(fs,
+ {s=undefined :: 'undefined' | 'cleared',
+ regs=#{} :: #{beam_ssa:b_var():=beam_ssa:b_var()},
+ fail=none :: 'none' | beam_ssa:label(),
+ non_guards :: gb_sets:set(beam_ssa:label()),
+ bs :: beam_ssa:block_map()
+ }).
+
+ssa_opt_float(#st{ssa=Linear0,cnt=Count0}=St) ->
+ NonGuards0 = float_non_guards(Linear0),
+ NonGuards = gb_sets:from_list(NonGuards0),
+ Blocks = maps:from_list(Linear0),
+ Fs = #fs{non_guards=NonGuards,bs=Blocks},
+ {Linear,Count} = float_opt(Linear0, Count0, Fs),
+ St#st{ssa=Linear,cnt=Count}.
+
+float_non_guards([{L,#b_blk{is=Is}}|Bs]) ->
+ case Is of
+ [#b_set{op=landingpad}|_] ->
+ [L|float_non_guards(Bs)];
+ _ ->
+ float_non_guards(Bs)
+ end;
+float_non_guards([]) -> [?BADARG_BLOCK].
+
+float_opt([{L,#b_blk{last=#b_br{fail=F}}=Blk}|Bs0],
+ Count0, #fs{non_guards=NonGuards}=Fs) ->
+ case gb_sets:is_member(F, NonGuards) of
+ true ->
+ %% This block is not inside a guard.
+ %% We can do the optimization.
+ float_opt_1(L, Blk, Bs0, Count0, Fs);
+ false ->
+ %% This block is inside a guard. Don't do
+ %% any floating point optimizations.
+ {Bs,Count} = float_opt(Bs0, Count0, Fs),
+ {[{L,Blk}|Bs],Count}
+ end;
+float_opt([{L,Blk}|Bs], Count, Fs) ->
+ float_opt_1(L, Blk, Bs, Count, Fs);
+float_opt([], Count, _Fs) ->
+ {[],Count}.
+
+float_opt_1(L, #b_blk{is=Is0}=Blk0, Bs0, Count0, Fs0) ->
+ case float_opt_is(Is0, Fs0, Count0, []) of
+ {Is1,Fs1,Count1} ->
+ Fs2 = float_fail_label(Blk0, Fs1),
+ Fail = Fs2#fs.fail,
+ {Flush,Blk,Fs,Count2} = float_maybe_flush(Blk0, Fs2, Count1),
+ Split = float_split_conv(Is1, Blk),
+ {Blks0,Count3} = float_number(Split, L, Count2),
+ {Blks,Count4} = float_conv(Blks0, Fail, Count3),
+ {Bs,Count} = float_opt(Bs0, Count4, Fs),
+ {Blks++Flush++Bs,Count};
+ none ->
+ {Bs,Count} = float_opt(Bs0, Count0, Fs0),
+ {[{L,Blk0}|Bs],Count}
+ end.
+
+%% Split {float,convert} instructions into individual blocks.
+float_split_conv(Is0, Blk) ->
+ Br = #b_br{bool=#b_literal{val=true},succ=0,fail=0},
+ case splitwith(fun(#b_set{op=Op}) ->
+ Op =/= {float,convert}
+ end, Is0) of
+ {Is,[]} ->
+ [Blk#b_blk{is=Is}];
+ {[_|_]=Is1,[#b_set{op={float,convert}}=Conv|Is2]} ->
+ [#b_blk{is=Is1,last=Br},
+ #b_blk{is=[Conv],last=Br}|float_split_conv(Is2, Blk)];
+ {[],[#b_set{op={float,convert}}=Conv|Is1]} ->
+ [#b_blk{is=[Conv],last=Br}|float_split_conv(Is1, Blk)]
+ end.
+
+%% Number the blocks that were split.
+float_number([B|Bs0], FirstL, Count0) ->
+ {Bs,Count} = float_number(Bs0, Count0),
+ {[{FirstL,B}|Bs],Count}.
+
+float_number([B|Bs0], Count0) ->
+ {Bs,Count} = float_number(Bs0, Count0+1),
+ {[{Count0,B}|Bs],Count};
+float_number([], Count) ->
+ {[],Count}.
+
+%% Insert 'succeeded' instructions after each {float,convert}
+%% instruction.
+float_conv([{L,#b_blk{is=Is0}=Blk0}|Bs0], Fail, Count0) ->
+ case Is0 of
+ [#b_set{op={float,convert}}=Conv] ->
+ {Bool0,Count1} = new_reg('@ssa_bool', Count0),
+ Bool = #b_var{name=Bool0},
+ Succeeded = #b_set{op=succeeded,dst=Bool,
+ args=[Conv#b_set.dst]},
+ Is = [Conv,Succeeded],
+ [{NextL,_}|_] = Bs0,
+ Br = #b_br{bool=Bool,succ=NextL,fail=Fail},
+ Blk = Blk0#b_blk{is=Is,last=Br},
+ {Bs,Count} = float_conv(Bs0, Fail, Count1),
+ {[{L,Blk}|Bs],Count};
+ [_|_] ->
+ case Bs0 of
+ [{NextL,_}|_] ->
+ Br = #b_br{bool=#b_literal{val=true},
+ succ=NextL,fail=NextL},
+ Blk = Blk0#b_blk{last=Br},
+ {Bs,Count} = float_conv(Bs0, Fail, Count0),
+ {[{L,Blk}|Bs],Count};
+ [] ->
+ {[{L,Blk0}],Count0}
+ end
+ end.
+
+float_maybe_flush(Blk0, #fs{s=cleared,fail=Fail,bs=Blocks}=Fs0, Count0) ->
+ #b_blk{last=#b_br{bool=#b_var{},succ=Succ}=Br} = Blk0,
+ #b_blk{is=Is} = maps:get(Succ, Blocks),
+ case Is of
+ [#b_set{anno=#{float_op:=_}}|_] ->
+ %% The next operation is also a floating point operation.
+ %% No flush needed.
+ {[],Blk0,Fs0,Count0};
+ _ ->
+ %% Flush needed.
+ {Bool0,Count1} = new_reg('@ssa_bool', Count0),
+ Bool = #b_var{name=Bool0},
+
+ %% Allocate block numbers.
+ CheckL = Count1, %For checkerror.
+ FlushL = Count1 + 1, %For flushing of float regs.
+ Count = Count1 + 2,
+ Blk = Blk0#b_blk{last=Br#b_br{succ=CheckL}},
+
+ %% Build the block with the checkerror instruction.
+ CheckIs = [#b_set{op={float,checkerror},dst=Bool}],
+ CheckBr = #b_br{bool=Bool,succ=FlushL,fail=Fail},
+ CheckBlk = #b_blk{is=CheckIs,last=CheckBr},
+
+ %% Build the block that flushes all registers.
+ FlushIs = float_flush_regs(Fs0),
+ FlushBr = #b_br{bool=#b_literal{val=true},succ=Succ,fail=Succ},
+ FlushBlk = #b_blk{is=FlushIs,last=FlushBr},
+
+ %% Update state and blocks.
+ Fs = Fs0#fs{s=undefined,regs=#{},fail=none},
+ FlushBs = [{CheckL,CheckBlk},{FlushL,FlushBlk}],
+ {FlushBs,Blk,Fs,Count}
+ end;
+float_maybe_flush(Blk, Fs, Count) ->
+ {[],Blk,Fs,Count}.
+
+float_opt_is([#b_set{op=succeeded,args=[Src]}=I0],
+ #fs{regs=Rs}=Fs, Count, Acc) ->
+ case Rs of
+ #{Src:=Fr} ->
+ I = I0#b_set{args=[Fr]},
+ {reverse(Acc, [I]),Fs,Count};
+ #{} ->
+ {reverse(Acc, [I0]),Fs,Count}
+ end;
+float_opt_is([#b_set{anno=Anno0}=I0|Is0], Fs0, Count0, Acc) ->
+ case Anno0 of
+ #{float_op:=FTypes} ->
+ Anno = maps:remove(float_op, Anno0),
+ I1 = I0#b_set{anno=Anno},
+ {Is,Fs,Count} = float_make_op(I1, FTypes, Fs0, Count0),
+ float_opt_is(Is0, Fs, Count, reverse(Is, Acc));
+ #{} ->
+ float_opt_is(Is0, Fs0#fs{regs=#{}}, Count0, [I0|Acc])
+ end;
+float_opt_is([], Fs, _Count, _Acc) ->
+ #fs{s=undefined} = Fs, %Assertion.
+ none.
+
+float_make_op(#b_set{op={bif,Op},dst=Dst,args=As0}=I0,
+ Ts, #fs{s=S,regs=Rs0}=Fs, Count0) ->
+ {As1,Rs1,Count1} = float_load(As0, Ts, Rs0, Count0, []),
+ {As,Is0} = unzip(As1),
+ {Fr,Count2} = new_reg('@fr', Count1),
+ FrDst = #b_var{name=Fr},
+ I = I0#b_set{op={float,Op},dst=FrDst,args=As},
+ Rs = Rs1#{Dst=>FrDst},
+ Is = append(Is0) ++ [I],
+ case S of
+ undefined ->
+ {Ignore,Count} = new_reg('@ssa_ignore', Count2),
+ C = #b_set{op={float,clearerror},dst=#b_var{name=Ignore}},
+ {[C|Is],Fs#fs{s=cleared,regs=Rs},Count};
+ cleared ->
+ {Is,Fs#fs{regs=Rs},Count2}
+ end.
+
+float_load([A|As], [T|Ts], Rs0, Count0, Acc) ->
+ {Load,Rs,Count} = float_reg_arg(A, T, Rs0, Count0),
+ float_load(As, Ts, Rs, Count, [Load|Acc]);
+float_load([], [], Rs, Count, Acc) ->
+ {reverse(Acc),Rs,Count}.
+
+float_reg_arg(A, T, Rs, Count0) ->
+ case Rs of
+ #{A:=Fr} ->
+ {{Fr,[]},Rs,Count0};
+ #{} ->
+ {Fr,Count} = new_float_copy_reg(Count0),
+ Dst = #b_var{name=Fr},
+ I = float_load_reg(T, A, Dst),
+ {{Dst,[I]},Rs#{A=>Dst},Count}
+ end.
+
+float_load_reg(convert, #b_var{}=Src, Dst) ->
+ #b_set{op={float,convert},dst=Dst,args=[Src]};
+float_load_reg(convert, #b_literal{val=Val}=Src, Dst) ->
+ try float(Val) of
+ F ->
+ #b_set{op={float,put},dst=Dst,args=[#b_literal{val=F}]}
+ catch
+ error:_ ->
+ %% Let the exception happen at runtime.
+ #b_set{op={float,convert},dst=Dst,args=[Src]}
+ end;
+float_load_reg(float, Src, Dst) ->
+ #b_set{op={float,put},dst=Dst,args=[Src]}.
+
+new_float_copy_reg(Count) ->
+ new_reg('@fr_copy', Count).
+
+new_reg(Base, Count) ->
+ Fr = {Base,Count},
+ {Fr,Count+1}.
+
+float_fail_label(#b_blk{last=Last}, Fs) ->
+ case Last of
+ #b_br{bool=#b_var{},fail=Fail} ->
+ Fs#fs{fail=Fail};
+ _ ->
+ Fs
+ end.
+
+float_flush_regs(#fs{regs=Rs}) ->
+ maps:fold(fun(_, #b_var{name={'@fr_copy',_}}, Acc) ->
+ Acc;
+ (Dst, Fr, Acc) ->
+ [#b_set{op={float,get},dst=Dst,args=[Fr]}|Acc]
+ end, [], Rs).
+
+%%%
+%%% Live optimization.
+%%%
+%%% Optimize instructions whose values are not used. They could be
+%%% removed if they have no side effects, or in a few cases replaced
+%%% with a cheaper instructions
+%%%
+
+ssa_opt_live(#st{ssa=Linear}=St) ->
+ St#st{ssa=live_opt(reverse(Linear), #{}, [])}.
+
+live_opt([{L,Blk0}|Bs], LiveMap0, Acc) ->
+ Successors = beam_ssa:successors(Blk0),
+ Live0 = live_opt_succ(Successors, L, LiveMap0),
+ {Blk,Live} = live_opt_blk(Blk0, Live0),
+ LiveMap = live_opt_phis(Blk#b_blk.is, L, Live, LiveMap0),
+ live_opt(Bs, LiveMap, [{L,Blk}|Acc]);
+live_opt([], _, Acc) -> Acc.
+
+live_opt_succ([S|Ss], L, LiveMap) ->
+ Live0 = live_opt_succ(Ss, L, LiveMap),
+ Key = {S,L},
+ case LiveMap of
+ #{Key:=Live} ->
+ gb_sets:union(Live, Live0);
+ #{S:=Live} ->
+ gb_sets:union(Live, Live0);
+ #{} ->
+ Live0
+ end;
+live_opt_succ([], _, _) ->
+ gb_sets:empty().
+
+live_opt_phis(Is, L, Live0, LiveMap0) ->
+ LiveMap = LiveMap0#{L=>Live0},
+ Phis = takewhile(fun(#b_set{op=Op}) -> Op =:= phi end, Is),
+ case Phis of
+ [] ->
+ LiveMap;
+ [_|_] ->
+ PhiArgs = append([Args || #b_set{args=Args} <- Phis]),
+ case [{P,V} || {#b_var{}=V,P} <- PhiArgs] of
+ [_|_]=PhiVars ->
+ PhiLive0 = rel2fam(PhiVars),
+ PhiLive = [{{L,P},gb_sets:union(gb_sets:from_list(Vs), Live0)} ||
+ {P,Vs} <- PhiLive0],
+ maps:merge(LiveMap, maps:from_list(PhiLive));
+ [] ->
+ %% There were only literals in the phi node(s).
+ LiveMap
+ end
+ end.
+
+live_opt_blk(#b_blk{is=Is0,last=Last}=Blk, Live0) ->
+ Live1 = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(Last))),
+ {Is,Live} = live_opt_is(reverse(Is0), Live1, []),
+ {Blk#b_blk{is=Is},Live}.
+
+live_opt_is([#b_set{op=phi,dst=Dst}=I|Is], Live, Acc) ->
+ case gb_sets:is_member(Dst, Live) of
+ true ->
+ live_opt_is(Is, Live, [I|Acc]);
+ false ->
+ live_opt_is(Is, Live, Acc)
+ end;
+live_opt_is([#b_set{op=succeeded,dst=SuccDst=SuccDstVar,
+ args=[Dst]}=SuccI,
+ #b_set{dst=Dst}=I|Is], Live0, Acc) ->
+ case gb_sets:is_member(Dst, Live0) of
+ true ->
+ case gb_sets:is_member(SuccDst, Live0) of
+ true ->
+ Live1 = gb_sets:add(Dst, Live0),
+ Live = gb_sets:delete_any(SuccDst, Live1),
+ live_opt_is([I|Is], Live, [SuccI|Acc]);
+ false ->
+ live_opt_is([I|Is], Live0, Acc)
+ end;
+ false ->
+ case live_opt_unused(I) of
+ {replace,NewI0} ->
+ NewI = NewI0#b_set{dst=SuccDstVar},
+ live_opt_is([NewI|Is], Live0, Acc);
+ keep ->
+ case gb_sets:is_member(SuccDst, Live0) of
+ true ->
+ Live1 = gb_sets:add(Dst, Live0),
+ Live = gb_sets:delete_any(SuccDst, Live1),
+ live_opt_is([I|Is], Live, [SuccI|Acc]);
+ false ->
+ live_opt_is([I|Is], Live0, Acc)
+ end
+ end
+ end;
+live_opt_is([#b_set{dst=Dst}=I|Is], Live0, Acc) ->
+ case gb_sets:is_member(Dst, Live0) of
+ true ->
+ Live1 = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(I))),
+ Live = gb_sets:delete_any(Dst, Live1),
+ live_opt_is(Is, Live, [I|Acc]);
+ false ->
+ case beam_ssa:no_side_effect(I) of
+ true ->
+ live_opt_is(Is, Live0, Acc);
+ false ->
+ Live = gb_sets:union(Live0, gb_sets:from_ordset(beam_ssa:used(I))),
+ live_opt_is(Is, Live, [I|Acc])
+ end
+ end;
+live_opt_is([], Live, Acc) ->
+ {Acc,Live}.
+
+live_opt_unused(#b_set{op=get_map_element}=Set) ->
+ {replace,Set#b_set{op=has_map_field}};
+live_opt_unused(_) -> keep.
+
+%%%
+%%% Optimize binary matching instructions.
+%%%
+
+ssa_opt_bsm(#st{ssa=Linear}=St) ->
+ Extracted0 = bsm_extracted(Linear),
+ Extracted = cerl_sets:from_list(Extracted0),
+ St#st{ssa=bsm_skip(Linear, Extracted)}.
+
+bsm_skip([{L,#b_blk{is=Is0}=Blk}|Bs], Extracted) ->
+ Is = bsm_skip_is(Is0, Extracted),
+ [{L,Blk#b_blk{is=Is}}|bsm_skip(Bs, Extracted)];
+bsm_skip([], _) -> [].
+
+bsm_skip_is([I0|Is], Extracted) ->
+ case I0 of
+ #b_set{op=bs_match,args=[#b_literal{val=string}|_]} ->
+ [I0|bsm_skip_is(Is, Extracted)];
+ #b_set{op=bs_match,dst=Ctx,args=[Type,PrevCtx|Args0]} ->
+ I = case cerl_sets:is_element(Ctx, Extracted) of
+ true ->
+ I0;
+ false ->
+ %% The value is never extracted.
+ Args = [#b_literal{val=skip},PrevCtx,Type|Args0],
+ I0#b_set{args=Args}
+ end,
+ [I|Is];
+ #b_set{} ->
+ [I0|bsm_skip_is(Is, Extracted)]
+ end;
+bsm_skip_is([], _) -> [].
+
+bsm_extracted([{_,#b_blk{is=Is}}|Bs]) ->
+ case Is of
+ [#b_set{op=bs_extract,args=[Ctx]}|_] ->
+ [Ctx|bsm_extracted(Bs)];
+ _ ->
+ bsm_extracted(Bs)
+ end;
+bsm_extracted([]) -> [].
+
+%%%
+%%% Short-cutting binary matching instructions.
+%%%
+
+ssa_opt_bsm_shortcut(#st{ssa=Linear}=St) ->
+ Positions = bsm_positions(Linear, #{}),
+ case map_size(Positions) of
+ 0 ->
+ %% No binary matching instructions.
+ St;
+ _ ->
+ St#st{ssa=bsm_shortcut(Linear, Positions)}
+ end.
+
+bsm_positions([{L,#b_blk{is=Is,last=Last}}|Bs], PosMap0) ->
+ PosMap = bsm_positions_is(Is, PosMap0),
+ case {Is,Last} of
+ {[#b_set{op=bs_test_tail,dst=Bool,args=[Ctx,#b_literal{val=Bits0}]}],
+ #b_br{bool=Bool,fail=Fail}} ->
+ Bits = Bits0 + maps:get(Ctx, PosMap0),
+ bsm_positions(Bs, PosMap#{L=>{Bits,Fail}});
+ {_,_} ->
+ bsm_positions(Bs, PosMap)
+ end;
+bsm_positions([], PosMap) -> PosMap.
+
+bsm_positions_is([#b_set{op=bs_start_match,dst=New}|Is], PosMap0) ->
+ PosMap = PosMap0#{New=>0},
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([#b_set{op=bs_match,dst=New,args=Args}|Is], PosMap0) ->
+ [_,Old|_] = Args,
+ #{Old:=Bits0} = PosMap0,
+ Bits = bsm_update_bits(Args, Bits0),
+ PosMap = PosMap0#{New=>Bits},
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([_|Is], PosMap) ->
+ bsm_positions_is(Is, PosMap);
+bsm_positions_is([], PosMap) -> PosMap.
+
+bsm_update_bits([#b_literal{val=string},_,#b_literal{val=String}], Bits) ->
+ Bits + bit_size(String);
+bsm_update_bits([#b_literal{val=utf8}|_], Bits) ->
+ Bits + 8;
+bsm_update_bits([#b_literal{val=utf16}|_], Bits) ->
+ Bits + 16;
+bsm_update_bits([#b_literal{val=utf32}|_], Bits) ->
+ Bits + 32;
+bsm_update_bits([_,_,_,#b_literal{val=Sz},#b_literal{val=U}], Bits)
+ when is_integer(Sz) ->
+ Bits + Sz*U;
+bsm_update_bits(_, Bits) -> Bits.
+
+bsm_shortcut([{L,#b_blk{is=Is,last=Last0}=Blk}|Bs], PosMap) ->
+ case {Is,Last0} of
+ {[#b_set{op=bs_match,dst=New,args=[_,Old|_]},
+ #b_set{op=succeeded,dst=Bool,args=[New]}],
+ #b_br{bool=Bool,fail=Fail}} ->
+ case PosMap of
+ #{Old:=Bits,Fail:={TailBits,NextFail}} when Bits > TailBits ->
+ Last = Last0#b_br{fail=NextFail},
+ [{L,Blk#b_blk{last=Last}}|bsm_shortcut(Bs, PosMap)];
+ #{} ->
+ [{L,Blk}|bsm_shortcut(Bs, PosMap)]
+ end;
+ {_,_} ->
+ [{L,Blk}|bsm_shortcut(Bs, PosMap)]
+ end;
+bsm_shortcut([], _PosMap) -> [].
+
+%%%
+%%% Eliminate redundant bs_test_unit2 instructions.
+%%%
+
+ssa_opt_bsm_units(#st{ssa=Linear}=St) ->
+ St#st{ssa=bsm_units(Linear, #{})}.
+
+bsm_units([{L,#b_blk{last=#b_br{succ=Succ,fail=Fail}}=Block0} | Bs], UnitMaps0) ->
+ UnitsIn = maps:get(L, UnitMaps0, #{}),
+ {Block, UnitsOut} = bsm_units_skip(Block0, UnitsIn),
+ UnitMaps1 = bsm_units_join(Succ, UnitsOut, UnitMaps0),
+ UnitMaps = bsm_units_join(Fail, UnitsIn, UnitMaps1),
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([{L,#b_blk{last=#b_switch{fail=Fail,list=Switch}}=Block} | Bs], UnitMaps0) ->
+ UnitsIn = maps:get(L, UnitMaps0, #{}),
+ Labels = [Fail | [Lbl || {_Arg, Lbl} <- Switch]],
+ UnitMaps = foldl(fun(Lbl, UnitMaps) ->
+ bsm_units_join(Lbl, UnitsIn, UnitMaps)
+ end, UnitMaps0, Labels),
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([{L, Block} | Bs], UnitMaps) ->
+ [{L, Block} | bsm_units(Bs, UnitMaps)];
+bsm_units([], _UnitMaps) ->
+ [].
+
+bsm_units_skip(Block, Units) ->
+ bsm_units_skip_1(Block#b_blk.is, Block, Units).
+
+bsm_units_skip_1([#b_set{op=bs_start_match,dst=New}|_], Block, Units) ->
+ %% We bail early since there can't be more than one match per block.
+ {Block, Units#{ New => 1 }};
+bsm_units_skip_1([#b_set{op=bs_match,
+ dst=New,
+ args=[#b_literal{val=skip},
+ Ctx,
+ #b_literal{val=binary},
+ _Flags,
+ #b_literal{val=all},
+ #b_literal{val=OpUnit}]}=Skip | Test],
+ Block0, Units) ->
+ [#b_set{op=succeeded,dst=Bool,args=[New]}] = Test, %Assertion.
+ #b_br{bool=Bool} = Last0 = Block0#b_blk.last, %Assertion.
+ CtxUnit = maps:get(Ctx, Units),
+ if
+ CtxUnit rem OpUnit =:= 0 ->
+ Is = takewhile(fun(I) -> I =/= Skip end, Block0#b_blk.is),
+ Last = Last0#b_br{bool=#b_literal{val=true}},
+ Block = Block0#b_blk{is=Is,last=Last},
+ {Block, Units#{ New => CtxUnit }};
+ CtxUnit rem OpUnit =/= 0 ->
+ {Block0, Units#{ New => OpUnit, Ctx => OpUnit }}
+ end;
+bsm_units_skip_1([#b_set{op=bs_match,dst=New,args=Args}|_], Block, Units) ->
+ [_,Ctx|_] = Args,
+ CtxUnit = maps:get(Ctx, Units),
+ OpUnit = bsm_op_unit(Args),
+ {Block, Units#{ New => gcd(OpUnit, CtxUnit) }};
+bsm_units_skip_1([_I | Is], Block, Units) ->
+ bsm_units_skip_1(Is, Block, Units);
+bsm_units_skip_1([], Block, Units) ->
+ {Block, Units}.
+
+bsm_op_unit([_,_,_,Size,#b_literal{val=U}]) ->
+ case Size of
+ #b_literal{val=Sz} when is_integer(Sz) -> Sz*U;
+ _ -> U
+ end;
+bsm_op_unit([#b_literal{val=string},_,#b_literal{val=String}]) ->
+ bit_size(String);
+bsm_op_unit([#b_literal{val=utf8}|_]) ->
+ 8;
+bsm_op_unit([#b_literal{val=utf16}|_]) ->
+ 16;
+bsm_op_unit([#b_literal{val=utf32}|_]) ->
+ 32;
+bsm_op_unit(_) ->
+ 1.
+
+%% Several paths can lead to the same match instruction and the inferred units
+%% may differ between them, so we can only keep the information that is common
+%% to all paths.
+bsm_units_join(Lbl, MapA, UnitMaps0) when is_map_key(Lbl, UnitMaps0) ->
+ MapB = maps:get(Lbl, UnitMaps0),
+ Merged = if
+ map_size(MapB) =< map_size(MapA) ->
+ bsm_units_join_1(maps:keys(MapB), MapA, MapB);
+ map_size(MapB) > map_size(MapA) ->
+ bsm_units_join_1(maps:keys(MapA), MapB, MapA)
+ end,
+ maps:put(Lbl, Merged, UnitMaps0);
+bsm_units_join(Lbl, MapA, UnitMaps0) when MapA =/= #{} ->
+ maps:put(Lbl, MapA, UnitMaps0);
+bsm_units_join(_Lbl, _MapA, UnitMaps0) ->
+ UnitMaps0.
+
+bsm_units_join_1([Key | Keys], Left, Right) when is_map_key(Key, Left) ->
+ UnitA = maps:get(Key, Left),
+ UnitB = maps:get(Key, Right),
+ bsm_units_join_1(Keys, Left, maps:put(Key, gcd(UnitA, UnitB), Right));
+bsm_units_join_1([Key | Keys], Left, Right) ->
+ bsm_units_join_1(Keys, Left, maps:remove(Key, Right));
+bsm_units_join_1([], _MapA, Right) ->
+ Right.
+
+%%%
+%%% Miscellanous optimizations in execution order.
+%%%
+
+ssa_opt_misc(#st{ssa=Linear}=St) ->
+ St#st{ssa=misc_opt(Linear, #{})}.
+
+misc_opt([{L,#b_blk{is=Is0,last=Last0}=Blk0}|Bs], Sub0) ->
+ {Is,Sub} = misc_opt_is(Is0, Sub0, []),
+ Last = sub(Last0, Sub),
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ [{L,Blk}|misc_opt(Bs, Sub)];
+misc_opt([], _) -> [].
+
+misc_opt_is([#b_set{op=phi}=I0|Is], Sub0, Acc) ->
+ #b_set{dst=Dst,args=Args} = I = sub(I0, Sub0),
+ case all_same(Args) of
+ true ->
+ %% Eliminate the phi node if there is just one source
+ %% value or if the values are identical.
+ [{Val,_}|_] = Args,
+ Sub = Sub0#{Dst=>Val},
+ misc_opt_is(Is, Sub, Acc);
+ false ->
+ misc_opt_is(Is, Sub0, [I|Acc])
+ end;
+misc_opt_is([#b_set{op={bif,'and'}}=I0], Sub, Acc) ->
+ #b_set{dst=Dst,args=Args} = I = sub(I0, Sub),
+ case eval_and(Args) of
+ error ->
+ misc_opt_is([], Sub, [I|Acc]);
+ Val ->
+ misc_opt_is([], Sub#{Dst=>Val}, Acc)
+ end;
+misc_opt_is([#b_set{op={bif,'or'}}=I0], Sub, Acc) ->
+ #b_set{dst=Dst,args=Args} = I = sub(I0, Sub),
+ case eval_or(Args) of
+ error ->
+ misc_opt_is([], Sub, [I|Acc]);
+ Val ->
+ misc_opt_is([], Sub#{Dst=>Val}, Acc)
+ end;
+misc_opt_is([#b_set{}=I0|Is], Sub, Acc) ->
+ #b_set{op=Op,dst=Dst,args=Args} = I = sub(I0, Sub),
+ case make_literal(Op, Args) of
+ #b_literal{}=Literal ->
+ misc_opt_is(Is, Sub#{Dst=>Literal}, Acc);
+ error ->
+ misc_opt_is(Is, Sub, [I|Acc])
+ end;
+misc_opt_is([], Sub, Acc) ->
+ {reverse(Acc),Sub}.
+
+all_same([{H,_}|T]) ->
+ all(fun({E,_}) -> E =:= H end, T).
+
+make_literal(put_tuple, Args) ->
+ case make_literal_list(Args, []) of
+ error ->
+ error;
+ List ->
+ #b_literal{val=list_to_tuple(List)}
+ end;
+make_literal(put_list, [#b_literal{val=H},#b_literal{val=T}]) ->
+ #b_literal{val=[H|T]};
+make_literal(_, _) -> error.
+
+make_literal_list([#b_literal{val=H}|T], Acc) ->
+ make_literal_list(T, [H|Acc]);
+make_literal_list([_|_], _) ->
+ error;
+make_literal_list([], Acc) ->
+ reverse(Acc).
+
+eval_and(Args) ->
+ case Args of
+ [_,#b_literal{val=false}=Res] -> Res;
+ [Res,#b_literal{val=true}] -> Res;
+ [_,_] -> error
+ end.
+
+eval_or(Args) ->
+ case Args of
+ [Res,#b_literal{val=false}] -> Res;
+ [_,#b_literal{val=true}=Res] -> Res;
+ [_,_] -> error
+ end.
+
+%%%
+%%% Optimize expressions such as "tuple_size(Var) =:= 2".
+%%%
+%%% Consider this code:
+%%%
+%%% 0:
+%%% .
+%%% .
+%%% .
+%%% Size = bif:tuple_size Var
+%%% BoolVar1 = succeeded Size
+%%% br BoolVar1, label 4, label 3
+%%%
+%%% 4:
+%%% BoolVar2 = bif:'=:=' Size, literal 2
+%%% br BoolVar2, label 6, label 3
+%%%
+%%% 6: ... %% OK
+%%%
+%%% 3: ... %% Not a tuple of size 2
+%%%
+%%% The BEAM code will look this:
+%%%
+%%% {bif,tuple_size,{f,3},[{x,0}],{x,0}}.
+%%% {test,is_eq_exact,{f,3},[{x,0},{integer,2}]}.
+%%%
+%%% Better BEAM code will be produced if we transform the
+%%% code like this:
+%%%
+%%% 0:
+%%% .
+%%% .
+%%% .
+%%% br label 10
+%%%
+%%% 10:
+%%% NewBoolVar = bif:is_tuple Var
+%%% br NewBoolVar, label 11, label 3
+%%%
+%%% 11:
+%%% Size = bif:tuple_size Var
+%%% br label 4
+%%%
+%%% 4:
+%%% BoolVar2 = bif:'=:=' Size, literal 2
+%%% br BoolVar2, label 6, label 3
+%%%
+%%% (The key part of the transformation is the removal of
+%%% the 'succeeded' instruction to signal to the code generator
+%%% that the call to tuple_size/1 can't fail.)
+%%%
+%%% The BEAM code will look like:
+%%%
+%%% {test,is_tuple,{f,3},[{x,0}]}.
+%%% {test_arity,{f,3},[{x,0},2]}.
+%%%
+%%% Those two instructions will be combined into a single
+%%% is_tuple_of_arity instruction by the loader.
+%%%
+
+ssa_opt_tuple_size(#st{ssa=Linear0,cnt=Count0}=St) ->
+ {Linear,Count} = opt_tup_size(Linear0, Count0, []),
+ St#st{ssa=Linear,cnt=Count}.
+
+opt_tup_size([{L,#b_blk{is=Is,last=Last}=Blk}|Bs], Count0, Acc0) ->
+ case {Is,Last} of
+ {[#b_set{op={bif,'=:='},dst=Bool,args=[#b_var{}=Tup,#b_literal{val=Arity}]}],
+ #b_br{bool=Bool}} when is_integer(Arity), Arity >= 0 ->
+ {Acc,Count} = opt_tup_size_1(Tup, L, Count0, Acc0),
+ opt_tup_size(Bs, Count, [{L,Blk}|Acc]);
+ {_,_} ->
+ opt_tup_size(Bs, Count0, [{L,Blk}|Acc0])
+ end;
+opt_tup_size([], Count, Acc) ->
+ {reverse(Acc),Count}.
+
+opt_tup_size_1(Size, EqL, Count0, [{L,Blk0}|Acc]) ->
+ case Blk0 of
+ #b_blk{is=Is0,last=#b_br{bool=Bool,succ=EqL,fail=Fail}} ->
+ case opt_tup_size_is(Is0, Bool, Size, []) of
+ none ->
+ {[{L,Blk0}|Acc],Count0};
+ {PreIs,TupleSizeIs,Tuple} ->
+ opt_tup_size_2(PreIs, TupleSizeIs, L, EqL,
+ Tuple, Fail, Count0, Acc)
+ end;
+ #b_blk{} ->
+ {[{L,Blk0}|Acc],Count0}
+ end;
+opt_tup_size_1(_, _, Count, Acc) ->
+ {Acc,Count}.
+
+opt_tup_size_2(PreIs, TupleSizeIs, PreL, EqL, Tuple, Fail, Count0, Acc) ->
+ IsTupleL = Count0,
+ TupleSizeL = Count0 + 1,
+ Bool = #b_var{name={'@ssa_bool',Count0+2}},
+ Count = Count0 + 3,
+
+ True = #b_literal{val=true},
+ PreBr = #b_br{bool=True,succ=IsTupleL,fail=IsTupleL},
+ PreBlk = #b_blk{is=PreIs,last=PreBr},
+
+ IsTupleIs = [#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}],
+ IsTupleBr = #b_br{bool=Bool,succ=TupleSizeL,fail=Fail},
+ IsTupleBlk = #b_blk{is=IsTupleIs,last=IsTupleBr},
+
+ TupleSizeBr = #b_br{bool=True,succ=EqL,fail=EqL},
+ TupleSizeBlk = #b_blk{is=TupleSizeIs,last=TupleSizeBr},
+ {[{TupleSizeL,TupleSizeBlk},
+ {IsTupleL,IsTupleBlk},
+ {PreL,PreBlk}|Acc],Count}.
+
+opt_tup_size_is([#b_set{op={bif,tuple_size},dst=Size,args=[Tuple]}=I,
+ #b_set{op=succeeded,dst=Bool,args=[Size]}],
+ Bool, Size, Acc) ->
+ {reverse(Acc),[I],Tuple};
+opt_tup_size_is([I|Is], Bool, Size, Acc) ->
+ opt_tup_size_is(Is, Bool, Size, [I|Acc]);
+opt_tup_size_is([], _, _, _Acc) -> none.
+
+%%%
+%%% Optimize #b_switch{} instructions.
+%%%
+%%% If the argument for a #b_switch{} comes from a phi node with all
+%%% literals, any values in the switch list which are not in the phi
+%%% node can be removed.
+%%%
+%%% If the values in the phi node and switch list are the same,
+%%% the failure label can't be reached and be eliminated.
+%%%
+%%% A #b_switch{} with only one value can be rewritten to
+%%% a #b_br{}. A switch that only verifies that the argument
+%%% is 'true' or 'false' can be rewritten to a is_boolean test.
+%%%
+
+ssa_opt_sw(#st{ssa=Linear0,cnt=Count0}=St) ->
+ {Linear,Count} = opt_sw(Linear0, #{}, Count0, []),
+ St#st{ssa=Linear,cnt=Count}.
+
+opt_sw([{L,#b_blk{is=Is,last=#b_switch{}=Last0}=Blk0}|Bs], Phis0, Count0, Acc) ->
+ Phis = opt_sw_phis(Is, Phis0),
+ case opt_sw_last(Last0, Phis) of
+ #b_switch{arg=Arg,fail=Fail,list=[{Lit,Lbl}]} ->
+ %% Rewrite a single value switch to a br.
+ Bool = #b_var{name={'@ssa_bool',Count0}},
+ Count = Count0 + 1,
+ IsEq = #b_set{op={bif,'=:='},dst=Bool,args=[Arg,Lit]},
+ Br = #b_br{bool=Bool,succ=Lbl,fail=Fail},
+ Blk = Blk0#b_blk{is=Is++[IsEq],last=Br},
+ opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]);
+ #b_switch{arg=Arg,fail=Fail,
+ list=[{#b_literal{val=B1},Lbl},{#b_literal{val=B2},Lbl}]}
+ when B1 =:= not B2 ->
+ %% Replace with is_boolean test.
+ Bool = #b_var{name={'@ssa_bool',Count0}},
+ Count = Count0 + 1,
+ IsBool = #b_set{op={bif,is_boolean},dst=Bool,args=[Arg]},
+ Br = #b_br{bool=Bool,succ=Lbl,fail=Fail},
+ Blk = Blk0#b_blk{is=Is++[IsBool],last=Br},
+ opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]);
+ Last0 ->
+ opt_sw(Bs, Phis, Count0, [{L,Blk0}|Acc]);
+ Last ->
+ Blk = Blk0#b_blk{last=Last},
+ opt_sw(Bs, Phis, Count0, [{L,Blk}|Acc])
+ end;
+opt_sw([{L,#b_blk{is=Is}=Blk}|Bs], Phis0, Count, Acc) ->
+ Phis = opt_sw_phis(Is, Phis0),
+ opt_sw(Bs, Phis, Count, [{L,Blk}|Acc]);
+opt_sw([], _Phis, Count, Acc) ->
+ {reverse(Acc),Count}.
+
+opt_sw_phis([#b_set{op=phi,dst=Dst,args=Args}|Is], Phis) ->
+ case opt_sw_literals(Args, []) of
+ error ->
+ opt_sw_phis(Is, Phis);
+ Literals ->
+ opt_sw_phis(Is, Phis#{Dst=>Literals})
+ end;
+opt_sw_phis(_, Phis) -> Phis.
+
+opt_sw_last(#b_switch{arg=Arg,fail=Fail,list=List0}=Sw0, Phis) ->
+ case Phis of
+ #{Arg:=Values0} ->
+ Values = gb_sets:from_list(Values0),
+
+ %% Prune the switch list to only contain the possible values.
+ List1 = [P || {Lit,_}=P <- List0, gb_sets:is_member(Lit, Values)],
+
+ %% Now test whether the failure label can ever be reached.
+ Sw = case gb_sets:size(Values) =:= length(List1) of
+ true ->
+ %% The switch list has the same number of values as the phi node.
+ %% The values must be the same, because the values that were not
+ %% possible were pruned from the switch list. Therefore, the
+ %% failure label can't possibly be reached, and we can choose a
+ %% a new failure label by picking a value from the list.
+ case List1 of
+ [{#b_literal{},Lbl}|List] ->
+ Sw0#b_switch{fail=Lbl,list=List};
+ [] ->
+ Sw0#b_switch{list=List1}
+ end;
+ false ->
+ %% There are some values in the phi node that are not in the
+ %% switch list; thus, the failure label can still be reached.
+ Sw0
+ end,
+ beam_ssa:normalize(Sw);
+ #{} ->
+ %% Ensure that no label in the switch list is the same
+ %% as the failure label.
+ List = [{Val,Lbl} || {Val,Lbl} <- List0, Lbl =/= Fail],
+ Sw = Sw0#b_switch{list=List},
+ beam_ssa:normalize(Sw)
+ end.
+
+opt_sw_literals([{#b_literal{}=Lit,_}|T], Acc) ->
+ opt_sw_literals(T, [Lit|Acc]);
+opt_sw_literals([_|_], _Acc) ->
+ error;
+opt_sw_literals([], Acc) -> Acc.
+
+
+%%%
+%%% Merge blocks.
+%%%
+
+ssa_opt_merge_blocks(#st{ssa=Blocks}=St) ->
+ Preds = beam_ssa:predecessors(Blocks),
+ St#st{ssa=merge_blocks_1(beam_ssa:rpo(Blocks), Preds, Blocks)}.
+
+merge_blocks_1([L|Ls], Preds0, Blocks0) ->
+ case Preds0 of
+ #{L:=[P]} ->
+ #{P:=Blk0,L:=Blk1} = Blocks0,
+ case is_merge_allowed(L, Blk0, Blk1) of
+ true ->
+ #b_blk{is=Is0} = Blk0,
+ #b_blk{is=Is1} = Blk1,
+ Is = Is0 ++ Is1,
+ Blk = Blk1#b_blk{is=Is},
+ Blocks1 = maps:remove(L, Blocks0),
+ Blocks2 = maps:put(P, Blk, Blocks1),
+ Successors = beam_ssa:successors(Blk),
+ Blocks = beam_ssa:update_phi_labels(Successors, L, P, Blocks2),
+ Preds = merge_update_preds(Successors, L, P, Preds0),
+ merge_blocks_1(Ls, Preds, Blocks);
+ false ->
+ merge_blocks_1(Ls, Preds0, Blocks0)
+ end;
+ #{} ->
+ merge_blocks_1(Ls, Preds0, Blocks0)
+ end;
+merge_blocks_1([], _Preds, Blocks) -> Blocks.
+
+merge_update_preds([L|Ls], From, To, Preds0) ->
+ Ps = [rename_label(P, From, To) || P <- maps:get(L, Preds0)],
+ Preds = maps:put(L, Ps, Preds0),
+ merge_update_preds(Ls, From, To, Preds);
+merge_update_preds([], _, _, Preds) -> Preds.
+
+rename_label(From, From, To) -> To;
+rename_label(Lbl, _, _) -> Lbl.
+
+is_merge_allowed(_, _, #b_blk{is=[#b_set{op=peek_message}|_]}) ->
+ false;
+is_merge_allowed(L, Blk0, #b_blk{}) ->
+ case beam_ssa:successors(Blk0) of
+ [L] -> true;
+ [_|_] -> false
+ end.
+
+%%%
+%%% When a tuple is matched, the pattern matching compiler generates a
+%%% get_tuple_element instruction for every tuple element that will
+%%% ever be used in the rest of the function. That often forces the
+%%% extracted tuple elements to be stored in Y registers until it's
+%%% time to use them. It could also mean that there could be execution
+%%% paths that will never use the extracted elements.
+%%%
+%%% This optimization will sink get_tuple_element instructions, that
+%%% is, move them forward in the execution stream to the last possible
+%%% block there they will still dominate all uses. That may reduce the
+%%% size of stack frames, reduce register shuffling, and avoid
+%%% extracting tuple elements on execution paths that never use the
+%%% extracted values.
+%%%
+
+ssa_opt_sink(#st{ssa=Blocks0}=St) ->
+ Linear = beam_ssa:linearize(Blocks0),
+
+ %% Create a map with all variables that define get_tuple_element
+ %% instructions. The variable name map to the block it is defined in.
+ Defs = maps:from_list(def_blocks(Linear)),
+
+ %% Now find all the blocks that use variables defined by get_tuple_element
+ %% instructions.
+ Used = used_blocks(Linear, Defs, []),
+
+ %% Calculate dominators.
+ Dom0 = beam_ssa:dominators(Blocks0),
+
+ %% It is not safe to move get_tuple_element instructions to blocks
+ %% that begin with certain instructions. It is also unsafe to move
+ %% the instructions into any part of a receive. To avoid such
+ %% unsafe moves, pretend that the unsuitable blocks are not
+ %% dominators.
+ Unsuitable = unsuitable(Linear, Blocks0),
+ Dom = case gb_sets:is_empty(Unsuitable) of
+ true ->
+ Dom0;
+ false ->
+ F = fun(_, DomBy) ->
+ [L || L <- DomBy,
+ not gb_sets:is_element(L, Unsuitable)]
+ end,
+ maps:map(F, Dom0)
+ end,
+
+ %% Calculate new positions for get_tuple_element instructions. The new
+ %% position is a block that dominates all uses of the variable.
+ DefLoc = new_def_locations(Used, Defs, Dom),
+
+ %% Now move all suitable get_tuple_element instructions to their
+ %% new blocks.
+ Blocks = foldl(fun({V,To}, A) ->
+ From = maps:get(V, Defs),
+ move_defs(V, From, To, A)
+ end, Blocks0, DefLoc),
+ St#st{ssa=Blocks}.
+
+def_blocks([{L,#b_blk{is=Is}}|Bs]) ->
+ def_blocks_is(Is, L, def_blocks(Bs));
+def_blocks([]) -> [].
+
+def_blocks_is([#b_set{op=get_tuple_element,dst=Dst}|Is], L, Acc) ->
+ def_blocks_is(Is, L, [{Dst,L}|Acc]);
+def_blocks_is([_|Is], L, Acc) ->
+ def_blocks_is(Is, L, Acc);
+def_blocks_is([], _, Acc) -> Acc.
+
+used_blocks([{L,Blk}|Bs], Def, Acc0) ->
+ Used = beam_ssa:used(Blk),
+ Acc = [{V,L} || V <- Used, maps:is_key(V, Def)] ++ Acc0,
+ used_blocks(Bs, Def, Acc);
+used_blocks([], _Def, Acc) ->
+ rel2fam(Acc).
+
+%% unsuitable(Linear, Blocks) -> Unsuitable.
+%% Return an ordset of block labels for the blocks that are not
+%% suitable for sinking of get_tuple_element instructions.
+
+unsuitable(Linear, Blocks) ->
+ Predecessors = beam_ssa:predecessors(Blocks),
+ Unsuitable0 = unsuitable_1(Linear),
+ Unsuitable1 = unsuitable_recv(Linear, Blocks, Predecessors),
+ gb_sets:from_list(Unsuitable0 ++ Unsuitable1).
+
+unsuitable_1([{L,#b_blk{is=[#b_set{op=Op}|_]}}|Bs]) ->
+ Unsuitable = case Op of
+ bs_extract -> true;
+ bs_put -> true;
+ {float,_} -> true;
+ landingpad -> true;
+ peek_message -> true;
+ wait_timeout -> true;
+ _ -> false
+ end,
+ case Unsuitable of
+ true ->
+ [L|unsuitable_1(Bs)];
+ false ->
+ unsuitable_1(Bs)
+ end;
+unsuitable_1([{_,#b_blk{}}|Bs]) ->
+ unsuitable_1(Bs);
+unsuitable_1([]) -> [].
+
+unsuitable_recv([{L,#b_blk{is=[#b_set{op=Op}|_]}}|Bs], Blocks, Predecessors) ->
+ Ls = case Op of
+ remove_message ->
+ unsuitable_loop(L, Blocks, Predecessors);
+ recv_next ->
+ unsuitable_loop(L, Blocks, Predecessors);
+ _ ->
+ []
+ end,
+ Ls ++ unsuitable_recv(Bs, Blocks, Predecessors);
+unsuitable_recv([_|Bs], Blocks, Predecessors) ->
+ unsuitable_recv(Bs, Blocks, Predecessors);
+unsuitable_recv([], _, _) -> [].
+
+unsuitable_loop(L, Blocks, Predecessors) ->
+ unsuitable_loop(L, Blocks, Predecessors, []).
+
+unsuitable_loop(L, Blocks, Predecessors, Acc) ->
+ Ps = maps:get(L, Predecessors),
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc).
+
+unsuitable_loop_1([P|Ps], Blocks, Predecessors, Acc0) ->
+ case maps:get(P, Blocks) of
+ #b_blk{is=[#b_set{op=peek_message}|_]} ->
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc0);
+ #b_blk{} ->
+ case ordsets:is_element(P, Acc0) of
+ false ->
+ Acc1 = ordsets:add_element(P, Acc0),
+ Acc = unsuitable_loop(P, Blocks, Predecessors, Acc1),
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc);
+ true ->
+ unsuitable_loop_1(Ps, Blocks, Predecessors, Acc0)
+ end
+ end;
+unsuitable_loop_1([], _, _, Acc) -> Acc.
+
+%% new_def_locations([{Variable,[UsedInBlock]}|Vs], Defs, Dominators) ->
+%% [{Variable,NewDefinitionBlock}]
+%% Calculate new locations for get_tuple_element instructions. For each
+%% variable, the new location is a block that dominates all uses of
+%% variable and as near to the uses of as possible. If no such block
+%% distinct from the block where the instruction currently is, the
+%% variable will not be included in the result list.
+
+new_def_locations([{V,UsedIn}|Vs], Defs, Dom) ->
+ DefIn = maps:get(V, Defs),
+ case common_dom(UsedIn, DefIn, Dom) of
+ [] ->
+ new_def_locations(Vs, Defs, Dom);
+ [_|_]=BetterDef ->
+ L = most_dominated(BetterDef, Dom),
+ [{V,L}|new_def_locations(Vs, Defs, Dom)]
+ end;
+new_def_locations([], _, _) -> [].
+
+common_dom([L|Ls], DefIn, Dom) ->
+ DomBy0 = maps:get(L, Dom),
+ DomBy = ordsets:subtract(DomBy0, maps:get(DefIn, Dom)),
+ common_dom_1(Ls, Dom, DomBy).
+
+common_dom_1(_, _, []) ->
+ [];
+common_dom_1([L|Ls], Dom, [_|_]=DomBy0) ->
+ DomBy1 = maps:get(L, Dom),
+ DomBy = ordsets:intersection(DomBy0, DomBy1),
+ common_dom_1(Ls, Dom, DomBy);
+common_dom_1([], _, DomBy) -> DomBy.
+
+most_dominated([L|Ls], Dom) ->
+ most_dominated(Ls, L, maps:get(L, Dom), Dom).
+
+most_dominated([L|Ls], L0, DomBy, Dom) ->
+ case member(L, DomBy) of
+ true ->
+ most_dominated(Ls, L0, DomBy, Dom);
+ false ->
+ most_dominated(Ls, L, maps:get(L, Dom), Dom)
+ end;
+most_dominated([], L, _, _) -> L.
+
+
+%% Move get_tuple_element instructions to their new locations.
+
+move_defs(V, From, To, Blocks) ->
+ #{From:=FromBlk0,To:=ToBlk0} = Blocks,
+ {Def,FromBlk} = remove_def(V, FromBlk0),
+ try insert_def(V, Def, ToBlk0) of
+ ToBlk ->
+ %%io:format("~p: ~p => ~p\n", [V,From,To]),
+ Blocks#{From:=FromBlk,To:=ToBlk}
+ catch
+ throw:not_possible ->
+ Blocks
+ end.
+
+remove_def(V, #b_blk{is=Is0}=Blk) ->
+ {Def,Is} = remove_def_is(Is0, V, []),
+ {Def,Blk#b_blk{is=Is}}.
+
+remove_def_is([#b_set{dst=Dst}=Def|Is], Dst, Acc) ->
+ {Def,reverse(Acc, Is)};
+remove_def_is([I|Is], Dst, Acc) ->
+ remove_def_is(Is, Dst, [I|Acc]).
+
+insert_def(V, Def, #b_blk{is=Is0}=Blk) ->
+ Is = insert_def_is(Is0, V, Def),
+ Blk#b_blk{is=Is}.
+
+insert_def_is([#b_set{op=phi}=I|Is], V, Def) ->
+ case member(V, beam_ssa:used(I)) of
+ true ->
+ throw(not_possible);
+ false ->
+ [I|insert_def_is(Is, V, Def)]
+ end;
+insert_def_is([#b_set{op=Op}=I|Is]=Is0, V, Def) ->
+ Action0 = case Op of
+ call -> beyond;
+ 'catch_end' -> beyond;
+ set_tuple_element -> beyond;
+ timeout -> beyond;
+ _ -> here
+ end,
+ Action = case Is of
+ [#b_set{op=succeeded}|_] -> here;
+ _ -> Action0
+ end,
+ case Action of
+ beyond ->
+ case member(V, beam_ssa:used(I)) of
+ true ->
+ %% The variable is used by this instruction. We must
+ %% place the definition before this instruction.
+ [Def|Is0];
+ false ->
+ %% Place it beyond the current instruction.
+ [I|insert_def_is(Is, V, Def)]
+ end;
+ here ->
+ [Def|Is0]
+ end;
+insert_def_is([], _V, Def) ->
+ [Def].
+
+
+%%%
+%%% Common utilities.
+%%%
+
+gcd(A, B) ->
+ case A rem B of
+ 0 -> B;
+ X -> gcd(B, X)
+ end.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
+
+sub(I, Sub) ->
+ beam_ssa:normalize(sub_1(I, Sub)).
+
+sub_1(#b_set{op=phi,args=Args}=I, Sub) ->
+ I#b_set{args=[{sub_arg(A, Sub),P} || {A,P} <- Args]};
+sub_1(#b_set{args=Args}=I, Sub) ->
+ I#b_set{args=[sub_arg(A, Sub) || A <- Args]};
+sub_1(#b_br{bool=#b_var{}=Old}=Br, Sub) ->
+ New = sub_arg(Old, Sub),
+ Br#b_br{bool=New};
+sub_1(#b_switch{arg=#b_var{}=Old}=Sw, Sub) ->
+ New = sub_arg(Old, Sub),
+ Sw#b_switch{arg=New};
+sub_1(#b_ret{arg=#b_var{}=Old}=Ret, Sub) ->
+ New = sub_arg(Old, Sub),
+ Ret#b_ret{arg=New};
+sub_1(Last, _) -> Last.
+
+sub_arg(#b_remote{mod=Mod,name=Name}=Rem, Sub) ->
+ Rem#b_remote{mod=sub_arg(Mod, Sub),name=sub_arg(Name, Sub)};
+sub_arg(Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end.
diff --git a/lib/compiler/src/beam_ssa_pp.erl b/lib/compiler/src/beam_ssa_pp.erl
new file mode 100644
index 0000000000..34ac08b32e
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_pp.erl
@@ -0,0 +1,238 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_ssa_pp).
+
+-export([format_function/1,format_instr/1,format_var/1]).
+
+-include("beam_ssa.hrl").
+
+-spec format_function(beam_ssa:b_function()) -> iolist().
+
+format_function(#b_function{anno=Anno0,args=Args,
+ bs=Blocks,cnt=Counter}) ->
+ #{func_info:={M,F,_}} = Anno0,
+ Anno = maps:without([func_info,location,live_intervals,registers], Anno0),
+ FuncAnno = case Anno0 of
+ #{live_intervals:=Intervals} ->
+ Anno0#{live_intervals:=maps:from_list(Intervals)};
+ #{} ->
+ Anno0
+ end,
+ ReachableBlocks = beam_ssa:rpo(Blocks),
+ All = maps:keys(Blocks),
+ Unreachable = ordsets:subtract(ordsets:from_list(All),
+ ordsets:from_list(ReachableBlocks)),
+ [case Anno0 of
+ #{location:={Filename,Line}} ->
+ io_lib:format("%% ~ts:~p\n", [Filename,Line]);
+ #{} ->
+ []
+ end,
+ io_lib:format("%% Counter = ~p\n", [Counter]),
+ [format_anno(Key, Value) ||
+ {Key,Value} <- lists:sort(maps:to_list(Anno))],
+ io_lib:format("function ~p:~p(~ts) {\n", [M,F,format_args(Args, FuncAnno)]),
+ [format_live_interval(Var, FuncAnno) || Var <- Args],
+ format_blocks(ReachableBlocks, Blocks, FuncAnno),
+ case Unreachable of
+ [] ->
+ [];
+ [_|_] ->
+ ["\n%% Unreachable blocks\n\n",
+ format_blocks(Unreachable, Blocks, FuncAnno)]
+ end,
+
+ "}\n"].
+
+
+-spec format_instr(beam_ssa:b_set()) -> iolist().
+
+format_instr(#b_set{}=I) ->
+ Cs = lists:flatten(format_instr(I#b_set{anno=#{}}, #{}, true)),
+ string:trim(Cs, leading);
+format_instr(I0) ->
+ I = setelement(2, I0, #{}),
+ Cs = lists:flatten(format_terminator(I, #{})),
+ string:trim(Cs, both).
+
+-spec format_var(beam_ssa:b_var()) -> iolist().
+
+format_var(V) ->
+ Cs = lists:flatten(format_var(V, #{})),
+ string:trim(Cs, leading).
+
+%%%
+%%% Local functions.
+%%%
+
+format_anno(Key, Map) when is_map(Map) ->
+ Sorted = lists:sort(maps:to_list(Map)),
+ [io_lib:format("%% ~s:\n", [Key]),
+ [io_lib:format("%% ~w => ~w\n", [K,V]) || {K,V} <- Sorted]];
+format_anno(Key, Value) ->
+ io_lib:format("%% ~s: ~p\n", [Key,Value]).
+
+format_blocks(Ls, Blocks, Anno) ->
+ PP = [format_block(L, Blocks, Anno) || L <- Ls],
+ lists:join($\n, PP).
+
+format_block(L, Blocks, FuncAnno) ->
+ #b_blk{anno=Anno,is=Is,last=Last} = maps:get(L, Blocks),
+ [case map_size(Anno) of
+ 0 -> [];
+ _ -> io_lib:format("%% ~p\n", [Anno])
+ end,
+ io_lib:format("~p:", [L]),
+ format_instrs(Is, FuncAnno, true),
+ $\n,
+ format_terminator(Last, FuncAnno)].
+
+format_instrs([I|Is], FuncAnno, First) ->
+ [$\n,
+ format_instr(I, FuncAnno, First),
+ format_instrs(Is, FuncAnno, false)];
+format_instrs([], _FuncAnno, _First) ->
+ [].
+
+format_instr(#b_set{anno=Anno,op=Op,dst=Dst,args=Args},
+ FuncAnno, First) ->
+ AnnoStr = format_anno(Anno),
+ LiveIntervalStr = format_live_interval(Dst, FuncAnno),
+ [if
+ First ->
+ [];
+ AnnoStr =/= []; LiveIntervalStr =/= [] ->
+ $\n;
+ true ->
+ []
+ end,
+ AnnoStr,
+ LiveIntervalStr,
+ io_lib:format(" ~s~ts = ~ts", [format_i_number(Anno),
+ format_var(Dst, FuncAnno),
+ format_op(Op)]),
+ case Args of
+ [] ->
+ [];
+ [_|_] ->
+ io_lib:format(" ~ts", [format_args(Args, FuncAnno)])
+ end].
+
+format_i_number(#{n:=N}) ->
+ io_lib:format("[~p] ", [N]);
+format_i_number(#{}) -> [].
+
+format_terminator(#b_br{anno=A,bool=#b_literal{val=true},succ=Lbl}, _) ->
+ io_lib:format(" ~sbr label ~p\n", [format_i_number(A),Lbl]);
+format_terminator(#b_br{anno=A,bool=#b_literal{val=false},fail=Lbl}, _) ->
+ io_lib:format(" ~sbr label ~p\n", [format_i_number(A),Lbl]);
+format_terminator(#b_br{anno=A,bool=Bool,succ=Succ,fail=Fail}, FuncAnno) ->
+ io_lib:format(" ~sbr ~ts, label ~p, label ~p\n",
+ [format_i_number(A),format_arg(Bool, FuncAnno),Succ,Fail]);
+format_terminator(#b_switch{anno=A,arg=Arg,fail=Fail,list=List}, FuncAnno) ->
+ io_lib:format(" ~sswitch ~ts, label ~p, ~ts\n",
+ [format_i_number(A),format_arg(Arg, FuncAnno),Fail,
+ format_list(List,FuncAnno)]);
+format_terminator(#b_ret{anno=A,arg=Arg}, FuncAnno) ->
+ io_lib:format(" ~sret ~ts\n", [format_i_number(A),format_arg(Arg, FuncAnno)]).
+
+format_op({Prefix,Name}) ->
+ io_lib:format("~p:~p", [Prefix,Name]);
+format_op(Name) ->
+ io_lib:format("~p", [Name]).
+
+format_register(#b_var{}=V, #{registers:=Regs}) ->
+ {Tag,N} = maps:get(V, Regs),
+ io_lib:format("~p~p", [Tag,N]);
+format_register(_, #{}) -> "".
+
+format_var(Var, FuncAnno) ->
+ VarString = format_var_1(Var),
+ case format_register(Var, FuncAnno) of
+ [] -> VarString;
+ [_|_]=Reg -> [Reg,$/,VarString]
+ end.
+
+format_var_1(#b_var{name={Name,Uniq}}) ->
+ if
+ is_atom(Name) ->
+ io_lib:format("~ts:~p", [Name,Uniq]);
+ is_integer(Name) ->
+ io_lib:format("_~p:~p", [Name,Uniq])
+ end;
+format_var_1(#b_var{name=Name}) when is_atom(Name) ->
+ atom_to_list(Name);
+format_var_1(#b_var{name=Name}) when is_integer(Name) ->
+ "_"++integer_to_list(Name).
+
+format_args(Args, FuncAnno) ->
+ Ss = [format_arg(Arg, FuncAnno) || Arg <- Args],
+ lists:join(", ", Ss).
+
+format_arg(#b_var{}=Arg, FuncAnno) ->
+ format_var(Arg, FuncAnno);
+format_arg(#b_literal{val=Val}, _FuncAnno) ->
+ io_lib:format("literal ~p", [Val]);
+format_arg(#b_remote{mod=Mod,name=Name,arity=Arity}, FuncAnno) ->
+ io_lib:format("remote (~ts):(~ts)/~p",
+ [format_arg(Mod, FuncAnno),format_arg(Name, FuncAnno),Arity]);
+format_arg(#b_local{name=Name,arity=Arity}, FuncAnno) ->
+ io_lib:format("local ~ts/~p", [format_arg(Name, FuncAnno),Arity]);
+format_arg({Value,Label}, FuncAnno) when is_integer(Label) ->
+ io_lib:format("{ ~ts, ~p }", [format_arg(Value, FuncAnno),Label]);
+format_arg(Other, _) ->
+ io_lib:format("*** ~p ***", [Other]).
+
+format_list(List, FuncAnno) ->
+ Ss = [io_lib:format("{ ~ts, ~ts }", [format_arg(Val, FuncAnno),format_label(L)]) ||
+ {Val,L} <- List],
+ io_lib:format("[ ~ts ]", [lists:join(", ", Ss)]).
+
+format_label(L) ->
+ ["label ",integer_to_list(L)].
+
+format_anno(#{n:=_}=Anno) ->
+ format_anno(maps:remove(n, Anno));
+format_anno(#{location:={File,Line}}=Anno0) ->
+ Anno = maps:remove(location, Anno0),
+ [io_lib:format(" %% ~ts:~p\n", [File,Line])|format_anno_1(Anno)];
+format_anno(Anno) ->
+ format_anno_1(Anno).
+
+format_anno_1(Anno) ->
+ case map_size(Anno) of
+ 0 ->
+ [];
+ _ ->
+ [io_lib:format(" %% Anno: ~p\n", [Anno])]
+ end.
+
+format_live_interval(#b_var{}=Dst, #{live_intervals:=Intervals}) ->
+ case Intervals of
+ #{Dst:=Rs0} ->
+ Rs1 = [io_lib:format("~p..~p", [Start,End]) ||
+ {Start,End} <- Rs0],
+ Rs = lists:join(" ", Rs1),
+ io_lib:format(" %% ~ts: ~s\n", [format_var_1(Dst),Rs]);
+ #{} ->
+ []
+ end;
+format_live_interval(_, _) -> [].
+
diff --git a/lib/compiler/src/beam_ssa_pre_codegen.erl b/lib/compiler/src/beam_ssa_pre_codegen.erl
new file mode 100644
index 0000000000..9175931375
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_pre_codegen.erl
@@ -0,0 +1,2496 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Purpose: Prepare for code generation, including register allocation.
+%%
+%% The output of this compiler pass is still in the SSA format, but
+%% it has been annotated and transformed to help the code generator.
+%%
+%% * Some instructions are translated to other instructions closer to
+%% the BEAM instructions. For example, the binary matching
+%% instructions are transformed from the optimization-friendly
+%% internal format to instruction more similar to the actual BEAM
+%% instructions.
+%%
+%% * Blocks that will need an instruction for allocating a stack frame
+%% are annotated with a {frame_size,Size} annotation.
+%%
+%% * 'copy' instructions are added for all variables that need
+%% to be saved to the stack frame. Additional 'copy' instructions
+%% can be added as an optimization to reuse y registers (see
+%% the copy_retval sub pass).
+%%
+%% * Each function is annotated with a {register,RegisterMap}
+%% annotation that maps each variable to a BEAM register. The linear
+%% scan algorithm is used to allocate registers.
+%%
+%% There are four kind of registers. x, y, fr (floating point register),
+%% and z. A variable will be allocated to a z register if it is only
+%% used by the instruction following the instruction that defines the
+%% the variable. The code generator will typically combine those
+%% instructions to a test instruction. z registers are also used for
+%% some instructions that don't have a return value.
+%%
+%% References:
+%%
+%% [1] H. Mössenböck and M. Pfeiffer. Linear scan register allocation
+%% in the context of SSA form and register constraints. In Proceedings
+%% of the International Conference on Compiler Construction, pages
+%% 229–246. LNCS 2304, Springer-Verlag, 2002.
+%%
+%% [2] C. Wimmer and H. Mössenböck. Optimized interval splitting in a
+%% linear scan register allocator. In Proceedings of the ACM/USENIX
+%% International Conference on Virtual Execution Environments, pages
+%% 132–141. ACM Press, 2005.
+%%
+%% [3] C. Wimmer and M. Franz. Linear Scan Register Allocation on SSA
+%% Form. In Proceedings of the International Symposium on Code
+%% Generation and Optimization, pages 170-179. ACM Press, 2010.
+%%
+
+-module(beam_ssa_pre_codegen).
+
+-export([module/2]).
+
+-include("beam_ssa.hrl").
+
+-import(lists, [all/2,any/2,append/1,duplicate/2,
+ foldl/3,last/1,map/2,member/2,partition/2,
+ reverse/1,reverse/2,sort/1,zip/2]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, Opts) ->
+ UseBSM3 = not proplists:get_bool(no_bsm3, Opts),
+ Ps = passes(Opts),
+ Fs = functions(Fs0, Ps, UseBSM3),
+ {ok,Module#b_module{body=Fs}}.
+
+functions([F|Fs], Ps, UseBSM3) ->
+ [function(F, Ps, UseBSM3)|functions(Fs, Ps, UseBSM3)];
+functions([], _Ps, _UseBSM3) -> [].
+
+-type b_var() :: beam_ssa:b_var().
+-type var_name() :: beam_ssa:var_name().
+-type instr_number() :: pos_integer().
+-type range() :: {instr_number(),instr_number()}.
+-type reg_num() :: beam_asm:reg_num().
+-type xreg() :: {'x',reg_num()}.
+-type yreg() :: {'y',reg_num()}.
+-type ypool() :: {'y',beam_ssa:label()}.
+-type reservation() :: 'fr' | {'prefer',xreg()} | 'x' | {'x',xreg()} |
+ ypool() | {yreg(),ypool()} | 'z'.
+-type ssa_register() :: beam_ssa_codegen:ssa_register().
+
+-define(TC(Body), tc(fun() -> Body end, ?FILE, ?LINE)).
+-record(st, {ssa :: beam_ssa:block_map(),
+ args :: [b_var()],
+ cnt :: beam_ssa:label(),
+ use_bsm3 :: boolean(),
+ frames=[] :: [beam_ssa:label()],
+ intervals=[] :: [{b_var(),[range()]}],
+ res=[] :: [{b_var(),reservation()}] | #{b_var():=reservation()},
+ regs=#{} :: #{b_var():=ssa_register()},
+ extra_annos=[] :: [{atom(),term()}]
+ }).
+-define(PASS(N), {N,fun N/1}).
+
+passes(Opts) ->
+ AddPrecgAnnos = proplists:get_bool(dprecg, Opts),
+ FixTuples = proplists:get_bool(no_put_tuple2, Opts),
+ Ps = [?PASS(assert_no_critical_edges),
+
+ %% Preliminaries.
+ ?PASS(fix_bs),
+ ?PASS(sanitize),
+ case FixTuples of
+ false -> ignore;
+ true -> ?PASS(fix_tuples)
+ end,
+ ?PASS(place_frames),
+ ?PASS(fix_receives),
+
+ %% Find and reserve Y registers.
+ ?PASS(find_yregs),
+ ?PASS(reserve_yregs),
+
+ %% Handle legacy binary match instruction that don't
+ %% accept a Y register as destination.
+ ?PASS(legacy_bs),
+
+ %% Improve reuse of Y registers to potentially
+ %% reduce the size of the stack frame.
+ ?PASS(copy_retval),
+ ?PASS(opt_get_list),
+
+ %% Calculate live intervals.
+ ?PASS(number_instructions),
+ ?PASS(live_intervals),
+ ?PASS(reserve_regs),
+
+ %% If needed for a .precg file, save the live intervals
+ %% so they can be included in an annotation.
+ case AddPrecgAnnos of
+ false -> ignore;
+ true -> ?PASS(save_live_intervals)
+ end,
+
+ %% Allocate registers.
+ ?PASS(linear_scan),
+ ?PASS(frame_size),
+ ?PASS(turn_yregs)],
+ [P || P <- Ps, P =/= ignore].
+
+function(#b_function{anno=Anno,args=Args,bs=Blocks0,cnt=Count0}=F0,
+ Ps, UseBSM3) ->
+ try
+ St0 = #st{ssa=Blocks0,args=Args,use_bsm3=UseBSM3,cnt=Count0},
+ St = compile:run_sub_passes(Ps, St0),
+ #st{ssa=Blocks,cnt=Count,regs=Regs,extra_annos=ExtraAnnos} = St,
+ F1 = add_extra_annos(F0, ExtraAnnos),
+ F = beam_ssa:add_anno(registers, Regs, F1),
+ F#b_function{bs=Blocks,cnt=Count}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+save_live_intervals(#st{intervals=Intervals}=St) ->
+ St#st{extra_annos=[{live_intervals,Intervals}]}.
+
+%% Add extra annotations when a .precg listing file is being produced.
+add_extra_annos(F, Annos) ->
+ foldl(fun({Name,Value}, Acc) ->
+ beam_ssa:add_anno(Name, Value, Acc)
+ end, F, Annos).
+
+%% assert_no_critical_edges(St0) -> St.
+%% The code generator will not work if there are critial edges.
+%% Abort if any critical edges are found.
+
+assert_no_critical_edges(#st{ssa=Blocks}=St) ->
+ F = fun assert_no_ces/3,
+ beam_ssa:fold_rpo(F, Blocks, Blocks),
+ St.
+
+assert_no_ces(_, #b_blk{is=[#b_set{op=phi,args=[_,_]=Phis}|_]}, Blocks) ->
+ %% This block has multiple predecessors. Make sure that none
+ %% of the precessors have more than one successor.
+ true = all(fun({_,P}) ->
+ length(beam_ssa:successors(P, Blocks)) =:= 1
+ end, Phis), %Assertion.
+ Blocks;
+assert_no_ces(_, _, Blocks) -> Blocks.
+
+%% fix_bs(St0) -> St.
+%% Fix up the binary matching instructions:
+%%
+%% * Insert bs_save and bs_restore instructions where needed.
+%%
+%% * Combine bs_match and bs_extract instructions to bs_get
+%% instructions.
+
+fix_bs(#st{ssa=Blocks,cnt=Count0,use_bsm3=UseBSM3}=St) ->
+ F = fun(#b_set{op=bs_start_match,dst=Dst}, A) ->
+ %% Mark the root of the match context list.
+ [{Dst,{context,Dst}}|A];
+ (#b_set{op=bs_match,dst=Dst,args=[_,ParentCtx|_]}, A) ->
+ %% Link this match context the previous match context.
+ [{Dst,ParentCtx}|A];
+ (_, A) ->
+ A
+ end,
+ case beam_ssa:fold_instrs_rpo(F, [0], [],Blocks) of
+ [] ->
+ %% No binary matching in this function.
+ St;
+ [_|_]=M ->
+ CtxChain = maps:from_list(M),
+ Linear0 = beam_ssa:linearize(Blocks),
+
+ %% Insert position instructions where needed.
+ {Linear1,Count} = case UseBSM3 of
+ true ->
+ bs_pos_bsm3(Linear0, CtxChain, Count0);
+ false ->
+ bs_pos_bsm2(Linear0, CtxChain, Count0)
+ end,
+
+ %% Rename instructions.
+ Linear = bs_instrs(Linear1, CtxChain, []),
+
+ St#st{ssa=maps:from_list(Linear),cnt=Count}
+ end.
+
+%% Insert bs_get_position and bs_set_position instructions as needed.
+bs_pos_bsm3(Linear0, CtxChain, Count0) ->
+ Rs0 = bs_restores(Linear0, CtxChain, #{}, #{}),
+ Rs = maps:values(Rs0),
+ S0 = sofs:relation(Rs, [{context,save_point}]),
+ S1 = sofs:relation_to_family(S0),
+ S = sofs:to_external(S1),
+
+ {SavePoints,Count1} = make_bs_pos_dict(S, Count0, []),
+ {Gets,Count2} = make_bs_setpos_map(Rs, SavePoints, Count1, []),
+ {Sets,Count} = make_bs_getpos_map(maps:to_list(Rs0), SavePoints, Count2, []),
+
+ %% Now insert all saves and restores.
+ {bs_insert_bsm3(Linear0, Gets, Sets, SavePoints),Count}.
+
+make_bs_setpos_map([{Ctx,Save}=Ps|T], SavePoints, Count, Acc) ->
+ SavePoint = get_savepoint(Ps, SavePoints),
+ I = #b_set{op=bs_get_position,dst=SavePoint,args=[Ctx]},
+ make_bs_setpos_map(T, SavePoints, Count+1, [{Save,I}|Acc]);
+make_bs_setpos_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_bs_getpos_map([{Bef,{Ctx,_}=Ps}|T], SavePoints, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ Args = [Ctx, get_savepoint(Ps, SavePoints)],
+ I = #b_set{op=bs_set_position,dst=Ignored,args=Args},
+ make_bs_getpos_map(T, SavePoints, Count+1, [{Bef,I}|Acc]);
+make_bs_getpos_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+get_savepoint({_,_}=Ps, SavePoints) ->
+ Name = {'@ssa_bs_position', maps:get(Ps, SavePoints)},
+ #b_var{name=Name}.
+
+make_bs_pos_dict([{Ctx,Pts}|T], Count0, Acc0) ->
+ {Acc, Count} = make_bs_pos_dict_1(Pts, Ctx, Count0, Acc0),
+ make_bs_pos_dict(T, Count, Acc);
+make_bs_pos_dict([], Count, Acc) ->
+ {maps:from_list(Acc), Count}.
+
+make_bs_pos_dict_1([H|T], Ctx, I, Acc) ->
+ make_bs_pos_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
+make_bs_pos_dict_1([], Ctx, I, Acc) ->
+ {[{Ctx,I}|Acc], I}.
+
+%% As bs_position but without OTP-22 instructions. This is only used when
+%% cross-compiling to older versions.
+bs_pos_bsm2(Linear0, CtxChain, Count0) ->
+ Rs0 = bs_restores(Linear0, CtxChain, #{}, #{}),
+ Rs = maps:values(Rs0),
+ S0 = sofs:relation(Rs, [{context,save_point}]),
+ S1 = sofs:relation_to_family(S0),
+ S = sofs:to_external(S1),
+ Slots = make_save_point_dict(S, []),
+ {Saves,Count1} = make_save_map(Rs, Slots, Count0, []),
+ {Restores,Count} = make_restore_map(maps:to_list(Rs0), Slots, Count1, []),
+
+ %% Now insert all saves and restores.
+ {bs_insert_bsm2(Linear0, Saves, Restores, Slots),Count}.
+
+make_save_map([{Ctx,Save}=Ps|T], Slots, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ case make_slot(Ps, Slots) of
+ #b_literal{val=start} ->
+ make_save_map(T, Slots, Count, Acc);
+ Slot ->
+ I = #b_set{op=bs_save,dst=Ignored,args=[Ctx,Slot]},
+ make_save_map(T, Slots, Count+1, [{Save,I}|Acc])
+ end;
+make_save_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_restore_map([{Bef,{Ctx,_}=Ps}|T], Slots, Count, Acc) ->
+ Ignored = #b_var{name={'@ssa_ignored',Count}},
+ I = #b_set{op=bs_restore,dst=Ignored,args=[Ctx,make_slot(Ps, Slots)]},
+ make_restore_map(T, Slots, Count+1, [{Bef,I}|Acc]);
+make_restore_map([], _, Count, Acc) ->
+ {maps:from_list(Acc),Count}.
+
+make_slot({Same,Same}, _Slots) ->
+ #b_literal{val=start};
+make_slot({_,_}=Ps, Slots) ->
+ #b_literal{val=maps:get(Ps, Slots)}.
+
+make_save_point_dict([{Ctx,Pts}|T], Acc0) ->
+ Acc = make_save_point_dict_1(Pts, Ctx, 0, Acc0),
+ make_save_point_dict(T, Acc);
+make_save_point_dict([], Acc) ->
+ maps:from_list(Acc).
+
+make_save_point_dict_1([Ctx|T], Ctx, I, Acc) ->
+ %% Special {atom,start} save point. Does not need a
+ %% bs_save instruction.
+ make_save_point_dict_1(T, Ctx, I, Acc);
+make_save_point_dict_1([H|T], Ctx, I, Acc) ->
+ make_save_point_dict_1(T, Ctx, I+1, [{{Ctx,H},I}|Acc]);
+make_save_point_dict_1([], Ctx, I, Acc) ->
+ [{Ctx,I}|Acc].
+
+bs_restores([{L,#b_blk{is=Is,last=Last}}|Bs], CtxChain, D0, Rs0) ->
+ FPos = case D0 of
+ #{L:=Pos0} -> Pos0;
+ #{} -> #{}
+ end,
+ {SPos,Rs} = bs_restores_is(Is, CtxChain, FPos, Rs0),
+ D = bs_update_successors(Last, SPos, FPos, D0),
+ bs_restores(Bs, CtxChain, D, Rs);
+bs_restores([], _, _, Rs) -> Rs.
+
+bs_update_successors(#b_br{succ=Succ,fail=Fail}, SPos, FPos, D) ->
+ join_positions([{Succ,SPos},{Fail,FPos}], D);
+bs_update_successors(#b_switch{fail=Fail,list=List}, SPos, _FPos, D) ->
+ Update = [{L,SPos} || {_,L} <- List] ++ [{Fail,SPos}],
+ join_positions(Update, D);
+bs_update_successors(#b_ret{}, _, _, D) -> D.
+
+join_positions([{L,MapPos0}|T], D) ->
+ case D of
+ #{L:=MapPos0} ->
+ %% Same map.
+ join_positions(T, D);
+ #{L:=MapPos1} ->
+ %% Different maps.
+ MapPos = join_positions_1(MapPos0, MapPos1),
+ join_positions(T, D#{L:=MapPos});
+ #{} ->
+ join_positions(T, D#{L=>MapPos0})
+ end;
+join_positions([], D) -> D.
+
+join_positions_1(MapPos0, MapPos1) ->
+ MapPos2 = maps:map(fun(Start, Pos) ->
+ case MapPos0 of
+ #{Start:=Pos} -> Pos;
+ #{Start:=_} -> unknown;
+ #{} -> Pos
+ end
+ end, MapPos1),
+ maps:merge(MapPos0, MapPos2).
+
+bs_restores_is([#b_set{op=bs_start_match,dst=Start}|Is],
+ CtxChain, PosMap0, Rs) ->
+ PosMap = PosMap0#{Start=>Start},
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([#b_set{op=bs_match,dst=NewPos,args=Args}=I|Is],
+ CtxChain, PosMap0, Rs0) ->
+ Start = bs_subst_ctx(NewPos, CtxChain),
+ [_,FromPos|_] = Args,
+ case PosMap0 of
+ #{Start:=FromPos} ->
+ %% Same position, no restore needed.
+ PosMap = case bs_match_type(I) of
+ plain ->
+ %% Update position to new position.
+ PosMap0#{Start:=NewPos};
+ _ ->
+ %% Position will not change (test_unit
+ %% instruction or no instruction at
+ %% all).
+ PosMap0#{Start:=FromPos}
+ end,
+ bs_restores_is(Is, CtxChain, PosMap, Rs0);
+ #{Start:=_} ->
+ %% Different positions, might need a restore instruction.
+ case bs_match_type(I) of
+ none ->
+ %% The tail test will be optimized away.
+ %% No need to do a restore.
+ PosMap = PosMap0#{Start:=FromPos},
+ bs_restores_is(Is, CtxChain, PosMap, Rs0);
+ test_unit ->
+ %% This match instruction will be replaced by
+ %% a test_unit instruction. We will need a
+ %% restore. The new position will be the position
+ %% restored to (NOT NewPos).
+ PosMap = PosMap0#{Start:=FromPos},
+ Rs = Rs0#{NewPos=>{Start,FromPos}},
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+ plain ->
+ %% Match or skip. Position will be changed.
+ PosMap = PosMap0#{Start:=NewPos},
+ Rs = Rs0#{NewPos=>{Start,FromPos}},
+ bs_restores_is(Is, CtxChain, PosMap, Rs)
+ end
+ end;
+bs_restores_is([#b_set{op=bs_extract,args=[FromPos|_]}|Is],
+ CtxChain, PosMap, Rs) ->
+ Start = bs_subst_ctx(FromPos, CtxChain),
+ #{Start:=FromPos} = PosMap, %Assertion.
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([#b_set{op=call,dst=Dst,args=Args}|Is],
+ CtxChain, PosMap0, Rs0) ->
+ {Rs,PosMap1} = bs_restore_args(Args, PosMap0, CtxChain, Dst, Rs0),
+ PosMap = bs_invalidate_pos(Args, PosMap1, CtxChain),
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([#b_set{op=landingpad}|Is], CtxChain, PosMap0, Rs) ->
+ %% We can land here from any point, so all positions are invalid.
+ PosMap = maps:map(fun(_Start,_Pos) -> unknown end, PosMap0),
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([#b_set{op=Op,dst=Dst,args=Args}|Is],
+ CtxChain, PosMap0, Rs0)
+ when Op =:= bs_test_tail;
+ Op =:= bs_get_tail ->
+ {Rs,PosMap} = bs_restore_args(Args, PosMap0, CtxChain, Dst, Rs0),
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([_|Is], CtxChain, PosMap, Rs) ->
+ bs_restores_is(Is, CtxChain, PosMap, Rs);
+bs_restores_is([], _CtxChain, PosMap, Rs) ->
+ {PosMap,Rs}.
+
+bs_match_type(#b_set{args=[#b_literal{val=skip},_Ctx,
+ #b_literal{val=binary},_Flags,
+ #b_literal{val=all},#b_literal{val=U}]}) ->
+ case U of
+ 1 -> none;
+ _ -> test_unit
+ end;
+bs_match_type(_) ->
+ plain.
+
+%% Call instructions leave the match position in an undefined state,
+%% requiring us to invalidate each affected argument.
+bs_invalidate_pos([#b_var{}=Arg|Args], PosMap0, CtxChain) ->
+ Start = bs_subst_ctx(Arg, CtxChain),
+ case PosMap0 of
+ #{Start:=_} ->
+ PosMap = PosMap0#{Start:=unknown},
+ bs_invalidate_pos(Args, PosMap, CtxChain);
+ #{} ->
+ %% Not a match context.
+ bs_invalidate_pos(Args, PosMap0, CtxChain)
+ end;
+bs_invalidate_pos([_|Args], PosMap, CtxChain) ->
+ bs_invalidate_pos(Args, PosMap, CtxChain);
+bs_invalidate_pos([], PosMap, _CtxChain) ->
+ PosMap.
+
+bs_restore_args([#b_var{}=Arg|Args], PosMap0, CtxChain, Dst, Rs0) ->
+ Start = bs_subst_ctx(Arg, CtxChain),
+ case PosMap0 of
+ #{Start:=Arg} ->
+ %% Same position, no restore needed.
+ bs_restore_args(Args, PosMap0, CtxChain, Dst, Rs0);
+ #{Start:=_} ->
+ %% Different positions, need a restore instruction.
+ PosMap = PosMap0#{Start:=Arg},
+ Rs = Rs0#{Dst=>{Start,Arg}},
+ bs_restore_args(Args, PosMap, CtxChain, Dst, Rs);
+ #{} ->
+ %% Not a match context.
+ bs_restore_args(Args, PosMap0, CtxChain, Dst, Rs0)
+ end;
+bs_restore_args([_|Args], PosMap, CtxChain, Dst, Rs) ->
+ bs_restore_args(Args, PosMap, CtxChain, Dst, Rs);
+bs_restore_args([], PosMap, _CtxChain, _Dst, Rs) ->
+ {Rs,PosMap}.
+
+%% Insert all bs_save and bs_restore instructions.
+
+bs_insert_bsm3(Blocks, Saves, Restores, SavePoints) ->
+ bs_insert_1(Blocks, Saves, Restores, SavePoints, fun(I) -> I end).
+
+bs_insert_bsm2(Blocks, Saves, Restores, SavePoints) ->
+ %% The old instructions require bs_start_match to be annotated with the
+ %% number of position slots it needs.
+ bs_insert_1(Blocks, Saves, Restores, SavePoints,
+ fun(#b_set{op=bs_start_match,dst=Dst}=I0) ->
+ NumSlots = case SavePoints of
+ #{Dst:=NumSlots0} -> NumSlots0;
+ #{} -> 0
+ end,
+ beam_ssa:add_anno(num_slots, NumSlots, I0);
+ (I) ->
+ I
+ end).
+
+bs_insert_1([{L,#b_blk{is=Is0}=Blk}|Bs0], Saves, Restores, Slots, XFrm) ->
+ Is = bs_insert_is_1(Is0, Restores, Slots, XFrm),
+ Bs = bs_insert_saves(Is, Bs0, Saves),
+ [{L,Blk#b_blk{is=Is}}|bs_insert_1(Bs, Saves, Restores, Slots, XFrm)];
+bs_insert_1([], _, _, _, _) -> [].
+
+bs_insert_is_1([#b_set{op=Op,dst=Dst}=I0|Is], Restores, SavePoints, XFrm) ->
+ I = XFrm(I0),
+ if
+ Op =:= bs_test_tail;
+ Op =:= bs_get_tail;
+ Op =:= bs_match;
+ Op =:= call ->
+ Rs = case Restores of
+ #{Dst:=R} -> [R];
+ #{} -> []
+ end,
+ Rs ++ [I|bs_insert_is_1(Is, Restores, SavePoints, XFrm)];
+ true ->
+ [I|bs_insert_is_1(Is, Restores, SavePoints, XFrm)]
+ end;
+bs_insert_is_1([], _, _, _) -> [].
+
+bs_insert_saves([#b_set{dst=Dst}|Is], Bs, Saves) ->
+ case Saves of
+ #{Dst:=S} ->
+ bs_insert_save(S, Bs);
+ #{} ->
+ bs_insert_saves(Is, Bs, Saves)
+ end;
+bs_insert_saves([], Bs, _) -> Bs.
+
+bs_insert_save(Save, [{L,#b_blk{is=Is0}=Blk}|Bs]) ->
+ Is = case Is0 of
+ [#b_set{op=bs_extract}=Ex|Is1] ->
+ [Ex,Save|Is1];
+ _ ->
+ [Save|Is0]
+ end,
+ [{L,Blk#b_blk{is=Is}}|Bs].
+
+%% Translate bs_match instructions to bs_get, bs_match_string,
+%% or bs_skip. Also rename match context variables to use the
+%% variable assigned to by the start_match instruction.
+
+bs_instrs([{L,#b_blk{is=Is0}=Blk}|Bs], CtxChain, Acc0) ->
+ case bs_instrs_is(Is0, CtxChain, []) of
+ [#b_set{op=bs_extract,dst=Dst,args=[Ctx]}|Is] ->
+ %% Drop this instruction. Rewrite the corresponding
+ %% bs_match instruction in the previous block to
+ %% a bs_get instruction.
+ Acc = bs_combine(Dst, Ctx, Acc0),
+ bs_instrs(Bs, CtxChain, [{L,Blk#b_blk{is=Is}}|Acc]);
+ Is ->
+ bs_instrs(Bs, CtxChain, [{L,Blk#b_blk{is=Is}}|Acc0])
+ end;
+bs_instrs([], _, Acc) ->
+ reverse(Acc).
+
+bs_instrs_is([#b_set{op=Op,args=Args0}=I0|Is], CtxChain, Acc) ->
+ Args = [bs_subst_ctx(A, CtxChain) || A <- Args0],
+ I1 = I0#b_set{args=Args},
+ I = case {Op,Args} of
+ {bs_match,[#b_literal{val=skip},Ctx,Type|As]} ->
+ I1#b_set{op=bs_skip,args=[Type,Ctx|As]};
+ {bs_match,[#b_literal{val=string},Ctx|As]} ->
+ I1#b_set{op=bs_match_string,args=[Ctx|As]};
+ {bs_get_tail,[Ctx|As]} ->
+ I1#b_set{op=bs_get_tail,args=[Ctx|As]};
+ {_,_} ->
+ I1
+ end,
+ bs_instrs_is(Is, CtxChain, [I|Acc]);
+bs_instrs_is([], _, Acc) ->
+ reverse(Acc).
+
+%% Combine a bs_match instruction with the destination register
+%% taken from a bs_extract instruction.
+
+bs_combine(Dst, Ctx, [{L,#b_blk{is=Is0}=Blk}|Acc]) ->
+ [#b_set{}=Succeeded,
+ #b_set{op=bs_match,args=[Type,_|As]}=BsMatch|Is1] = reverse(Is0),
+ Is = reverse(Is1, [BsMatch#b_set{op=bs_get,dst=Dst,args=[Type,Ctx|As]},
+ Succeeded#b_set{args=[Dst]}]),
+ [{L,Blk#b_blk{is=Is}}|Acc].
+
+bs_subst_ctx(#b_var{}=Var, CtxChain) ->
+ case CtxChain of
+ #{Var:={context,Ctx}} ->
+ Ctx;
+ #{Var:=ParentCtx} ->
+ bs_subst_ctx(ParentCtx, CtxChain);
+ #{} ->
+ %% Not a match context variable.
+ Var
+ end;
+bs_subst_ctx(Other, _CtxChain) ->
+ Other.
+
+%% legacy_bs(St0) -> St.
+%% Binary matching instructions in OTP 21 and earlier don't support
+%% a Y register as destination. If St#st.use_bsm3 is false,
+%% we will need to rewrite those instructions so that the result
+%% is first put in an X register and then moved to a Y register
+%% if the operation succeeded.
+
+legacy_bs(#st{use_bsm3=false,ssa=Blocks0,cnt=Count0,res=Res}=St) ->
+ IsYreg = maps:from_list([{V,true} || {V,{y,_}} <- Res]),
+ Linear0 = beam_ssa:linearize(Blocks0),
+ {Linear,Count} = legacy_bs(Linear0, IsYreg, Count0, #{}, []),
+ Blocks = maps:from_list(Linear),
+ St#st{ssa=Blocks,cnt=Count};
+legacy_bs(#st{use_bsm3=true}=St) -> St.
+
+legacy_bs([{L,Blk}|Bs], IsYreg, Count0, Copies0, Acc) ->
+ #b_blk{is=Is0,last=Last} = Blk,
+ Is1 = case Copies0 of
+ #{L:=Copy} -> [Copy|Is0];
+ #{} -> Is0
+ end,
+ {Is,Count,Copies} = legacy_bs_is(Is1, Last, IsYreg, Count0, Copies0, []),
+ legacy_bs(Bs, IsYreg, Count, Copies, [{L,Blk#b_blk{is=Is}}|Acc]);
+legacy_bs([], _IsYreg, Count, _Copies, Acc) ->
+ {Acc,Count}.
+
+legacy_bs_is([#b_set{op=Op,dst=Dst}=I0,
+ #b_set{op=succeeded,dst=SuccDst,args=[Dst]}=SuccI0],
+ Last, IsYreg, Count0, Copies0, Acc) ->
+ NeedsFix = is_map_key(Dst, IsYreg) andalso
+ case Op of
+ bs_get -> true;
+ bs_init -> true;
+ _ -> false
+ end,
+ case NeedsFix of
+ true ->
+ TempDst = #b_var{name={'@bs_temp_dst',Count0}},
+ Count = Count0 + 1,
+ I = I0#b_set{dst=TempDst},
+ SuccI = SuccI0#b_set{args=[TempDst]},
+ Copy = #b_set{op=copy,dst=Dst,args=[TempDst]},
+ #b_br{bool=SuccDst,succ=SuccL} = Last,
+ Copies = Copies0#{SuccL=>Copy},
+ legacy_bs_is([], Last, IsYreg, Count, Copies, [SuccI,I|Acc]);
+ false ->
+ legacy_bs_is([], Last, IsYreg, Count0, Copies0, [SuccI0,I0|Acc])
+ end;
+legacy_bs_is([I|Is], Last, IsYreg, Count, Copies, Acc) ->
+ legacy_bs_is(Is, Last, IsYreg, Count, Copies, [I|Acc]);
+legacy_bs_is([], _Last, _IsYreg, Count, Copies, Acc) ->
+ {reverse(Acc),Count,Copies}.
+
+%% sanitize(St0) -> St.
+%% Remove constructs that can cause problems later:
+%%
+%% * Unreachable blocks may cause problems for determination of
+%% dominators.
+%%
+%% * Some instructions (such as get_hd) don't accept literal
+%% arguments. Evaluate the instructions and remove them.
+
+sanitize(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ {Blocks,Count} = sanitize(Ls, Count0, Blocks0, #{}),
+ St#st{ssa=Blocks,cnt=Count}.
+
+sanitize([L|Ls], Count0, Blocks0, Values0) ->
+ #b_blk{is=Is0} = Blk0 = maps:get(L, Blocks0),
+ case sanitize_is(Is0, Count0, Values0, false, []) of
+ no_change ->
+ sanitize(Ls, Count0, Blocks0, Values0);
+ {Is,Count,Values} ->
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks0#{L:=Blk},
+ sanitize(Ls, Count, Blocks, Values)
+ end;
+sanitize([], Count, Blocks0, Values) ->
+ Blocks = if
+ map_size(Values) =:= 0 ->
+ Blocks0;
+ true ->
+ beam_ssa:rename_vars(Values, [0], Blocks0)
+ end,
+
+ %% Unreachable blocks can cause problems for the dominator calculations.
+ Ls = beam_ssa:rpo(Blocks),
+ Reachable = gb_sets:from_list(Ls),
+ {case map_size(Blocks) =:= gb_sets:size(Reachable) of
+ true -> Blocks;
+ false -> remove_unreachable(Ls, Blocks, Reachable, [])
+ end,Count}.
+
+sanitize_is([#b_set{op=get_map_element,args=Args0}=I0|Is],
+ Count0, Values, Changed, Acc) ->
+ case sanitize_args(Args0, Values) of
+ [#b_literal{}=Map,Key] ->
+ %% Bind the literal map to a variable.
+ {MapVar,Count} = new_var('@ssa_map', Count0),
+ I = I0#b_set{args=[MapVar,Key]},
+ Copy = #b_set{op=copy,dst=MapVar,args=[Map]},
+ sanitize_is(Is, Count, Values, true, [I,Copy|Acc]);
+ [_,_]=Args0 ->
+ sanitize_is(Is, Count0, Values, Changed, [I0|Acc]);
+ [_,_]=Args ->
+ I = I0#b_set{args=Args},
+ sanitize_is(Is, Count0, Values, Changed, [I|Acc])
+ end;
+sanitize_is([#b_set{op=Op,dst=Dst,args=Args0}=I0|Is0],
+ Count, Values, Changed0, Acc) ->
+ Args = sanitize_args(Args0, Values),
+ case sanitize_instr(Op, Args, I0) of
+ {value,Value0} ->
+ Value = #b_literal{val=Value0},
+ sanitize_is(Is0, Count, Values#{Dst=>Value}, true, Acc);
+ {ok,I} ->
+ sanitize_is(Is0, Count, Values, true, [I|Acc]);
+ ok ->
+ I = I0#b_set{args=Args},
+ Changed = Changed0 orelse Args =/= Args0,
+ sanitize_is(Is0, Count, Values, Changed, [I|Acc])
+ end;
+sanitize_is([], Count, Values, Changed, Acc) ->
+ case Changed of
+ true ->
+ {reverse(Acc),Count,Values};
+ false ->
+ no_change
+ end.
+
+sanitize_args(Args, Values) ->
+ map(fun(Var) ->
+ case Values of
+ #{Var:=New} -> New;
+ #{} -> Var
+ end
+ end, Args).
+
+sanitize_instr({bif,Bif}, [#b_literal{val=Lit}], _I) ->
+ case erl_bifs:is_pure(erlang, Bif, 1) of
+ false ->
+ ok;
+ true ->
+ try
+ {value,erlang:Bif(Lit)}
+ catch
+ error:_ ->
+ ok
+ end
+ end;
+sanitize_instr({bif,Bif}, [#b_literal{val=Lit1},#b_literal{val=Lit2}], _I) ->
+ true = erl_bifs:is_pure(erlang, Bif, 2), %Assertion.
+ try
+ {value,erlang:Bif(Lit1, Lit2)}
+ catch
+ error:_ ->
+ ok
+ end;
+sanitize_instr(get_hd, [#b_literal{val=[Hd|_]}], _I) ->
+ {value,Hd};
+sanitize_instr(get_tl, [#b_literal{val=[_|Tl]}], _I) ->
+ {value,Tl};
+sanitize_instr(get_tuple_element, [#b_literal{val=T},
+ #b_literal{val=I}], _I)
+ when I < tuple_size(T) ->
+ {value,element(I+1, T)};
+sanitize_instr(is_nonempty_list, [#b_literal{val=Lit}], _I) ->
+ {value,case Lit of
+ [_|_] -> true;
+ _ -> false
+ end};
+sanitize_instr(is_tagged_tuple, [#b_literal{val=Tuple},
+ #b_literal{val=Arity},
+ #b_literal{val=Tag}], _I)
+ when is_integer(Arity), is_atom(Tag) ->
+ if
+ tuple_size(Tuple) =:= Arity, element(1, Tuple) =:= Tag ->
+ {value,true};
+ true ->
+ {value,false}
+ end;
+sanitize_instr(bs_init, [#b_literal{val=new},#b_literal{val=Sz}|_], I0) ->
+ if
+ is_integer(Sz), Sz >= 0 -> ok;
+ true -> {ok,sanitize_badarg(I0)}
+ end;
+sanitize_instr(bs_init, [#b_literal{val=append},_,#b_literal{val=Sz}|_], I0) ->
+ if
+ is_integer(Sz), Sz >= 0 -> ok;
+ true -> {ok,sanitize_badarg(I0)}
+ end;
+sanitize_instr(succeeded, [#b_literal{}], _I) ->
+ {value,true};
+sanitize_instr(_, _, _) -> ok.
+
+sanitize_badarg(I) ->
+ Func = #b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=error},arity=1},
+ I#b_set{op=call,args=[Func,#b_literal{val=badarg}]}.
+
+remove_unreachable([L|Ls], Blocks, Reachable, Acc) ->
+ #b_blk{is=Is0} = Blk0 = maps:get(L, Blocks),
+ case split_phis(Is0) of
+ {[_|_]=Phis,Rest} ->
+ Is = [prune_phi(Phi, Reachable) || Phi <- Phis] ++ Rest,
+ Blk = Blk0#b_blk{is=Is},
+ remove_unreachable(Ls, Blocks, Reachable, [{L,Blk}|Acc]);
+ {[],_} ->
+ remove_unreachable(Ls, Blocks, Reachable, [{L,Blk0}|Acc])
+ end;
+remove_unreachable([], _Blocks, _, Acc) ->
+ maps:from_list(Acc).
+
+prune_phi(#b_set{args=Args0}=Phi, Reachable) ->
+ Args = [A || {_,Pred}=A <- Args0,
+ gb_sets:is_element(Pred, Reachable)],
+ Phi#b_set{args=Args}.
+
+%%%
+%%% Fix tuples.
+%%%
+
+%% fix_tuples(St0) -> St.
+%% If compatibility with a previous version of Erlang has been
+%% requested, tuple creation must be split into two instruction to
+%% mirror the the way tuples are created in BEAM prior to OTP 22.
+%% Each put_tuple instruction is split into put_tuple_arity followed
+%% by put_tuple_elements.
+
+fix_tuples(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ F = fun (#b_set{op=put_tuple,args=Args}=Put, C0) ->
+ Arity = #b_literal{val=length(Args)},
+ {Ignore,C} = new_var('@ssa_ignore', C0),
+ {[Put#b_set{op=put_tuple_arity,args=[Arity]},
+ #b_set{dst=Ignore,op=put_tuple_elements,args=Args}],C};
+ (I, C) -> {[I],C}
+ end,
+ {Blocks,Count} = beam_ssa:flatmapfold_instrs_rpo(F, [0], Count0, Blocks0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+%%%
+%%% Find out where frames should be placed.
+%%%
+
+%% place_frames(St0) -> St.
+%% Return a list of the labels for the blocks that need stack frame
+%% allocation instructions.
+%%
+%% This function attempts to place stack frames as tight as possible
+%% around the code, to avoid building stack frames for code paths
+%% that don't need one.
+%%
+%% Stack frames are placed in blocks that dominate all of their
+%% descendants. That guarantees that the deallocation instructions
+%% cannot be reached from other execution paths that didn't set up
+%% a stack frame or set up a stack frame with a different size.
+
+place_frames(#st{ssa=Blocks}=St) ->
+ Doms = beam_ssa:dominators(Blocks),
+ Ls = beam_ssa:rpo(Blocks),
+ Tried = gb_sets:empty(),
+ Frames0 = [],
+ {Frames,_} = place_frames_1(Ls, Blocks, Doms, Tried, Frames0),
+ St#st{frames=Frames}.
+
+place_frames_1([L|Ls], Blocks, Doms, Tried0, Frames0) ->
+ Blk = maps:get(L, Blocks),
+ case need_frame(Blk) of
+ true ->
+ %% This block needs a frame. Try to place it here.
+ {Frames,Tried} = do_place_frame(L, Blocks, Doms, Tried0, Frames0),
+
+ %% Successfully placed. Try to place more frames in descendants
+ %% that are not dominated by this block.
+ place_frames_1(Ls, Blocks, Doms, Tried, Frames);
+ false ->
+ try
+ place_frames_1(Ls, Blocks, Doms, Tried0, Frames0)
+ catch
+ throw:{need_frame,For,Tried1}=Reason ->
+ %% An descendant block needs a stack frame. Try to
+ %% place it here.
+ case is_dominated_by(For, L, Doms) of
+ true ->
+ %% Try to place a frame here.
+ {Frames,Tried} = do_place_frame(L, Blocks, Doms,
+ Tried1, Frames0),
+ place_frames_1(Ls, Blocks, Doms, Tried, Frames);
+ false ->
+ %% Wrong place. This block does not dominate
+ %% the block that needs the frame. Pass it on
+ %% to our ancestors.
+ throw(Reason)
+ end
+ end
+ end;
+place_frames_1([], _, _, Tried, Frames) ->
+ {Frames,Tried}.
+
+%% do_place_frame(Label, Blocks, Dominators, Tried0, Frames0) -> {Frames,Tried}.
+%% Try to place a frame in this block. This function returns
+%% successfully if it either succeds at placing a frame in this
+%% block, if an ancestor that dominates this block has already placed
+%% a frame, or if we have already tried to put a frame in this block.
+%%
+%% An {need_frame,Label,Tried} exception will be thrown if this block
+%% block is not suitable for having a stack frame (i.e. it does not dominate
+%% all of its descendants). The exception means that an ancestor will have to
+%% place the frame needed by this block.
+
+do_place_frame(L, Blocks, Doms, Tried0, Frames) ->
+ case gb_sets:is_element(L, Tried0) of
+ true ->
+ %% We have already tried to put a frame in this block.
+ {Frames,Tried0};
+ false ->
+ %% Try to place a frame in this block.
+ Tried = gb_sets:insert(L, Tried0),
+ case place_frame_here(L, Blocks, Doms, Frames) of
+ yes ->
+ %% We need a frame and it is safe to place it here.
+ {[L|Frames],Tried};
+ no ->
+ %% An ancestor has a frame. Not needed.
+ {Frames,Tried};
+ ancestor ->
+ %% This block does not dominate all of its
+ %% descendants. We must place the frame in
+ %% an ancestor.
+ throw({need_frame,L,Tried})
+ end
+ end.
+
+%% place_frame_here(Label, Blocks, Doms, Frames) -> no|yes|ancestor.
+%% Determine whether a frame should be placed in block Label.
+
+place_frame_here(L, Blocks, Doms, Frames) ->
+ B0 = any(fun(DomBy) ->
+ is_dominated_by(L, DomBy, Doms)
+ end, Frames),
+ case B0 of
+ true ->
+ %% This block is dominated by an ancestor block that
+ %% defines a frame. Not needed/allowed to put a frame
+ %% here.
+ no;
+ false ->
+ %% No frame in any ancestor. We need a frame.
+ %% Now check whether the frame can be placed here.
+ %% If this block dominates all of its descendants
+ %% and the predecessors of any phi nodes it can be
+ %% placed here.
+ Descendants = beam_ssa:rpo([L], Blocks),
+ PhiPredecessors = phi_predecessors(L, Blocks),
+ MustDominate = ordsets:from_list(PhiPredecessors ++ Descendants),
+ Dominates = all(fun(?BADARG_BLOCK) ->
+ %% This block defines no variables and calls
+ %% erlang:error(badarg). It does not matter
+ %% whether L dominates ?BADARG_BLOCK or not;
+ %% it is still safe to put the frame in L.
+ true;
+ (Bl) ->
+ is_dominated_by(Bl, L, Doms)
+ end, MustDominate),
+
+ %% Also, this block must not be a loop header.
+ IsLoopHeader = is_loop_header(L, Blocks),
+ case Dominates andalso not IsLoopHeader of
+ true -> yes;
+ false -> ancestor
+ end
+ end.
+
+%% phi_predecessors(Label, Blocks) ->
+%% Return all predecessors referenced in phi nodes.
+
+phi_predecessors(L, Blocks) ->
+ #b_blk{is=Is} = maps:get(L, Blocks),
+ [P || #b_set{op=phi,args=Args} <- Is, {_,P} <- Args].
+
+%% is_dominated_by(Label, DominatedBy, Dominators) -> true|false.
+%% Test whether block Label is dominated by block DominatedBy.
+
+is_dominated_by(L, DomBy, Doms) ->
+ DominatedBy = maps:get(L, Doms),
+ ordsets:is_element(DomBy, DominatedBy).
+
+%% need_frame(#b_blk{}) -> true|false.
+%% Test whether any of the instructions in the block requires a stack frame.
+
+need_frame(#b_blk{is=Is,last=#b_ret{arg=Ret}}) ->
+ need_frame_1(Is, {return,Ret});
+need_frame(#b_blk{is=Is}) ->
+ need_frame_1(Is, body).
+
+need_frame_1([#b_set{op=make_fun,dst=Fun}|Is], {return,_}=Context) ->
+ %% Since make_fun clobbers X registers, a stack frame is needed if
+ %% any of the following instructions use any other variable than
+ %% the one holding the reference to the created fun.
+ need_frame_1(Is, Context) orelse
+ case beam_ssa:used(#b_blk{is=Is,last=#b_ret{arg=Fun}}) of
+ [Fun] -> false;
+ [_|_] -> true
+ end;
+need_frame_1([#b_set{op=new_try_tag}|_], _) ->
+ true;
+need_frame_1([#b_set{op=call,dst=Val}]=Is, {return,Ret}) ->
+ if
+ Val =:= Ret -> need_frame_1(Is, tail);
+ true -> need_frame_1(Is, body)
+ end;
+need_frame_1([#b_set{op=call,args=[Func|_]}|Is], Context) ->
+ case Func of
+ #b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name},
+ arity=Arity} ->
+ case erl_bifs:is_exit_bif(Mod, Name, Arity) of
+ true ->
+ false;
+ false ->
+ Context =:= body orelse
+ Is =/= [] orelse
+ is_trap_bif(Mod, Name, Arity)
+ end;
+ #b_remote{} ->
+ %% This is an apply(), which always needs a frame.
+ true;
+ #b_local{} ->
+ Context =:= body orelse Is =/= [];
+ _ ->
+ %% A fun call always needs a frame.
+ true
+ end;
+need_frame_1([I|Is], Context) ->
+ beam_ssa:clobbers_xregs(I) orelse need_frame_1(Is, Context);
+need_frame_1([], _) -> false.
+
+%% is_trap_bif(Mod, Name, Arity) -> true|false.
+%% Test whether we need a stack frame for this BIF.
+
+is_trap_bif(erlang, '!', 2) -> true;
+is_trap_bif(erlang, link, 1) -> true;
+is_trap_bif(erlang, unlink, 1) -> true;
+is_trap_bif(erlang, monitor_node, 2) -> true;
+is_trap_bif(erlang, group_leader, 2) -> true;
+is_trap_bif(erlang, exit, 2) -> true;
+is_trap_bif(_, _, _) -> false.
+
+%%%
+%%% Fix variables used in matching in receive.
+%%%
+%%% The loop_rec/2 instruction may return a reference to a
+%%% message outside of any heap or heap fragment. If the message
+%%% does not match, it is not allowed to store any reference to
+%%% the message (or part of the message) on the stack. If we do,
+%%% the message will be corrupted if there happens to be a GC.
+%%%
+%%% Here we make sure to introduce copies of variables that are
+%%% matched out and subsequently used after the remove_message/0
+%%% instructions. That will make sure that only X registers are
+%%% used during matching.
+%%%
+%%% Depending on where variables are defined and used, they must
+%%% be handled in two different ways.
+%%%
+%%% Variables that are always defined in the receive (before branching
+%%% out into the different clauses of the receive) and used after the
+%%% receive must be handled in the following way: Before each
+%%% remove_message instruction, each such variable must be copied, and
+%%% all variables must be consolidated using a phi node in the
+%%% common exit block for the receive.
+%%%
+%%% Variables that are matched out and used in the same clause
+%%% need copy instructions before the remove_message instruction
+%%% in that clause.
+%%%
+
+fix_receives(#st{ssa=Blocks0,cnt=Count0}=St) ->
+ {Blocks,Count} = fix_receives_1(maps:to_list(Blocks0),
+ Blocks0, Count0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+fix_receives_1([{L,Blk}|Ls], Blocks0, Count0) ->
+ case Blk of
+ #b_blk{is=[#b_set{op=peek_message}|_]} ->
+ Rm = find_rm_blocks(L, Blocks0),
+ LoopExit = find_loop_exit(Rm, Blocks0),
+ Defs0 = beam_ssa:def([L], Blocks0),
+ CommonUsed = recv_common(Defs0, LoopExit, Blocks0),
+ {Blocks1,Count1} = recv_fix_common(CommonUsed, LoopExit, Rm,
+ Blocks0, Count0),
+ Defs = ordsets:subtract(Defs0, CommonUsed),
+ {Blocks,Count} = fix_receive(Rm, Defs, Blocks1, Count1),
+ fix_receives_1(Ls, Blocks, Count);
+ #b_blk{} ->
+ fix_receives_1(Ls, Blocks0, Count0)
+ end;
+fix_receives_1([], Blocks, Count) ->
+ {Blocks,Count}.
+
+recv_common(_Defs, none, _Blocks) ->
+ %% There is no common exit block because receive is used
+ %% in the tail position of a function.
+ [];
+recv_common(Defs, Exit, Blocks) ->
+ {ExitDefs,ExitUsed} = beam_ssa:def_used([Exit], Blocks),
+ Def = ordsets:subtract(Defs, ExitDefs),
+ ordsets:intersection(Def, ExitUsed).
+
+%% recv_fix_common([CommonVar], LoopExit, [RemoveMessageLabel],
+%% Blocks0, Count0) -> {Blocks,Count}.
+%% Handle variables alwys defined in a receive and used
+%% in the exit block following the receive.
+
+recv_fix_common([Msg0|T], Exit, Rm, Blocks0, Count0) ->
+ {Msg,Count1} = new_var('@recv', Count0),
+ Blocks1 = beam_ssa:rename_vars(#{Msg0=>Msg}, [Exit], Blocks0),
+ N = length(Rm),
+ {MsgVars,Count} = new_vars(duplicate(N, '@recv'), Count1),
+ PhiArgs = fix_exit_phi_args(MsgVars, Rm, Exit, Blocks1),
+ Phi = #b_set{op=phi,dst=Msg,args=PhiArgs},
+ ExitBlk0 = maps:get(Exit, Blocks1),
+ ExitBlk = ExitBlk0#b_blk{is=[Phi|ExitBlk0#b_blk.is]},
+ Blocks2 = Blocks1#{Exit:=ExitBlk},
+ Blocks = recv_fix_common_1(MsgVars, Rm, Msg0, Blocks2),
+ recv_fix_common(T, Exit, Rm, Blocks, Count);
+recv_fix_common([], _, _, Blocks, Count) ->
+ {Blocks,Count}.
+
+recv_fix_common_1([V|Vs], [Rm|Rms], Msg, Blocks0) ->
+ Ren = #{Msg=>V},
+ Blocks1 = beam_ssa:rename_vars(Ren, [Rm], Blocks0),
+ #b_blk{is=Is0} = Blk0 = maps:get(Rm, Blocks1),
+ Copy = #b_set{op=copy,dst=V,args=[Msg]},
+ Is = insert_after_phis(Is0, [Copy]),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = Blocks1#{Rm:=Blk},
+ recv_fix_common_1(Vs, Rms, Msg, Blocks);
+recv_fix_common_1([], [], _Msg, Blocks) -> Blocks.
+
+fix_exit_phi_args([V|Vs], [Rm|Rms], Exit, Blocks) ->
+ Path = beam_ssa:rpo([Rm], Blocks),
+ Preds = exit_predecessors(Path, Exit, Blocks),
+ [{V,Pred} || Pred <- Preds] ++ fix_exit_phi_args(Vs, Rms, Exit, Blocks);
+fix_exit_phi_args([], [], _, _) -> [].
+
+exit_predecessors([L|Ls], Exit, Blocks) ->
+ Blk = map_get(L, Blocks),
+ case member(Exit, beam_ssa:successors(Blk)) of
+ true ->
+ [L|exit_predecessors(Ls, Exit, Blocks)];
+ false ->
+ exit_predecessors(Ls, Exit, Blocks)
+ end;
+exit_predecessors([], _Exit, _Blocks) -> [].
+
+%% fix_receive([Label], Defs, Blocks0, Count0) -> {Blocks,Count}.
+%% Add a copy instruction for all variables that are matched out and
+%% later used within a clause of the receive.
+
+fix_receive([L|Ls], Defs, Blocks0, Count0) ->
+ {RmDefs,Used0} = beam_ssa:def_used([L], Blocks0),
+ Def = ordsets:subtract(Defs, RmDefs),
+ Used = ordsets:intersection(Def, Used0),
+ {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Used], Count0),
+ Ren = zip(Used, NewVars),
+ Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+ #b_blk{is=Is0} = Blk1 = maps:get(L, Blocks1),
+ CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
+ Is = insert_after_phis(Is0, CopyIs),
+ Blk = Blk1#b_blk{is=Is},
+ Blocks = maps:put(L, Blk, Blocks1),
+ fix_receive(Ls, Defs, Blocks, Count);
+fix_receive([], _Defs, Blocks, Count) ->
+ {Blocks,Count}.
+
+%% find_loop_exit([Label], Blocks) -> Label | none.
+%% Find the block to which control is transferred when the
+%% the receive loop is exited.
+
+find_loop_exit([L1,L2|_Ls], Blocks) ->
+ Path1 = beam_ssa:rpo([L1], Blocks),
+ Path2 = beam_ssa:rpo([L2], Blocks),
+ find_loop_exit_1(reverse(Path1), reverse(Path2), none);
+find_loop_exit(_, _) -> none.
+
+find_loop_exit_1([H|T1], [H|T2], _) ->
+ find_loop_exit_1(T1, T2, H);
+find_loop_exit_1(_, _, Exit) -> Exit.
+
+%% find_rm_blocks(StartLabel, Blocks) -> [Label].
+%% Find all blocks that start with remove_message within the receive
+%% loop whose peek_message label is StartLabel.
+
+find_rm_blocks(L, Blocks) ->
+ Seen = gb_sets:singleton(L),
+ Blk = maps:get(L, Blocks),
+ Succ = beam_ssa:successors(Blk),
+ find_rm_blocks_1(Succ, Seen, Blocks).
+
+find_rm_blocks_1([L|Ls], Seen0, Blocks) ->
+ case gb_sets:is_member(L, Seen0) of
+ true ->
+ find_rm_blocks_1(Ls, Seen0, Blocks);
+ false ->
+ Seen = gb_sets:insert(L, Seen0),
+ Blk = maps:get(L, Blocks),
+ case find_rm_act(Blk#b_blk.is) of
+ prune ->
+ %% Looping back. Don't look at any successors.
+ find_rm_blocks_1(Ls, Seen, Blocks);
+ continue ->
+ %% Neutral block. Do nothing here, but look at
+ %% all successors.
+ Succ = beam_ssa:successors(Blk),
+ find_rm_blocks_1(Succ++Ls, Seen, Blocks);
+ found ->
+ %% Found remove_message instruction.
+ [L|find_rm_blocks_1(Ls, Seen, Blocks)]
+ end
+ end;
+find_rm_blocks_1([], _, _) -> [].
+
+find_rm_act([#b_set{op=Op}|Is]) ->
+ case Op of
+ remove_message -> found;
+ peek_message -> prune;
+ recv_next -> prune;
+ wait_timeout -> prune;
+ wait -> prune;
+ _ -> find_rm_act(Is)
+ end;
+find_rm_act([]) ->
+ continue.
+
+%%%
+%%% Find out which variables need to be stored in Y registers.
+%%%
+
+-record(dk, {d :: ordsets:ordset(var_name()),
+ k :: ordsets:ordset(var_name())
+ }).
+
+%% find_yregs(St0) -> St.
+%% Find all variables that must be stored in Y registers. Annotate
+%% the blocks that allocate frames with the set of Y registers
+%% used within that stack frame.
+%%
+%% Basically, we following all execution paths starting from a block
+%% that allocates a frame, keeping track of of all defined registers
+%% and all registers killed by an instruction that clobbers X
+%% registers. For every use of a variable, we check if if it is in
+%% the set of killed variables; if it is, it must be stored in an Y
+%% register.
+
+find_yregs(#st{frames=[]}=St) ->
+ St;
+find_yregs(#st{frames=[_|_]=Frames,args=Args,ssa=Blocks0}=St) ->
+ FrameDefs = find_defs(Frames, Blocks0, [V || #b_var{}=V <- Args]),
+ Blocks = find_yregs_1(FrameDefs, Blocks0),
+ St#st{ssa=Blocks}.
+
+find_yregs_1([{F,Defs}|Fs], Blocks0) ->
+ DK = #dk{d=Defs,k=[]},
+ D0 = #{F=>DK},
+ Ls = beam_ssa:rpo([F], Blocks0),
+ Yregs0 = [],
+ Yregs = find_yregs_2(Ls, Blocks0, D0, Yregs0),
+ Blk0 = maps:get(F, Blocks0),
+ Blk = beam_ssa:add_anno(yregs, Yregs, Blk0),
+ Blocks = Blocks0#{F:=Blk},
+ find_yregs_1(Fs, Blocks);
+find_yregs_1([], Blocks) -> Blocks.
+
+find_yregs_2([L|Ls], Blocks0, D0, Yregs0) ->
+ Blk0 = maps:get(L, Blocks0),
+ #b_blk{is=Is,last=Last} = Blk0,
+ Ys0 = maps:get(L, D0),
+ {Yregs1,Ys} = find_yregs_is(Is, Ys0, Yregs0),
+ Yregs = find_yregs_terminator(Last, Ys, Yregs1),
+ Successors = beam_ssa:successors(Blk0),
+ D = find_update_succ(Successors, Ys, D0),
+ find_yregs_2(Ls, Blocks0, D, Yregs);
+find_yregs_2([], _Blocks, _D, Yregs) -> Yregs.
+
+find_defs(Frames, Blocks, Defs) ->
+ Seen = gb_sets:empty(),
+ FramesSet = gb_sets:from_list(Frames),
+ {FrameDefs,_} = find_defs_1([0], Blocks, FramesSet, Seen, Defs, []),
+ FrameDefs.
+
+find_defs_1([L|Ls], Blocks, Frames, Seen0, Defs0, Acc0) ->
+ case gb_sets:is_member(L, Frames) of
+ true ->
+ OrderedDefs = ordsets:from_list(Defs0),
+ find_defs_1(Ls, Blocks, Frames, Seen0, Defs0,
+ [{L,OrderedDefs}|Acc0]);
+ false ->
+ case gb_sets:is_member(L, Seen0) of
+ true ->
+ find_defs_1(Ls, Blocks, Frames, Seen0, Defs0, Acc0);
+ false ->
+ Seen1 = gb_sets:insert(L, Seen0),
+ {Acc,Seen} = find_defs_1(Ls, Blocks, Frames, Seen1, Defs0, Acc0),
+ #b_blk{is=Is} = Blk = maps:get(L, Blocks),
+ Defs = find_defs_is(Is, Defs0),
+ Successors = beam_ssa:successors(Blk),
+ find_defs_1(Successors, Blocks, Frames, Seen, Defs, Acc)
+ end
+ end;
+find_defs_1([], _, _, Seen, _, Acc) ->
+ {Acc,Seen}.
+
+find_defs_is([#b_set{dst=Dst}|Is], Acc) ->
+ find_defs_is(Is, [Dst|Acc]);
+find_defs_is([], Acc) -> Acc.
+
+find_update_succ([S|Ss], #dk{d=Defs0,k=Killed0}=DK0, D0) ->
+ case D0 of
+ #{S:=#dk{d=Defs1,k=Killed1}} ->
+ Defs = ordsets:intersection(Defs0, Defs1),
+ Killed = ordsets:union(Killed0, Killed1),
+ DK = #dk{d=Defs,k=Killed},
+ D = maps:put(S, DK, D0),
+ find_update_succ(Ss, DK0, D);
+ #{} ->
+ D = maps:put(S, DK0, D0),
+ find_update_succ(Ss, DK0, D)
+ end;
+find_update_succ([], _, D) -> D.
+
+find_yregs_is([#b_set{dst=Dst}=I|Is], #dk{d=Defs0,k=Killed0}=Ys, Yregs0) ->
+ Used = beam_ssa:used(I),
+ Yregs1 = ordsets:intersection(Used, Killed0),
+ Yregs = ordsets:union(Yregs0, Yregs1),
+ case beam_ssa:clobbers_xregs(I) of
+ false ->
+ Defs = ordsets:add_element(Dst, Defs0),
+ find_yregs_is(Is, Ys#dk{d=Defs}, Yregs);
+ true ->
+ Killed = ordsets:union(Defs0, Killed0),
+ Defs = [Dst],
+ find_yregs_is(Is, Ys#dk{d=Defs,k=Killed}, Yregs)
+ end;
+find_yregs_is([], Ys, Yregs) -> {Yregs,Ys}.
+
+find_yregs_terminator(Terminator, #dk{k=Killed}, Yregs0) ->
+ Used = beam_ssa:used(Terminator),
+ Yregs = ordsets:intersection(Used, Killed),
+ ordsets:union(Yregs0, Yregs).
+
+%%%
+%%% Try to reduce the size of the stack frame, by adding an explicit
+%%% 'copy' instructions for return values from 'call' and 'make_fun' that
+%%% need to be saved in Y registers. Here is an example to show
+%%% how that's useful. First, here is the Erlang code:
+%%%
+%%% f(Pid) ->
+%%% Res = foo(42),
+%%% _ = node(Pid),
+%%% bar(),
+%%% Res.
+%%%
+%%% Compiled to SSA format, the main part of the code looks like this:
+%%%
+%%% 0:
+%%% Res = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%% 3:
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% It can be seen that the variables Pid and Res must be saved in Y
+%%% registers in order to survive the function calls. A previous sub
+%%% pass has inserted a 'copy' instruction to save the value of the
+%%% variable Pid:
+%%%
+%%% 0:
+%%% Pid:4 = copy Pid
+%%% Res = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid:4
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%%
+%%% 3:
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% The Res and Pid:4 variables must be assigned to different Y registers
+%%% because they are live at the same time. copy_retval() inserts a
+%%% 'copy' instruction to copy Res to a new variable:
+%%%
+%%% 0:
+%%% Pid:4 = copy Pid
+%%% Res:6 = call local literal foo/1, literal 42
+%%% _1 = bif:node Pid:4
+%%% @ssa_bool = succeeded _1
+%%% br @ssa_bool, label 3, label 1
+%%%
+%%% 3:
+%%% Res = copy Res:6
+%%% @ssa_ignored = call local literal bar/0
+%%% ret Res
+%%%
+%%% The new variable Res:6 is used to capture the return value from the call.
+%%% The variables Pid:4 and Res are no longer live at the same time, so they
+%%% can be assigned to the same Y register.
+%%%
+
+copy_retval(#st{frames=Frames,ssa=Blocks0,cnt=Count0}=St) ->
+ {Blocks,Count} = copy_retval_1(Frames, Blocks0, Count0),
+ St#st{ssa=Blocks,cnt=Count}.
+
+copy_retval_1([F|Fs], Blocks0, Count0) ->
+ #b_blk{anno=#{yregs:=Yregs0},is=Is} = maps:get(F, Blocks0),
+ Yregs1 = gb_sets:from_list(Yregs0),
+ Yregs = collect_yregs(Is, Yregs1),
+ Ls = beam_ssa:rpo([F], Blocks0),
+ {Blocks,Count} = copy_retval_2(Ls, Yregs, none, Blocks0, Count0),
+ copy_retval_1(Fs, Blocks, Count);
+copy_retval_1([], Blocks, Count) ->
+ {Blocks,Count}.
+
+collect_yregs([#b_set{op=copy,dst=Y,args=[#b_var{}=X]}|Is],
+ Yregs0) ->
+ true = gb_sets:is_member(X, Yregs0), %Assertion.
+ Yregs = gb_sets:insert(Y, gb_sets:delete(X, Yregs0)),
+ collect_yregs(Is, Yregs);
+collect_yregs([#b_set{}|Is], Yregs) ->
+ collect_yregs(Is, Yregs);
+collect_yregs([], Yregs) -> Yregs.
+
+copy_retval_2([L|Ls], Yregs, Copy0, Blocks0, Count0) ->
+ #b_blk{is=Is0,last=Last} = Blk = maps:get(L, Blocks0),
+ RC = case {Last,Ls} of
+ {#b_br{succ=Succ,fail=?BADARG_BLOCK},[Succ|_]} ->
+ true;
+ {_,_} ->
+ false
+ end,
+ case copy_retval_is(Is0, RC, Yregs, Copy0, Count0, []) of
+ {Is,Count} ->
+ case Copy0 =:= none andalso Count0 =:= Count of
+ true ->
+ copy_retval_2(Ls, Yregs, none, Blocks0, Count0);
+ false ->
+ Blocks = Blocks0#{L=>Blk#b_blk{is=Is}},
+ copy_retval_2(Ls, Yregs, none, Blocks, Count)
+ end;
+ {Is,Count,Copy} ->
+ Blocks = Blocks0#{L=>Blk#b_blk{is=Is}},
+ copy_retval_2(Ls, Yregs, Copy, Blocks, Count)
+ end;
+copy_retval_2([], _Yregs, none, Blocks, Count) ->
+ {Blocks,Count}.
+
+copy_retval_is([#b_set{op=put_tuple_elements,args=Args0}=I0], false, _Yregs,
+ Copy, Count, Acc) ->
+ I = I0#b_set{args=copy_sub_args(Args0, Copy)},
+ {reverse(Acc, [I|acc_copy([], Copy)]),Count};
+copy_retval_is([#b_set{}]=Is, false, _Yregs, Copy, Count, Acc) ->
+ {reverse(Acc, acc_copy(Is, Copy)),Count};
+copy_retval_is([#b_set{},#b_set{op=succeeded}]=Is, false, _Yregs, Copy, Count, Acc) ->
+ {reverse(Acc, acc_copy(Is, Copy)),Count};
+copy_retval_is([#b_set{op=Op,dst=#b_var{name=RetName}=Dst}=I0|Is], RC, Yregs,
+ Copy0, Count0, Acc0) when Op =:= call; Op =:= make_fun ->
+ {I1,Count1,Acc} = place_retval_copy(I0, Yregs, Copy0, Count0, Acc0),
+ case gb_sets:is_member(Dst, Yregs) of
+ true ->
+ {NewVar,Count} = new_var(RetName, Count1),
+ Copy = #b_set{op=copy,dst=Dst,args=[NewVar]},
+ I = I1#b_set{dst=NewVar},
+ copy_retval_is(Is, RC, Yregs, Copy, Count, [I|Acc]);
+ false ->
+ copy_retval_is(Is, RC, Yregs, none, Count1, [I1|Acc])
+ end;
+copy_retval_is([#b_set{args=Args0}=I0|Is], RC, Yregs, Copy, Count, Acc) ->
+ I = I0#b_set{args=copy_sub_args(Args0, Copy)},
+ case beam_ssa:clobbers_xregs(I) of
+ true ->
+ copy_retval_is(Is, RC, Yregs, none, Count, [I|acc_copy(Acc, Copy)]);
+ false ->
+ copy_retval_is(Is, RC, Yregs, Copy, Count, [I|Acc])
+ end;
+copy_retval_is([], RC, _, Copy, Count, Acc) ->
+ case {Copy,RC} of
+ {none,_} ->
+ {reverse(Acc),Count};
+ {#b_set{},true} ->
+ {reverse(Acc),Count,Copy};
+ {#b_set{},false} ->
+ {reverse(Acc, [Copy]),Count}
+ end.
+
+%%
+%% Consider this code:
+%%
+%% Var = ...
+%% ...
+%% A1 = call foo/0
+%% A = copy A1
+%% B = call bar/1, Var
+%%
+%% If the Var variable is no longer used after this code, its Y register
+%% can't be reused for A. To allow the Y register to be reused
+%% we will need to insert 'copy' instructions for arguments that are
+%% in Y registers:
+%%
+%% Var = ...
+%% ...
+%% A1 = call foo/0
+%% Var1 = copy Var
+%% A = copy A1
+%% B = call bar/1, Var1
+%%
+
+place_retval_copy(I, _Yregs, none, Count, Acc) ->
+ {I,Count,Acc};
+place_retval_copy(#b_set{args=[F|Args0]}=I, Yregs, Copy, Count0, Acc0) ->
+ #b_set{dst=Avoid} = Copy,
+ {Args,Acc1,Count} = copy_func_args(Args0, Yregs, Avoid, Acc0, [], Count0),
+ Acc = [Copy|Acc1],
+ {I#b_set{args=[F|Args]},Count,Acc}.
+
+copy_func_args([#b_var{name=AName}=A|As], Yregs, Avoid, CopyAcc, Acc, Count0) ->
+ case gb_sets:is_member(A, Yregs) of
+ true when A =/= Avoid ->
+ {NewVar,Count} = new_var(AName, Count0),
+ Copy = #b_set{op=copy,dst=NewVar,args=[A]},
+ copy_func_args(As, Yregs, Avoid, [Copy|CopyAcc], [NewVar|Acc], Count);
+ _ ->
+ copy_func_args(As, Yregs, Avoid, CopyAcc, [A|Acc], Count0)
+ end;
+copy_func_args([A|As], Yregs, Avoid, CopyAcc, Acc, Count) ->
+ copy_func_args(As, Yregs, Avoid, CopyAcc, [A|Acc], Count);
+copy_func_args([], _Yregs, _Avoid, CopyAcc, Acc, Count) ->
+ {reverse(Acc),CopyAcc,Count}.
+
+acc_copy(Acc, none) -> Acc;
+acc_copy(Acc, #b_set{}=Copy) -> [Copy|Acc].
+
+copy_sub_args(Args, none) ->
+ Args;
+copy_sub_args(Args, #b_set{dst=Dst,args=[Src]}) ->
+ [sub_arg(A, Dst, Src) || A <- Args].
+
+sub_arg(Old, Old, New) -> New;
+sub_arg(Old, _, _) -> Old.
+
+%%%
+%%% Consider:
+%%%
+%%% x1/Hd = get_hd x0/Cons
+%%% y0/Tl = get_tl x0/Cons
+%%%
+%%% Register x0 can't be reused for Hd. If Hd needs to be in x0,
+%%% a 'move' instruction must be inserted.
+%%%
+%%% If we swap get_hd and get_tl when Tl is in a Y register,
+%%% x0 can be used for Hd if Cons is not used again:
+%%%
+%%% y0/Tl = get_tl x0/Cons
+%%% x0/Hd = get_hd x0/Cons
+%%%
+
+opt_get_list(#st{ssa=Blocks,res=Res}=St) ->
+ ResMap = maps:from_list(Res),
+ Ls = beam_ssa:rpo(Blocks),
+ St#st{ssa=opt_get_list_1(Ls, ResMap, Blocks)}.
+
+opt_get_list_1([L|Ls], Res, Blocks0) ->
+ #b_blk{is=Is0} = Blk = maps:get(L, Blocks0),
+ case opt_get_list_is(Is0, Res, [], false) of
+ no ->
+ opt_get_list_1(Ls, Res, Blocks0);
+ {yes,Is} ->
+ Blocks = Blocks0#{L:=Blk#b_blk{is=Is}},
+ opt_get_list_1(Ls, Res, Blocks)
+ end;
+opt_get_list_1([], _, Blocks) -> Blocks.
+
+opt_get_list_is([#b_set{op=get_hd,dst=Hd,
+ args=[Cons]}=GetHd,
+ #b_set{op=get_tl,dst=Tl,
+ args=[Cons]}=GetTl|Is],
+ Res, Acc, Changed) ->
+ %% Note that when this pass is run, only Y registers have
+ %% reservations. The absence of an entry for a variable therefore
+ %% means that the variable will be in an X register.
+ case Res of
+ #{Hd:={y,_}} ->
+ %% Hd will be in a Y register. Don't swap.
+ opt_get_list_is([GetTl|Is], Res, [GetHd|Acc], Changed);
+ #{Tl:={y,_}} ->
+ %% Tl will be in a Y register. Swap.
+ opt_get_list_is([GetHd|Is], Res, [GetTl|Acc], true);
+ #{} ->
+ %% Both are in X registers. Nothing to do.
+ opt_get_list_is([GetTl|Is], Res, [GetHd|Acc], Changed)
+ end;
+opt_get_list_is([I|Is], Res, Acc, Changed) ->
+ opt_get_list_is(Is, Res, [I|Acc], Changed);
+opt_get_list_is([], _Res, Acc, Changed) ->
+ case Changed of
+ true ->
+ {yes,reverse(Acc)};
+ false ->
+ no
+ end.
+
+%%%
+%%% Number instructions in the order they are executed.
+%%%
+
+%% number_instructions(St0) -> St.
+%% Number instructions in the order they are executed. Use a step
+%% size of 2. Don't number phi instructions. All phi variables in
+%% a block will be live one unit before the first non-phi instruction
+%% in the block.
+
+number_instructions(#st{ssa=Blocks0}=St) ->
+ Ls = beam_ssa:rpo(Blocks0),
+ St#st{ssa=number_is_1(Ls, 1, Blocks0)}.
+
+number_is_1([L|Ls], N0, Blocks0) ->
+ #b_blk{is=Is0,last=Last0} = Bl0 = maps:get(L, Blocks0),
+ {Is,N1} = number_is_2(Is0, N0, []),
+ Last = beam_ssa:add_anno(n, N1, Last0),
+ N = N1 + 2,
+ Bl = Bl0#b_blk{is=Is,last=Last},
+ Blocks = maps:put(L, Bl, Blocks0),
+ number_is_1(Ls, N, Blocks);
+number_is_1([], _, Blocks) -> Blocks.
+
+number_is_2([#b_set{op=phi}=I|Is], N, Acc) ->
+ number_is_2(Is, N, [I|Acc]);
+number_is_2([I0|Is], N, Acc) ->
+ I = beam_ssa:add_anno(n, N, I0),
+ number_is_2(Is, N+2, [I|Acc]);
+number_is_2([], N, Acc) ->
+ {reverse(Acc),N}.
+
+%%%
+%%% Calculate live intervals.
+%%%
+
+live_intervals(#st{args=Args,ssa=Blocks}=St) ->
+ Vars0 = [{V,{0,1}} || #b_var{}=V <- Args],
+ F = fun(L, _, A) -> live_interval_blk(L, Blocks, A) end,
+ LiveMap0 = #{},
+ Acc0 = {[],LiveMap0},
+ {Vars,_} = beam_ssa:fold_po(F, Acc0, Blocks),
+ Intervals = merge_ranges(rel2fam(Vars0++Vars)),
+ St#st{intervals=Intervals}.
+
+merge_ranges([{V,Rs}|T]) ->
+ [{V,merge_ranges_1(Rs)}|merge_ranges(T)];
+merge_ranges([]) -> [].
+
+merge_ranges_1([{A,N},{N,Z}|Rs]) ->
+ merge_ranges_1([{A,Z}|Rs]);
+merge_ranges_1([R|Rs]) ->
+ [R|merge_ranges_1(Rs)];
+merge_ranges_1([]) -> [].
+
+live_interval_blk(L, Blocks, {Vars0,LiveMap0}) ->
+ Live0 = [],
+ Successors = beam_ssa:successors(L, Blocks),
+ Live1 = update_successors(Successors, L, Blocks, LiveMap0, Live0),
+
+ %% Add ranges for all variables that are live in the successors.
+ #b_blk{is=Is,last=Last} = maps:get(L, Blocks),
+ End = beam_ssa:get_anno(n, Last),
+ Use = [{V,{use,End+1}} || V <- Live1],
+
+ %% Determine used and defined variables in this block.
+ FirstNumber = first_number(Is, Last),
+ UseDef0 = live_interval_blk_1([Last|reverse(Is)], FirstNumber, Use),
+ UseDef = rel2fam(UseDef0),
+
+ %% Update what is live at the beginning of this block and
+ %% store it.
+ Used = [V || {V,[{use,_}|_]} <- UseDef],
+ Live2 = ordsets:union(Live1, Used),
+ Killed = [V || {V,[{def,_}|_]} <- UseDef],
+ Live = ordsets:subtract(Live2, Killed),
+ LiveMap = LiveMap0#{L=>Live},
+
+ %% Construct the ranges for this block.
+ Vars = make_block_ranges(UseDef, FirstNumber, Vars0),
+ {Vars,LiveMap}.
+
+make_block_ranges([{V,[{def,Def}]}|Vs], First, Acc) ->
+ make_block_ranges(Vs, First, [{V,{Def,Def}}|Acc]);
+make_block_ranges([{V,[{def,Def}|Uses]}|Vs], First, Acc) ->
+ {use,Last} = last(Uses),
+ make_block_ranges(Vs, First, [{V,{Def,Last}}|Acc]);
+make_block_ranges([{V,[{use,_}|_]=Uses}|Vs], First, Acc) ->
+ {use,Last} = last(Uses),
+ make_block_ranges(Vs, First, [{V,{First,Last}}|Acc]);
+make_block_ranges([], _, Acc) -> Acc.
+
+live_interval_blk_1([#b_set{op=phi,dst=Dst}|Is], FirstNumber, Acc0) ->
+ Acc = [{Dst,{def,FirstNumber}}|Acc0],
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([#b_set{op=bs_start_match}=I|Is],
+ FirstNumber, Acc0) ->
+ N = beam_ssa:get_anno(n, I),
+ #b_set{dst=Dst} = I,
+ Acc1 = [{Dst,{def,N}}|Acc0],
+ Acc = [{V,{use,N}} || V <- beam_ssa:used(I)] ++ Acc1,
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([I|Is], FirstNumber, Acc0) ->
+ N = beam_ssa:get_anno(n, I),
+ Acc1 = case I of
+ #b_set{dst=Dst} ->
+ [{Dst,{def,N}}|Acc0];
+ _ ->
+ Acc0
+ end,
+ Used = beam_ssa:used(I),
+ Acc = [{V,{use,N}} || V <- Used] ++ Acc1,
+ live_interval_blk_1(Is, FirstNumber, Acc);
+live_interval_blk_1([], _FirstNumber, Acc) ->
+ Acc.
+
+%% first_number([#b_set{}]) -> InstructionNumber.
+%% Return the number for the first instruction for the block.
+%% Note that this number is one less than the first
+%% non-phi instruction in the block.
+
+first_number([#b_set{op=phi}|Is], Last) ->
+ first_number(Is, Last);
+first_number([I|_], _) ->
+ beam_ssa:get_anno(n, I) - 1;
+first_number([], Last) ->
+ beam_ssa:get_anno(n, Last) - 1.
+
+update_successors([L|Ls], Pred, Blocks, LiveMap, Live0) ->
+ Live1 = ordsets:union(Live0, get_live(L, LiveMap)),
+ #b_blk{is=Is} = maps:get(L, Blocks),
+ Live = update_live_phis(Is, Pred, Live1),
+ update_successors(Ls, Pred, Blocks, LiveMap, Live);
+update_successors([], _, _, _, Live) -> Live.
+
+get_live(L, LiveMap) ->
+ case LiveMap of
+ #{L:=Live} -> Live;
+ #{} -> []
+ end.
+
+update_live_phis([#b_set{op=phi,dst=Killed,args=Args}|Is],
+ Pred, Live0) ->
+ Used = [V || {#b_var{}=V,L} <- Args, L =:= Pred],
+ Live1 = ordsets:union(ordsets:from_list(Used), Live0),
+ Live = ordsets:del_element(Killed, Live1),
+ update_live_phis(Is, Pred, Live);
+update_live_phis(_, _, Live) -> Live.
+
+%%%
+%%% Reserve Y registers.
+%%%
+
+%% reserve_yregs(St0) -> St.
+%% In each block that allocates a stack frame, insert instructions
+%% that copy variables that must be in Y registers (given by
+%% the `yregs` annotation) to new variables.
+%%
+%% Also allocate specific Y registers for try and catch tags.
+%% The outermost try/catch tag is placed in y0, any directly
+%% nested tag in y1, and so on. Note that this is the reversed
+%% order as required by BEAM; it will be corrected later by
+%% turn_yregs().
+
+reserve_yregs(#st{frames=Frames}=St0) ->
+ foldl(fun reserve_yregs_1/2, St0, Frames).
+
+reserve_yregs_1(L, #st{ssa=Blocks0,cnt=Count0,res=Res0}=St) ->
+ Blk = maps:get(L, Blocks0),
+ Yregs = beam_ssa:get_anno(yregs, Blk),
+ {Def,Used} = beam_ssa:def_used([L], Blocks0),
+ UsedYregs = ordsets:intersection(Yregs, Used),
+ DefBefore = ordsets:subtract(UsedYregs, Def),
+ {BeforeVars,Blocks,Count} = rename_vars(DefBefore, L, Blocks0, Count0),
+ InsideVars = ordsets:subtract(UsedYregs, DefBefore),
+ ResTryTags0 = reserve_try_tags(L, Blocks),
+ ResTryTags = [{V,{Reg,Count}} || {V,Reg} <- ResTryTags0],
+ Vars = BeforeVars ++ InsideVars,
+ Res = [{V,{y,Count}} || V <- Vars] ++ ResTryTags ++ Res0,
+ St#st{res=Res,ssa=Blocks,cnt=Count+1}.
+
+reserve_try_tags(L, Blocks) ->
+ Seen = gb_sets:empty(),
+ {Res0,_} = reserve_try_tags_1([L], Blocks, Seen, #{}),
+ Res1 = [maps:to_list(M) || {_,M} <- maps:to_list(Res0)],
+ Res = [{V,{y,Y}} || {V,Y} <- append(Res1)],
+ ordsets:from_list(Res).
+
+reserve_try_tags_1([L|Ls], Blocks, Seen0, ActMap0) ->
+ case gb_sets:is_element(L, Seen0) of
+ true ->
+ reserve_try_tags_1(Ls, Blocks, Seen0, ActMap0);
+ false ->
+ Seen1 = gb_sets:insert(L, Seen0),
+ #b_blk{is=Is} = Blk = maps:get(L, Blocks),
+ Active0 = get_active(L, ActMap0),
+ Active = reserve_try_tags_is(Is, Active0),
+ Successors = beam_ssa:successors(Blk),
+ ActMap1 = update_act_map(Successors, Active, ActMap0),
+ {ActMap,Seen} = reserve_try_tags_1(Ls, Blocks, Seen1, ActMap1),
+ reserve_try_tags_1(Successors, Blocks, Seen,ActMap)
+ end;
+reserve_try_tags_1([], _Blocks, Seen, ActMap) ->
+ {ActMap,Seen}.
+
+get_active(L, ActMap) ->
+ case ActMap of
+ #{L:=Active} -> Active;
+ #{} -> #{}
+ end.
+
+reserve_try_tags_is([#b_set{op=new_try_tag,dst=V}|Is], Active) ->
+ N = map_size(Active),
+ reserve_try_tags_is(Is, Active#{V=>N});
+reserve_try_tags_is([#b_set{op=kill_try_tag,args=[Tag]}|Is], Active) ->
+ reserve_try_tags_is(Is, maps:remove(Tag, Active));
+reserve_try_tags_is([_|Is], Active) ->
+ reserve_try_tags_is(Is, Active);
+reserve_try_tags_is([], Active) -> Active.
+
+update_act_map([L|Ls], Active0, ActMap0) ->
+ case ActMap0 of
+ #{L:=Active1} ->
+ ActMap = ActMap0#{L=>maps:merge(Active0, Active1)},
+ update_act_map(Ls, Active0, ActMap);
+ #{} ->
+ ActMap = ActMap0#{L=>Active0},
+ update_act_map(Ls, Active0, ActMap)
+ end;
+update_act_map([], _, ActMap) -> ActMap.
+
+rename_vars([], _, Blocks, Count) ->
+ {[],Blocks,Count};
+rename_vars(Vs, L, Blocks0, Count0) ->
+ {NewVars,Count} = new_vars([Base || #b_var{name=Base} <- Vs], Count0),
+ Ren = zip(Vs, NewVars),
+ Blocks1 = beam_ssa:rename_vars(Ren, [L], Blocks0),
+ #b_blk{is=Is0} = Blk0 = maps:get(L, Blocks1),
+ CopyIs = [#b_set{op=copy,dst=New,args=[Old]} || {Old,New} <- Ren],
+ Is = insert_after_phis(Is0, CopyIs),
+ Blk = Blk0#b_blk{is=Is},
+ Blocks = maps:put(L, Blk, Blocks1),
+ {NewVars,Blocks,Count}.
+
+insert_after_phis([#b_set{op=phi}=I|Is], InsertIs) ->
+ [I|insert_after_phis(Is, InsertIs)];
+insert_after_phis(Is, InsertIs) ->
+ InsertIs ++ Is.
+
+%% frame_size(St0) -> St.
+%% Calculate the frame size for each block that allocates a frame.
+%% Annotate the block with the frame size. Also annotate all
+%% return instructions with {deallocate,FrameSize} to simplify
+%% code generation.
+
+frame_size(#st{frames=Frames,regs=Regs,ssa=Blocks0}=St) ->
+ Blocks = foldl(fun(L, Blks) ->
+ frame_size_1(L, Regs, Blks)
+ end, Blocks0, Frames),
+ St#st{ssa=Blocks}.
+
+frame_size_1(L, Regs, Blocks0) ->
+ Def = beam_ssa:def([L], Blocks0),
+ Yregs0 = [maps:get(V, Regs) || V <- Def, is_yreg(maps:get(V, Regs))],
+ Yregs = ordsets:from_list(Yregs0),
+ FrameSize = length(ordsets:from_list(Yregs)),
+ if
+ FrameSize =/= 0 ->
+ [{y,0}|_] = Yregs, %Assertion.
+ {y,Last} = last(Yregs),
+ Last = FrameSize - 1, %Assertion.
+ ok;
+ true ->
+ ok
+ end,
+ Blk0 = maps:get(L, Blocks0),
+ Blk = beam_ssa:add_anno(frame_size, FrameSize, Blk0),
+
+ %% Insert an annotation for frame deallocation on
+ %% each #b_ret{}.
+ Blocks = maps:put(L, Blk, Blocks0),
+ Reachable = beam_ssa:rpo([L], Blocks),
+ frame_deallocate(Reachable, FrameSize, Blocks).
+
+frame_deallocate([L|Ls], Size, Blocks0) ->
+ Blk0 = maps:get(L, Blocks0),
+ Blk = case Blk0 of
+ #b_blk{last=#b_ret{}=Ret0} ->
+ Ret = beam_ssa:add_anno(deallocate, Size, Ret0),
+ Blk0#b_blk{last=Ret};
+ #b_blk{} ->
+ Blk0
+ end,
+ Blocks = maps:put(L, Blk, Blocks0),
+ frame_deallocate(Ls, Size, Blocks);
+frame_deallocate([], _, Blocks) -> Blocks.
+
+
+%% turn_yregs(St0) -> St.
+%% Renumber y registers so that {y,0} becomes {y,FrameSize-1},
+%% {y,FrameSize-1} becomes {y,0} and so on. This is to make nested
+%% catches work. The register allocator (linear_scan()) has given
+%% a lower number to the outermost catch.
+
+turn_yregs(#st{frames=Frames,regs=Regs0,ssa=Blocks}=St) ->
+ Regs1 = foldl(fun(L, A) ->
+ Blk = maps:get(L, Blocks),
+ FrameSize = beam_ssa:get_anno(frame_size, Blk),
+ Def = beam_ssa:def([L], Blocks),
+ [turn_yregs_1(Def, FrameSize, Regs0)|A]
+ end, [], Frames),
+ Regs = maps:merge(Regs0, maps:from_list(append(Regs1))),
+ St#st{regs=Regs}.
+
+turn_yregs_1(Def, FrameSize, Regs) ->
+ Yregs0 = [{maps:get(V, Regs),V} || V <- Def, is_yreg(maps:get(V, Regs))],
+ Yregs1 = rel2fam(Yregs0),
+ FrameSize = length(Yregs1),
+ Yregs2 = [{{y,FrameSize-Y-1},Vs} || {{y,Y},Vs} <- Yregs1],
+ R0 = sofs:family(Yregs2),
+ R1 = sofs:family_to_relation(R0),
+ R = sofs:converse(R1),
+ sofs:to_external(R).
+
+%%%
+%%% Reserving registers before register allocation.
+%%%
+
+%% reserve_regs(St0) -> St.
+%% Reserve registers prior to register allocation. Y registers
+%% have already been reserved. This function will reserve z,
+%% fr, and specific x registers.
+
+reserve_regs(#st{args=Args,ssa=Blocks,intervals=Intervals,res=Res0}=St) ->
+ %% Reserve x0, x1, and so on for the function arguments.
+ Res1 = reserve_arg_regs(Args, 0, Res0),
+
+ %% Reserve Z registers (dummy registers) for instructions with no
+ %% return values (e.g. remove_message) or pseudo-return values
+ %% (e.g. landingpad).
+ Res2 = reserve_zregs(Blocks, Intervals, Res1),
+
+ %% Reserve float registers.
+ Res3 = reserve_fregs(Blocks, Res2),
+
+ %% Reserve all remaining unreserved variables as X registers.
+ Res = maps:from_list(Res3),
+ St#st{res=reserve_xregs(Blocks, Res)}.
+
+reserve_arg_regs([#b_var{}=Arg|Is], N, Acc) ->
+ reserve_arg_regs(Is, N+1, [{Arg,{x,N}}|Acc]);
+reserve_arg_regs([], _, Acc) -> Acc.
+
+reserve_zregs(Blocks, Intervals, Res) ->
+ ShortLived0 = [V || {V,[{Start,End}]} <- Intervals, Start+2 =:= End],
+ ShortLived = cerl_sets:from_list(ShortLived0),
+ F = fun(_, #b_blk{is=Is,last=Last}, A) ->
+ reserve_zreg(Is, Last, ShortLived, A)
+ end,
+ beam_ssa:fold_rpo(F, [0], Res, Blocks).
+
+reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst},
+ #b_set{op={bif,'=:='},args=[Dst,Val]}], _Last, ShortLived, A0) ->
+ case Val of
+ #b_literal{val=Arity} when Arity bsr 32 =:= 0 ->
+ %% These two instructions can be combined to a test_arity
+ %% instruction provided that the arity variable is short-lived.
+ reserve_zreg_1(Dst, ShortLived, A0);
+ _ ->
+ A0
+ end;
+reserve_zreg([#b_set{op={bif,tuple_size},dst=Dst}],
+ #b_switch{}, ShortLived, A) ->
+ reserve_zreg_1(Dst, ShortLived, A);
+reserve_zreg([#b_set{op=Op,dst=Dst}|Is], Last, ShortLived, A0) ->
+ IsZReg = case Op of
+ bs_match_string -> true;
+ bs_save -> true;
+ bs_restore -> true;
+ bs_set_position -> true;
+ {float,clearerror} -> true;
+ kill_try_tag -> true;
+ landingpad -> true;
+ put_tuple_elements -> true;
+ remove_message -> true;
+ set_tuple_element -> true;
+ succeeded -> true;
+ timeout -> true;
+ wait_timeout -> true;
+ _ -> false
+ end,
+ A = case IsZReg of
+ true -> [{Dst,z}|A0];
+ false -> A0
+ end,
+ reserve_zreg(Is, Last, ShortLived, A);
+reserve_zreg([], #b_br{bool=Bool}, ShortLived, A) ->
+ reserve_zreg_1(Bool, ShortLived, A);
+reserve_zreg([], _, _, A) -> A.
+
+reserve_zreg_1(#b_var{}=V, ShortLived, A) ->
+ case cerl_sets:is_element(V, ShortLived) of
+ true -> [{V,z}|A];
+ false -> A
+ end;
+reserve_zreg_1(#b_literal{}, _, A) -> A.
+
+reserve_fregs(Blocks, Res) ->
+ F = fun(_, #b_blk{is=Is}, A) ->
+ reserve_freg(Is, A)
+ end,
+ beam_ssa:fold_rpo(F, [0], Res, Blocks).
+
+reserve_freg([#b_set{op={float,Op},dst=V}|Is], Res) ->
+ case Op of
+ get ->
+ reserve_freg(Is, Res);
+ _ ->
+ reserve_freg(Is, [{V,fr}|Res])
+ end;
+reserve_freg([_|Is], Res) ->
+ reserve_freg(Is, Res);
+reserve_freg([], Res) -> Res.
+
+%% reserve_xregs(St0) -> St.
+%% Reserve all remaining variables as X registers.
+%%
+%% If a variable will need to be in a specific X register for a
+%% 'call' or 'make_fun' (and there is nothing that will kill it
+%% between the definition and use), reserve the register using a
+%% {prefer,{x,X} annotation. That annotation means that the linear
+%% scan algorithm will place the variable in the preferred register,
+%% unless that register is already occupied.
+%%
+%% All remaining variables are reserved as X registers. Linear scan
+%% will allocate the lowest free X register for the variable.
+
+reserve_xregs(Blocks, Res) ->
+ F = fun(L, #b_blk{is=Is,last=Last}, R) ->
+ {Xs0,Used0} = reserve_terminator(L, Last, Blocks, R),
+ reserve_xregs_is(reverse(Is), R, Xs0, Used0)
+ end,
+ beam_ssa:fold_po(F, Res, Blocks).
+
+reserve_xregs_is([#b_set{op=Op,dst=Dst,args=Args}=I|Is], Res0, Xs0, Used0) ->
+ Xs1 = case is_gc_safe(I) of
+ true ->
+ Xs0;
+ false ->
+ %% There may be a garbage collection after executing this
+ %% instruction. We will need prune the list of preferred
+ %% X registers.
+ res_xregs_prune(Xs0, Used0, Res0)
+ end,
+ Res = reserve_xreg(Dst, Xs1, Res0),
+ Used1 = ordsets:union(Used0, beam_ssa:used(I)),
+ Used = ordsets:del_element(Dst, Used1),
+ case Op of
+ call ->
+ Xs = reserve_call_args(tl(Args)),
+ reserve_xregs_is(Is, Res, Xs, Used);
+ make_fun ->
+ Xs = reserve_call_args(tl(Args)),
+ reserve_xregs_is(Is, Res, Xs, Used);
+ _ ->
+ reserve_xregs_is(Is, Res, Xs1, Used)
+ end;
+reserve_xregs_is([], Res, _Xs, _Used) -> Res.
+
+reserve_terminator(L, #b_br{bool=#b_literal{val=true},succ=Succ}, Blocks, Res) ->
+ case maps:get(Succ, Blocks) of
+ #b_blk{is=[],last=Last} ->
+ reserve_terminator(Succ, Last, Blocks, Res);
+ #b_blk{is=[_|_]=Is} ->
+ {res_xregs_from_phi(Is, L, Res, #{}),[]}
+ end;
+reserve_terminator(_, Last, _, _) ->
+ {#{},beam_ssa:used(Last)}.
+
+res_xregs_from_phi([#b_set{op=phi,dst=Dst,args=Args}|Is],
+ Pred, Res, Acc) ->
+ case [V || {#b_var{}=V,L} <- Args, L =:= Pred] of
+ [] ->
+ res_xregs_from_phi(Is, Pred, Res, Acc);
+ [V] ->
+ case Res of
+ #{Dst:={prefer,Reg}} ->
+ res_xregs_from_phi(Is, Pred, Res, Acc#{V=>Reg});
+ #{Dst:=_} ->
+ res_xregs_from_phi(Is, Pred, Res, Acc)
+ end
+ end;
+res_xregs_from_phi(_, _, _, Acc) -> Acc.
+
+reserve_call_args(Args) ->
+ reserve_call_args(Args, 0, #{}).
+
+reserve_call_args([#b_var{}=Var|As], X, Xs) ->
+ reserve_call_args(As, X+1, Xs#{Var=>{x,X}});
+reserve_call_args([#b_literal{}|As], X, Xs) ->
+ reserve_call_args(As, X+1, Xs);
+reserve_call_args([], _, Xs) -> Xs.
+
+reserve_xreg(V, Xs, Res) ->
+ case Res of
+ #{V:=_} ->
+ %% Already reserved.
+ Res;
+ #{} ->
+ case Xs of
+ #{V:=X} ->
+ %% Add a hint that a specific X register is
+ %% preferred, unless it is already in use.
+ Res#{V=>{prefer,X}};
+ #{} ->
+ %% Reserve as an X register in general.
+ Res#{V=>x}
+ end
+ end.
+
+is_gc_safe(#b_set{op=phi}) ->
+ false;
+is_gc_safe(#b_set{op=Op,args=Args}) ->
+ case beam_ssa_codegen:classify_heap_need(Op, Args) of
+ neutral -> true;
+ {put,_} -> true;
+ _ -> false
+ end.
+
+%% res_xregs_prune(PreferredRegs, Used, Res) -> PreferredRegs.
+%% Prune the list of preferred to only include X registers that
+%% are guaranteed to survice a garbage collection.
+
+res_xregs_prune(Xs, Used, Res) ->
+ %% The number of safe registers is the number of the X registers
+ %% used after this point. The actual number of safe registers may
+ %% be highter than this number, but this is a conservative safe
+ %% estimate.
+ NumSafe = foldl(fun(V, N) ->
+ case Res of
+ #{V:={x,_}} -> N + 1;
+ #{V:=_} -> N;
+ #{} -> N + 1
+ end
+ end, 0, Used),
+
+ %% Remove unsafe registers from the list of potential
+ %% preferred registers.
+ maps:filter(fun(_, {x,X}) -> X < NumSafe end, Xs).
+
+%%%
+%%% Register allocation using linear scan.
+%%%
+
+-record(i,
+ {sort=1 :: instr_number(),
+ reg=none :: i_reg(),
+ pool=x :: pool_id(),
+ var=#b_var{} :: b_var(),
+ rs=[] :: [range()]
+ }).
+
+-record(l,
+ {cur=#i{} :: interval(),
+ unhandled_res=[] :: [interval()],
+ unhandled_any=[] :: [interval()],
+ active=[] :: [interval()],
+ inactive=[] :: [interval()],
+ free=#{} :: #{var_name()=>pool(),
+ {'next',pool_id()}:=reg_num()},
+ regs=[] :: [{b_var(),ssa_register()}]
+ }).
+
+-type interval() :: #i{}.
+-type i_reg() :: ssa_register() | {'prefer',xreg()} | 'none'.
+-type pool_id() :: 'fr' | 'x' | 'z' | instr_number().
+-type pool() :: ordsets:ordset(ssa_register()).
+
+linear_scan(#st{intervals=Intervals0,res=Res}=St0) ->
+ St = St0#st{intervals=[],res=[]},
+ Free = init_free(maps:to_list(Res)),
+ Intervals1 = [init_interval(Int, Res) || Int <- Intervals0],
+ Intervals = sort(Intervals1),
+ IsReserved = fun (#i{reg=Reg}) -> Reg =/= none end,
+ {UnhandledRes,Unhandled} = partition(IsReserved, Intervals),
+ L = #l{unhandled_res=UnhandledRes,
+ unhandled_any=Unhandled,free=Free},
+ #l{regs=Regs} = do_linear(L),
+ St#st{regs=maps:from_list(Regs)}.
+
+init_interval({V,[{Start,_}|_]=Rs}, Res) ->
+ Info = maps:get(V, Res),
+ Pool = case Info of
+ {prefer,{x,_}} -> x;
+ x -> x;
+ {x,_} -> x;
+ {y,Uniq} -> Uniq;
+ {{y,_},Uniq} -> Uniq;
+ z -> z;
+ fr -> fr
+ end,
+ Reg = case Info of
+ {prefer,{x,_}} -> Info;
+ {x,_} -> Info;
+ {{y,_}=Y,_} -> Y;
+ _ -> none
+ end,
+ #i{sort=Start,var=V,reg=Reg,pool=Pool,rs=Rs}.
+
+init_free(Res) ->
+ Free0 = rel2fam([{x,{x,0}}|init_free_1(Res)]),
+ #{x:=Xs0} = Free1 = maps:from_list(Free0),
+ Xs = init_xregs(Xs0),
+ Free = Free1#{x:=Xs},
+ Next = maps:fold(fun(K, V, A) -> [{{next,K},length(V)}|A] end, [], Free),
+ maps:merge(Free, maps:from_list(Next)).
+
+init_free_1([{_,{prefer,{x,_}=Reg}}|Res]) ->
+ [{x,Reg}|init_free_1(Res)];
+init_free_1([{_,{x,_}=Reg}|Res]) ->
+ [{x,Reg}|init_free_1(Res)];
+init_free_1([{_,{y,Uniq}}|Res]) ->
+ [{Uniq,{y,0}}|init_free_1(Res)];
+init_free_1([{_,{{y,_}=Reg,Uniq}}|Res]) ->
+ [{Uniq,Reg}|init_free_1(Res)];
+init_free_1([{_,z}|Res]) ->
+ [{z,{z,0}}|init_free_1(Res)];
+init_free_1([{_,fr}|Res]) ->
+ [{fr,{fr,0}}|init_free_1(Res)];
+init_free_1([{_,x}|Res]) ->
+ init_free_1(Res);
+init_free_1([]) -> [].
+
+%% Make sure that the pool of xregs is contiguous.
+init_xregs([{x,N},{x,M}|Is]) when N+1 =:= M ->
+ [{x,N}|init_xregs([{x,M}|Is])];
+init_xregs([{x,N}|[{x,_}|_]=Is]) ->
+ [{x,N}|init_xregs([{x,N+1}|Is])];
+init_xregs([{x,_}]=Is) -> Is.
+
+do_linear(L0) ->
+ case set_next_current(L0) of
+ done ->
+ L0;
+ L1 ->
+ L2 = expire_active(L1),
+ L3 = check_inactive(L2),
+ Available = collect_available(L3),
+ L4 = select_register(Available, L3),
+ L = make_cur_active(L4),
+ do_linear(L)
+ end.
+
+set_next_current(#l{unhandled_res=[Cur1|T1],
+ unhandled_any=[Cur2|T2]}=L) ->
+ case {Cur1,Cur2} of
+ {#i{sort=N1},#i{sort=N2}} when N1 < N2 ->
+ L#l{cur=Cur1,unhandled_res=T1};
+ {_,_} ->
+ L#l{cur=Cur2,unhandled_any=T2}
+ end;
+set_next_current(#l{unhandled_res=[],
+ unhandled_any=[Cur|T]}=L) ->
+ L#l{cur=Cur,unhandled_any=T};
+set_next_current(#l{unhandled_res=[Cur|T],
+ unhandled_any=[]}=L) ->
+ L#l{cur=Cur,unhandled_res=T};
+set_next_current(#l{unhandled_res=[],unhandled_any=[]}) ->
+ done.
+
+expire_active(#l{cur=#i{sort=CurBegin},active=Act0}=L0) ->
+ {Act,L} = expire_active(Act0, CurBegin, L0, []),
+ L#l{active=Act}.
+
+expire_active([#i{reg=Reg,rs=Rs0}=I|Is], CurBegin, L0, Acc) ->
+ {_,_} = Reg, %Assertion.
+ case overlap_status(Rs0, CurBegin) of
+ ends_before_cur ->
+ L = free_reg(I, L0),
+ expire_active(Is, CurBegin, L, Acc);
+ overlapping ->
+ expire_active(Is, CurBegin, L0, [I|Acc]);
+ not_overlapping ->
+ Rs = strip_before_current(Rs0, CurBegin),
+ L1 = free_reg(I, L0),
+ L = L1#l{inactive=[I#i{rs=Rs}|L1#l.inactive]},
+ expire_active(Is, CurBegin, L, Acc)
+ end;
+expire_active([], _CurBegin, L, Acc) ->
+ {Acc,L}.
+
+check_inactive(#l{cur=#i{sort=CurBegin},inactive=InAct0}=L0) ->
+ {InAct,L} = check_inactive(InAct0, CurBegin, L0, []),
+ L#l{inactive=InAct}.
+
+check_inactive([#i{rs=Rs0}=I|Is], CurBegin, L0, Acc) ->
+ case overlap_status(Rs0, CurBegin) of
+ ends_before_cur ->
+ check_inactive(Is, CurBegin, L0, Acc);
+ not_overlapping ->
+ check_inactive(Is, CurBegin, L0, [I|Acc]);
+ overlapping ->
+ Rs = strip_before_current(Rs0, CurBegin),
+ L1 = L0#l{active=[I#i{rs=Rs}|L0#l.active]},
+ L = reserve_reg(I, L1),
+ check_inactive(Is, CurBegin, L, Acc)
+ end;
+check_inactive([], _CurBegin, L, Acc) ->
+ {Acc,L}.
+
+strip_before_current([{_,E}|Rs], CurBegin) when E =< CurBegin ->
+ strip_before_current(Rs, CurBegin);
+strip_before_current(Rs, _CurBegin) -> Rs.
+
+collect_available(#l{cur=#i{reg={prefer,{_,_}=Prefer}}=I}=L) ->
+ %% Use the preferred register if it is available.
+ Avail = collect_available(L#l{cur=I#i{reg=none}}),
+ case member(Prefer, Avail) of
+ true -> [Prefer];
+ false -> Avail
+ end;
+collect_available(#l{cur=#i{reg={_,_}=ReservedReg}}) ->
+ %% Return the already reserved register.
+ [ReservedReg];
+collect_available(#l{unhandled_res=Unhandled,cur=Cur}=L) ->
+ Free = get_pool(Cur, L),
+
+ %% Note that since the live intervals are constructed from
+ %% SSA form, there cannot be any overlap of the current interval
+ %% with any inactive interval. See [3], page 175. Therefore we
+ %% only have check the unhandled intervals for overlap with
+ %% the current interval. As a further optimization, we only need
+ %% to check the intervals that have reserved registers.
+ collect_available(Unhandled, Cur, Free).
+
+collect_available([#i{pool=Pool1}|Is], #i{pool=Pool2}=Cur, Free)
+ when Pool1 =/= Pool2 ->
+ %% Wrong pool. Ignore this interval.
+ collect_available(Is, Cur, Free);
+collect_available([#i{reg={_,_}=Reg}=I|Is], Cur, Free0) ->
+ case overlaps(I, Cur) of
+ true ->
+ Free = ordsets:del_element(Reg, Free0),
+ collect_available(Is, Cur, Free);
+ false ->
+ collect_available(Is, Cur, Free0)
+ end;
+collect_available([], _, Free) -> Free.
+
+select_register([{_,_}=Reg|_], #l{cur=Cur0,regs=Regs}=L) ->
+ Cur = Cur0#i{reg=Reg},
+ reserve_reg(Cur, L#l{cur=Cur,regs=[{Cur#i.var,Reg}|Regs]});
+select_register([], #l{cur=Cur0,regs=Regs}=L0) ->
+ %% Allocate a new register in the pool.
+ {Reg,L1} = get_next_free(Cur0, L0),
+ Cur = Cur0#i{reg=Reg},
+ L = L1#l{cur=Cur,regs=[{Cur#i.var,Reg}|Regs]},
+ reserve_reg(Cur, L).
+
+make_cur_active(#l{cur=Cur,active=Act}=L) ->
+ L#l{active=[Cur|Act]}.
+
+overlaps(#i{rs=Rs1}, #i{rs=Rs2}) ->
+ are_overlapping(Rs1, Rs2).
+
+overlap_status([{S,E}], CurBegin) ->
+ if
+ E =< CurBegin -> ends_before_cur;
+ CurBegin < S -> not_overlapping;
+ true -> overlapping
+ end;
+overlap_status([{S,E}|Rs], CurBegin) ->
+ if
+ E =< CurBegin ->
+ overlap_status(Rs, CurBegin);
+ S =< CurBegin ->
+ overlapping;
+ true ->
+ not_overlapping
+ end.
+
+reserve_reg(#i{reg={_,_}=Reg}=I, L) ->
+ FreeRegs0 = get_pool(I, L),
+ FreeRegs = ordsets:del_element(Reg, FreeRegs0),
+ update_pool(I, FreeRegs, L).
+
+free_reg(#i{reg={_,_}=Reg}=I, L) ->
+ FreeRegs0 = get_pool(I, L),
+ FreeRegs = ordsets:add_element(Reg, FreeRegs0),
+ update_pool(I, FreeRegs, L).
+
+get_pool(#i{pool=Pool}, #l{free=Free}) ->
+ maps:get(Pool, Free).
+
+update_pool(#i{pool=Pool}, New, #l{free=Free0}=L) ->
+ Free = maps:put(Pool, New, Free0),
+ L#l{free=Free}.
+
+get_next_free(#i{pool=Pool}, #l{free=Free0}=L0) ->
+ K = {next,Pool},
+ N = maps:get(K, Free0),
+ Free = maps:put(K, N+1, Free0),
+ L = L0#l{free=Free},
+ if
+ is_integer(Pool) -> {{y,N},L};
+ is_atom(Pool) -> {{Pool,N},L}
+ end.
+
+%%%
+%%% Interval utilities.
+%%%
+
+are_overlapping([R|Rs1], Rs2) ->
+ case are_overlapping_1(R, Rs2) of
+ true ->
+ true;
+ false ->
+ are_overlapping(Rs1, Rs2)
+ end;
+are_overlapping([], _) -> false.
+
+are_overlapping_1({_S1,E1}, [{S2,_E2}|_]) when E1 < S2 ->
+ false;
+are_overlapping_1({S1,E1}=R, [{S2,E2}|Rs]) ->
+ (S2 < E1 andalso E2 > S1) orelse are_overlapping_1(R, Rs);
+are_overlapping_1({_,_}, []) -> false.
+
+%%%
+%%% Utilities.
+%%%
+
+%% is_loop_header(L, Blocks) -> false|true.
+%% Check whether the block is a loop header.
+
+is_loop_header(L, Blocks) ->
+ %% We KNOW that a loop header must start with a peek_message
+ %% instruction.
+ case maps:get(L, Blocks) of
+ #b_blk{is=[#b_set{op=peek_message}|_]} -> true;
+ _ -> false
+ end.
+
+rel2fam(S0) ->
+ S1 = sofs:relation(S0),
+ S = sofs:rel2fam(S1),
+ sofs:to_external(S).
+
+split_phis(Is) ->
+ partition(fun(#b_set{op=Op}) -> Op =:= phi end, Is).
+
+is_yreg({y,_}) -> true;
+is_yreg({x,_}) -> false;
+is_yreg({z,_}) -> false;
+is_yreg({fr,_}) -> false.
+
+new_vars([Base|Vs0], Count0) ->
+ {V,Count1} = new_var(Base, Count0),
+ {Vs,Count} = new_vars(Vs0, Count1),
+ {[V|Vs],Count};
+new_vars([], Count) -> {[],Count}.
+
+new_var({Base,Int}, Count) ->
+ true = is_integer(Int), %Assertion.
+ {#b_var{name={Base,Count}},Count+1};
+new_var(Base, Count) ->
+ {#b_var{name={Base,Count}},Count+1}.
diff --git a/lib/compiler/src/beam_ssa_recv.erl b/lib/compiler/src/beam_ssa_recv.erl
new file mode 100644
index 0000000000..6e49b128da
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_recv.erl
@@ -0,0 +1,278 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_ssa_recv).
+-export([module/2]).
+
+%%%
+%%% In code such as:
+%%%
+%%% Ref = make_ref(), %Or erlang:monitor(process, Pid)
+%%% .
+%%% .
+%%% .
+%%% receive
+%%% {Ref,Reply} -> Reply
+%%% end.
+%%%
+%%% we know that none of the messages that exist in the message queue
+%%% before the call to make_ref/0 can be matched out in the receive
+%%% statement. Therefore we can avoid going through the entire message
+%%% queue if we introduce two new instructions (here written as
+%%% BIFs in pseudo-Erlang):
+%%%
+%%% recv_mark(SomeUniqInteger),
+%%% Ref = make_ref(),
+%%% .
+%%% .
+%%% .
+%%% recv_set(SomeUniqInteger),
+%%% receive
+%%% {Ref,Reply} -> Reply
+%%% end.
+%%%
+%%% The recv_mark/1 instruction will save the current position and
+%%% SomeUniqInteger in the process context. The recv_set
+%%% instruction will verify that SomeUniqInteger is still stored
+%%% in the process context. If it is, it will set the current pointer
+%%% for the message queue (the next message to be read out) to the
+%%% position that was saved by recv_mark/1.
+%%%
+%%% The remove_message instruction must be modified to invalidate
+%%% the information stored by the previous recv_mark/1, in case there
+%%% is another receive executed between the calls to recv_mark/1 and
+%%% recv_set/1.
+%%%
+%%% We use a reference to a label (i.e. a position in the loaded code)
+%%% as the SomeUniqInteger.
+%%%
+
+-include("beam_ssa.hrl").
+-import(lists, [all/2,reverse/2]).
+
+-spec module(beam_ssa:b_module(), [compile:option()]) ->
+ {'ok',beam_ssa:b_module()}.
+
+module(#b_module{body=Fs0}=Module, _Opts) ->
+ Fs = [function(F) || F <- Fs0],
+ {ok,Module#b_module{body=Fs}}.
+
+%%%
+%%% Local functions.
+%%%
+
+function(#b_function{anno=Anno,bs=Blocks0}=F) ->
+ try
+ Blocks = opt(Blocks0),
+ F#b_function{bs=Blocks}
+ catch
+ Class:Error:Stack ->
+ #{func_info:={_,Name,Arity}} = Anno,
+ io:fwrite("Function: ~w/~w\n", [Name,Arity]),
+ erlang:raise(Class, Error, Stack)
+ end.
+
+opt(Blocks) ->
+ Linear = beam_ssa:linearize(Blocks),
+ opt(Linear, Blocks, []).
+
+opt([{L,#b_blk{is=[#b_set{op=peek_message}|_]}=Blk0}|Bs], Blocks0, Preds) ->
+ %% Search for a suitable reference creating call in one of the predecessor
+ %% blocks. Whether we find such a call or not, we always clear the
+ %% the list of predecessors to ensure that any nested receive can't
+ %% search above the current receive.
+ case recv_opt(Preds, L, Blocks0) of
+ {yes,Blocks1} ->
+ Blk = beam_ssa:add_anno(recv_set, L, Blk0),
+ Blocks = maps:put(L, Blk, Blocks1),
+ opt(Bs, Blocks, []);
+ no ->
+ opt(Bs, Blocks0, [])
+ end;
+opt([{L,_}|Bs], Blocks, Preds) ->
+ opt(Bs, Blocks, [L|Preds]);
+opt([], Blocks, _) -> Blocks.
+
+recv_opt([L|Ls], RecvLbl, Blocks) ->
+ #b_blk{is=Is0} = Blk0 = maps:get(L, Blocks),
+ case recv_opt_is(Is0, RecvLbl, Blocks, []) of
+ {yes,Is} ->
+ Blk = Blk0#b_blk{is=Is},
+ {yes,maps:put(L, Blk, Blocks)};
+ no ->
+ recv_opt(Ls, RecvLbl, Blocks)
+ end;
+recv_opt([], _, _Blocks) -> no.
+
+recv_opt_is([#b_set{op=call}=I0|Is], RecvLbl, Blocks0, Acc) ->
+ case makes_ref(I0, Blocks0) of
+ no ->
+ recv_opt_is(Is, RecvLbl, Blocks0, [I0|Acc]);
+ {yes,Ref} ->
+ case opt_ref_used(RecvLbl, Ref, Blocks0) of
+ false ->
+ recv_opt_is(Is, RecvLbl, Blocks0, [I0|Acc]);
+ true ->
+ I = beam_ssa:add_anno(recv_mark, RecvLbl, I0),
+ {yes,reverse(Acc, [I|Is])}
+ end
+ end;
+recv_opt_is([I|Is], RecvLbl, Blocks, Acc) ->
+ recv_opt_is(Is, RecvLbl, Blocks, [I|Acc]);
+recv_opt_is([], _, _, _) -> no.
+
+makes_ref(#b_set{dst=Dst,args=[Func0|_]}, Blocks) ->
+ Func = case Func0 of
+ #b_remote{mod=#b_literal{val=erlang},
+ name=#b_literal{val=Name},arity=A0} ->
+ {Name,A0};
+ _ ->
+ none
+ end,
+ case Func of
+ {make_ref,0} ->
+ {yes,Dst};
+ {monitor,2} ->
+ {yes,Dst};
+ {spawn_monitor,A} when A =:= 1; A =:= 3 ->
+ ref_in_tuple(Dst, Blocks);
+ _ ->
+ no
+ end.
+
+ref_in_tuple(Tuple, Blocks) ->
+ F = fun(#b_set{op=get_tuple_element,dst=Ref,
+ args=[#b_var{}=Tup,#b_literal{val=1}]}, no)
+ when Tup =:= Tuple -> {yes,Ref};
+ (_, A) -> A
+ end,
+ beam_ssa:fold_instrs_rpo(F, [0], no, Blocks).
+
+opt_ref_used(RecvLbl, Ref, Blocks) ->
+ Vs = #{Ref=>ref,ref=>Ref,ref_matched=>false},
+ case opt_ref_used_1(RecvLbl, Vs, Blocks) of
+ used -> true;
+ not_used -> false;
+ done -> false
+ end.
+
+opt_ref_used_1(L, Vs0, Blocks) ->
+ #b_blk{is=Is} = Blk = maps:get(L, Blocks),
+ case opt_ref_used_is(Is, Vs0) of
+ #{}=Vs ->
+ opt_ref_used_last(Blk, Vs, Blocks);
+ Result ->
+ Result
+ end.
+
+opt_ref_used_is([#b_set{op=peek_message,dst=Msg}|Is], Vs0) ->
+ Vs = Vs0#{Msg=>message},
+ opt_ref_used_is(Is, Vs);
+opt_ref_used_is([#b_set{op={bif,Bif},args=Args,dst=Dst}=I|Is],
+ Vs0) ->
+ S = case Bif of
+ '=:=' -> true;
+ '==' -> true;
+ _ -> none
+ end,
+ case S of
+ none ->
+ Vs = update_vars(I, Vs0),
+ opt_ref_used_is(Is, Vs);
+ Bool when is_boolean(Bool) ->
+ case is_ref_msg_comparison(Args, Vs0) of
+ true ->
+ Vs = Vs0#{Dst=>{is_ref,Bool}},
+ opt_ref_used_is(Is, Vs);
+ false ->
+ opt_ref_used_is(Is, Vs0)
+ end
+ end;
+opt_ref_used_is([#b_set{op=remove_message}|_], Vs) ->
+ case Vs of
+ #{ref_matched:=true} ->
+ used;
+ #{ref_matched:=false} ->
+ not_used
+ end;
+opt_ref_used_is([#b_set{op=recv_next}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{op=wait_timeout}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{op=wait}|_], _Vs) ->
+ done;
+opt_ref_used_is([#b_set{}=I|Is], Vs0) ->
+ Vs = update_vars(I, Vs0),
+ opt_ref_used_is(Is, Vs);
+opt_ref_used_is([], Vs) -> Vs.
+
+opt_ref_used_last(#b_blk{last=Last}=Blk, Vs, Blocks) ->
+ case Last of
+ #b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail} ->
+ case Vs of
+ #{Bool:={is_ref,Matched}} ->
+ ref_used_in([{Succ,Vs#{ref_matched:=Matched}},
+ {Fail,Vs#{ref_matched:=not Matched}}],
+ Blocks);
+ #{} ->
+ ref_used_in([{Succ,Vs},{Fail,Vs}], Blocks)
+ end;
+ _ ->
+ SuccVs = [{Succ,Vs} || Succ <- beam_ssa:successors(Blk)],
+ ref_used_in(SuccVs, Blocks)
+ end.
+
+ref_used_in([{L,Vs0}|Ls], Blocks) ->
+ case opt_ref_used_1(L, Vs0, Blocks) of
+ not_used ->
+ not_used;
+ used ->
+ case ref_used_in(Ls, Blocks) of
+ done -> used;
+ Result -> Result
+ end;
+ done -> ref_used_in(Ls, Blocks)
+ end;
+ref_used_in([], _) -> done.
+
+update_vars(#b_set{args=Args,dst=Dst}, Vs) ->
+ Vars = [V || #b_var{}=V <- Args],
+ All = all(fun(Var) ->
+ case Vs of
+ #{Var:=message} -> true;
+ #{} -> false
+ end
+ end, Vars),
+ case All of
+ true -> Vs#{Dst=>message};
+ false -> Vs
+ end.
+
+%% is_ref_msg_comparison(Args, Variables) -> true|false.
+%% Return 'true' if Args denotes a comparison between the
+%% reference and message or part of the message.
+
+is_ref_msg_comparison([#b_var{}=V1,#b_var{}=V2], Vs) ->
+ case Vs of
+ #{V1:=ref,V2:=message} -> true;
+ #{V1:=message,V2:=ref} -> true;
+ #{} -> false
+ end;
+is_ref_msg_comparison(_, _) -> false.
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl
new file mode 100644
index 0000000000..18e6e73a46
--- /dev/null
+++ b/lib/compiler/src/beam_ssa_type.erl
@@ -0,0 +1,1195 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(beam_ssa_type).
+-export([opt/2]).
+
+-include("beam_ssa.hrl").
+-import(lists, [all/2,any/2,droplast/1,foldl/3,last/1,member/2,
+ reverse/1,sort/1]).
+
+-define(UNICODE_INT, #t_integer{elements={0,16#10FFFF}}).
+
+-record(d, {ds :: #{beam_ssa:var_name():=beam_ssa:b_set()},
+ ls :: #{beam_ssa:label():=type_db()},
+ sub :: #{beam_ssa:var_name():=beam_ssa:value()}
+ }).
+
+-define(ATOM_SET_SIZE, 5).
+
+%% Records that represent type information.
+-record(t_atom, {elements=any :: 'any' | [atom()]}).
+-record(t_integer, {elements=any :: 'any' | {integer(),integer()}}).
+-record(t_bs_match, {type :: type()}).
+-record(t_tuple, {size=0 :: integer(),
+ exact=false :: boolean(),
+ elements=[] :: [any()]
+ }).
+
+-type type() :: 'any' | 'none' |
+ #t_atom{} | #t_integer{} | #t_bs_match{} | #t_tuple{} |
+ {'binary',pos_integer()} | 'cons' | 'float' | 'list' | 'map' | 'nil' |'number'.
+-type type_db() :: #{beam_ssa:var_name():=type()}.
+
+-spec opt([{Label0,Block0}], Args) -> [{Label,Block}] when
+ Label0 :: beam_ssa:label(),
+ Block0 :: beam_ssa:b_blk(),
+ Args :: [beam_ssa:b_var()],
+ Label :: beam_ssa:label(),
+ Block :: beam_ssa:b_blk().
+
+opt(Linear, Args) ->
+ Ts = maps:from_list([{V,any} || #b_var{}=V <- Args]),
+ FakeCall = #b_set{op=call,args=[#b_remote{mod=#b_literal{val=unknown},
+ name=#b_literal{val=unknown},
+ arity=0}]},
+ Defs = maps:from_list([{Var,FakeCall#b_set{dst=Var}} ||
+ #b_var{}=Var <- Args]),
+ D = #d{ds=Defs,ls=#{0=>Ts},sub=#{}},
+ opt_1(Linear, D).
+
+opt_1([{L,Blk}|Bs], #d{ls=Ls}=D) ->
+ case Ls of
+ #{L:=Ts} ->
+ opt_2(L, Blk, Bs, Ts, D);
+ #{} ->
+ %% This block is never reached. Discard it.
+ opt_1(Bs, D)
+ end;
+opt_1([], #d{}) -> [].
+
+opt_2(L, #b_blk{is=Is0}=Blk0, Bs, Ts, #d{sub=Sub}=D0) ->
+ case Is0 of
+ [#b_set{op=call,dst=Dst,
+ args=[#b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name}}=Rem|Args0]}=I0] ->
+ case erl_bifs:is_exit_bif(Mod, Name, length(Args0)) of
+ true ->
+ %% This call will never reach the successor block.
+ %% Rewrite the terminator to a 'ret', and remove
+ %% all type information for this label. That will
+ %% simplify the phi node in the former successor.
+ Args = simplify_args(Args0, Sub, Ts),
+ I = I0#b_set{args=[Rem|Args]},
+ Ret = #b_ret{arg=Dst},
+ Blk = Blk0#b_blk{is=[I],last=Ret},
+ Ls = maps:remove(L, D0#d.ls),
+ D = D0#d{ls=Ls},
+ [{L,Blk}|opt_1(Bs, D)];
+ false ->
+ opt_3(L, Blk0, Bs, Ts, D0)
+ end;
+ _ ->
+ opt_3(L, Blk0, Bs, Ts, D0)
+ end.
+
+opt_3(L, #b_blk{is=Is0,last=Last0}=Blk0, Bs, Ts0,
+ #d{ds=Ds0,ls=Ls0,sub=Sub0}=D0) ->
+ {Is,Ts,Ds,Sub} = opt_is(Is0, Ts0, Ds0, Ls0, Sub0, []),
+ D1 = D0#d{ds=Ds,sub=Sub},
+ Last1 = simplify_terminator(Last0, Sub, Ts),
+ Last = opt_terminator(Last1, Ts, Ds),
+ D = update_successors(Last, Ts, D1),
+ Blk = Blk0#b_blk{is=Is,last=Last},
+ [{L,Blk}|opt_1(Bs, D)].
+
+simplify_terminator(#b_br{bool=Bool}=Br, Sub, Ts) ->
+ Br#b_br{bool=simplify_arg(Bool, Sub, Ts)};
+simplify_terminator(#b_switch{arg=Arg}=Sw, Sub, Ts) ->
+ Sw#b_switch{arg=simplify_arg(Arg, Sub, Ts)};
+simplify_terminator(#b_ret{arg=Arg}=Ret, Sub, Ts) ->
+ Ret#b_ret{arg=simplify_arg(Arg, Sub, Ts)}.
+
+opt_is([#b_set{op=phi,dst=Dst,args=Args0}=I0|Is],
+ Ts0, Ds0, Ls, Sub0, Acc) ->
+ %% Simplify the phi node by removing all predecessor blocks that no
+ %% longer exists or no longer branches to this block.
+ Args = [{simplify_arg(Arg, Sub0, Ts0),From} ||
+ {Arg,From} <- Args0, maps:is_key(From, Ls)],
+ case all_same(Args) of
+ true ->
+ %% Eliminate the phi node if there is just one source
+ %% value or if the values are identical.
+ [{Val,_}|_] = Args,
+ Sub = Sub0#{Dst=>Val},
+ opt_is(Is, Ts0, Ds0, Ls, Sub, Acc);
+ false ->
+ I = I0#b_set{args=Args},
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{Dst=>I},
+ opt_is(Is, Ts, Ds, Ls, Sub0, [I|Acc])
+ end;
+opt_is([#b_set{args=Args0,dst=Dst}=I0|Is],
+ Ts0, Ds0, Ls, Sub0, Acc) ->
+ Args = simplify_args(Args0, Sub0, Ts0),
+ I1 = beam_ssa:normalize(I0#b_set{args=Args}),
+ case simplify(I1, Ts0) of
+ #b_set{}=I2 ->
+ I = beam_ssa:normalize(I2),
+ Ts = update_types(I, Ts0, Ds0),
+ Ds = Ds0#{Dst=>I},
+ opt_is(Is, Ts, Ds, Ls, Sub0, [I|Acc]);
+ #b_literal{}=Lit ->
+ Sub = Sub0#{Dst=>Lit},
+ opt_is(Is, Ts0, Ds0, Ls, Sub, Acc);
+ #b_var{}=Var ->
+ Sub = Sub0#{Dst=>Var},
+ opt_is(Is, Ts0, Ds0, Ls, Sub, Acc)
+ end;
+opt_is([], Ts, Ds, _Ls, Sub, Acc) ->
+ {reverse(Acc),Ts,Ds,Sub}.
+
+simplify(#b_set{op={bif,'and'},args=Args}=I, Ts) ->
+ case is_safe_bool_op(Args, Ts) of
+ true ->
+ case Args of
+ [_,#b_literal{val=false}=Res] -> Res;
+ [Res,#b_literal{val=true}] -> Res;
+ _ -> eval_bif(I, Ts)
+ end;
+ false ->
+ I
+ end;
+simplify(#b_set{op={bif,'or'},args=Args}=I, Ts) ->
+ case is_safe_bool_op(Args, Ts) of
+ true ->
+ case Args of
+ [Res,#b_literal{val=false}] -> Res;
+ [_,#b_literal{val=true}=Res] -> Res;
+ _ -> eval_bif(I, Ts)
+ end;
+ false ->
+ I
+ end;
+simplify(#b_set{op={bif,element},args=[#b_literal{val=Index},Tuple]}=I, Ts) ->
+ case t_tuple_size(get_type(Tuple, Ts)) of
+ {_,Size} when is_integer(Index), 1 =< Index, Index =< Size ->
+ I#b_set{op=get_tuple_element,args=[Tuple,#b_literal{val=Index-1}]};
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,hd},args=[List]}=I, Ts) ->
+ case get_type(List, Ts) of
+ cons ->
+ I#b_set{op=get_hd};
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,tl},args=[List]}=I, Ts) ->
+ case get_type(List, Ts) of
+ cons ->
+ I#b_set{op=get_tl};
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,size},args=[Term]}=I, Ts) ->
+ case get_type(Term, Ts) of
+ #t_tuple{} ->
+ simplify(I#b_set{op={bif,tuple_size}}, Ts);
+ _ ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,tuple_size},args=[Term]}=I, Ts) ->
+ case get_type(Term, Ts) of
+ #t_tuple{size=Size,exact=true} ->
+ #b_literal{val=Size};
+ _ ->
+ I
+ end;
+simplify(#b_set{op={bif,'=='},args=Args}=I, Ts) ->
+ Types = get_types(Args, Ts),
+ EqEq = case {meet(Types),join(Types)} of
+ {none,any} -> true;
+ {#t_integer{},#t_integer{}} -> true;
+ {float,float} -> true;
+ {{binary,_},_} -> true;
+ {#t_atom{},_} -> true;
+ {_,_} -> false
+ end,
+ case EqEq of
+ true ->
+ simplify(I#b_set{op={bif,'=:='}}, Ts);
+ false ->
+ eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,'=:='},args=[Same,Same]}, _Ts) ->
+ #b_literal{val=true};
+simplify(#b_set{op={bif,'=:='},args=Args}=I, Ts) ->
+ case meet(get_types(Args, Ts)) of
+ none -> #b_literal{val=false};
+ _ -> eval_bif(I, Ts)
+ end;
+simplify(#b_set{op={bif,Op},args=Args}=I, Ts) ->
+ Types = get_types(Args, Ts),
+ case is_float_op(Op, Types) of
+ false ->
+ eval_bif(I, Ts);
+ true ->
+ AnnoArgs = [anno_float_arg(A) || A <- Types],
+ eval_bif(beam_ssa:add_anno(float_op, AnnoArgs, I), Ts)
+ end;
+simplify(#b_set{op=get_tuple_element,args=[Tuple,#b_literal{val=0}]}=I, Ts) ->
+ case get_type(Tuple, Ts) of
+ #t_tuple{elements=[First]} ->
+ #b_literal{val=First};
+ #t_tuple{} ->
+ I
+ end;
+simplify(#b_set{op=is_nonempty_list,args=[Src]}=I, Ts) ->
+ case get_type(Src, Ts) of
+ any -> I;
+ list -> I;
+ cons -> #b_literal{val=true};
+ _ -> #b_literal{val=false}
+ end;
+simplify(#b_set{op=is_tagged_tuple,
+ args=[Src,#b_literal{val=Size},#b_literal{val=Tag}]}=I, Ts) ->
+ case get_type(Src, Ts) of
+ #t_tuple{exact=true,size=Size,elements=[Tag]} ->
+ #b_literal{val=true};
+ #t_tuple{exact=true,size=ActualSize,elements=[]} ->
+ if
+ Size =/= ActualSize ->
+ #b_literal{val=false};
+ true ->
+ I
+ end;
+ #t_tuple{exact=false} ->
+ I;
+ any ->
+ I;
+ _ ->
+ #b_literal{val=false}
+ end;
+simplify(#b_set{op=put_list,args=[#b_literal{val=H},
+ #b_literal{val=T}]}, _Ts) ->
+ #b_literal{val=[H|T]};
+simplify(#b_set{op=put_tuple,args=Args}=I, _Ts) ->
+ case make_literal_list(Args) of
+ none -> I;
+ List -> #b_literal{val=list_to_tuple(List)}
+ end;
+simplify(#b_set{op=succeeded,args=[#b_literal{}]}, _Ts) ->
+ #b_literal{val=true};
+simplify(#b_set{op=wait_timeout,args=[#b_literal{val=infinity}]}=I, _Ts) ->
+ I#b_set{op=wait,args=[]};
+simplify(I, _Ts) -> I.
+
+make_literal_list(Args) ->
+ make_literal_list(Args, []).
+
+make_literal_list([#b_literal{val=H}|T], Acc) ->
+ make_literal_list(T, [H|Acc]);
+make_literal_list([_|_], _) ->
+ none;
+make_literal_list([], Acc) ->
+ reverse(Acc).
+
+is_safe_bool_op(Args, Ts) ->
+ [T1,T2] = get_types(Args, Ts),
+ t_is_boolean(T1) andalso t_is_boolean(T2).
+
+all_same([{H,_}|T]) ->
+ all(fun({E,_}) -> E =:= H end, T).
+
+eval_bif(#b_set{op={bif,Bif},args=Args}=I, Ts) ->
+ Arity = length(Args),
+ case erl_bifs:is_pure(erlang, Bif, Arity) of
+ false ->
+ I;
+ true ->
+ case make_literal_list(Args) of
+ none ->
+ case get_types(Args, Ts) of
+ [any] ->
+ I;
+ [Type] ->
+ case will_succeed(Bif, Type) of
+ yes ->
+ #b_literal{val=true};
+ no ->
+ #b_literal{val=false};
+ maybe ->
+ I
+ end;
+ _ ->
+ I
+ end;
+ LitArgs ->
+ try apply(erlang, Bif, LitArgs) of
+ Val -> #b_literal{val=Val}
+ catch
+ error:_ -> I
+ end
+
+ end
+ end.
+
+simplify_args(Args, Sub, Ts) ->
+ [simplify_arg(Arg, Sub, Ts) || Arg <- Args].
+
+simplify_arg(#b_var{}=Arg0, Sub, Ts) ->
+ case sub_arg(Arg0, Sub) of
+ #b_literal{}=LitArg ->
+ LitArg;
+ #b_var{}=Arg ->
+ Type = get_type(Arg, Ts),
+ case get_literal_from_type(Type) of
+ none -> Arg;
+ #b_literal{}=Lit -> Lit
+ end
+ end;
+simplify_arg(#b_remote{mod=Mod,name=Name}=Rem, Sub, Ts) ->
+ Rem#b_remote{mod=simplify_arg(Mod, Sub, Ts),
+ name=simplify_arg(Name, Sub, Ts)};
+simplify_arg(Arg, _Sub, _Ts) -> Arg.
+
+sub_arg(#b_var{}=Old, Sub) ->
+ case Sub of
+ #{Old:=New} -> New;
+ #{} -> Old
+ end.
+
+is_float_op('-', [float]) ->
+ true;
+is_float_op('/', [_,_]) ->
+ true;
+is_float_op(Op, [float,_Other]) ->
+ is_float_op_1(Op);
+is_float_op(Op, [_Other,float]) ->
+ is_float_op_1(Op);
+is_float_op(_, _) -> false.
+
+is_float_op_1('+') -> true;
+is_float_op_1('-') -> true;
+is_float_op_1('*') -> true;
+is_float_op_1(_) -> false.
+
+anno_float_arg(float) -> float;
+anno_float_arg(_) -> convert.
+
+opt_terminator(#b_br{bool=#b_literal{}}=Br, _Ts, _Ds) ->
+ beam_ssa:normalize(Br);
+opt_terminator(#b_br{bool=#b_var{}=V}=Br, Ts, Ds) ->
+ #{V:=Set} = Ds,
+ case Set of
+ #b_set{op={bif,'=:='},args=[Bool,#b_literal{val=true}]} ->
+ case t_is_boolean(get_type(Bool, Ts)) of
+ true ->
+ %% Bool =:= true ==> Bool
+ simplify_not(Br#b_br{bool=Bool}, Ts, Ds);
+ false ->
+ Br
+ end;
+ #b_set{} ->
+ simplify_not(Br, Ts, Ds)
+ end;
+opt_terminator(#b_switch{arg=#b_literal{}}=Sw, _Ts, _Ds) ->
+ beam_ssa:normalize(Sw);
+opt_terminator(#b_switch{arg=#b_var{}=V}=Sw0, Ts, Ds) ->
+ Type = get_type(V, Ts),
+ case Type of
+ #t_integer{elements={_,_}=Range} ->
+ simplify_switch_int(Sw0, Range);
+ _ ->
+ case t_is_boolean(Type) of
+ true ->
+ case simplify_switch_bool(Sw0, Ts, Ds) of
+ #b_br{}=Br ->
+ opt_terminator(Br, Ts, Ds);
+ Sw ->
+ beam_ssa:normalize(Sw)
+ end;
+ false ->
+ beam_ssa:normalize(Sw0)
+ end
+ end;
+opt_terminator(#b_ret{}=Ret, _Ts, _Ds) -> Ret.
+
+update_successors(#b_br{bool=#b_literal{val=true},succ=S}, Ts, D) ->
+ update_successor(S, Ts, D);
+update_successors(#b_br{bool=#b_var{}=Bool,succ=Succ,fail=Fail}, Ts, D0) ->
+ D = update_successor_bool(Bool, false, Fail, Ts, D0),
+ SuccTs = infer_types(Bool, Ts, D0),
+ update_successor_bool(Bool, true, Succ, SuccTs, D);
+update_successors(#b_switch{arg=#b_var{}=V,fail=Fail,list=List}, Ts, D0) ->
+ D = update_successor(Fail, Ts, D0),
+ foldl(fun({Val,S}, A) ->
+ T = get_type(Val, Ts),
+ update_successor(S, Ts#{V=>T}, A)
+ end, D, List);
+update_successors(#b_ret{}, _Ts, D) -> D.
+
+update_successor_bool(#b_var{}=Var, BoolValue, S, Ts, D) ->
+ case t_is_boolean(get_type(Var, Ts)) of
+ true ->
+ update_successor(S, Ts#{Var:=t_atom(BoolValue)}, D);
+ false ->
+ %% The `br` terminator is preceeded by an instruction that
+ %% does not produce a boolean value, such a `new_try_tag`.
+ update_successor(S, Ts, D)
+ end.
+
+update_successor(S, Ts0, #d{ls=Ls}=D) ->
+ case Ls of
+ #{S:=Ts1} ->
+ Ts = join_types(Ts0, Ts1),
+ D#d{ls=Ls#{S:=Ts}};
+ #{} ->
+ D#d{ls=Ls#{S=>Ts0}}
+ end.
+
+update_types(#b_set{op=Op,dst=Dst,args=Args}, Ts, Ds) ->
+ T = type(Op, Args, Ts, Ds),
+ Ts#{Dst=>T}.
+
+type(phi, Args, Ts, _Ds) ->
+ Types = [get_type(A, Ts) || {A,_} <- Args],
+ join(Types);
+type({bif,'band'}, Args, Ts, _Ds) ->
+ band_type(Args, Ts);
+type({bif,Bif}, Args, Ts, _Ds) ->
+ case bif_type(Bif, Args) of
+ number ->
+ arith_op_type(Args, Ts);
+ Type ->
+ Type
+ end;
+type(bs_init, [#b_literal{val=Type}|Args], _Ts, _Ds) ->
+ case {Type,Args} of
+ {new,[_,#b_literal{val=Unit}]} ->
+ {binary,Unit};
+ {append,[_,_,#b_literal{val=Unit}]} ->
+ {binary,Unit};
+ {private_append,[_,_,#b_literal{val=Unit}]} ->
+ {binary,Unit}
+ end;
+type(bs_extract, [Ctx], Ts, _Ds) ->
+ #t_bs_match{type=Type} = get_type(Ctx, Ts),
+ Type;
+type(bs_match, Args, _Ts, _Ds) ->
+ #t_bs_match{type=bs_match_type(Args)};
+type(bs_get_tail, _Args, _Ts, _Ds) ->
+ {binary, 1};
+type(call, [#b_remote{mod=#b_literal{val=Mod},
+ name=#b_literal{val=Name}}|Args], Ts, _Ds) ->
+ case {Mod,Name,Args} of
+ {erlang,setelement,[Pos,Tuple,_]} ->
+ case {get_type(Pos, Ts),get_type(Tuple, Ts)} of
+ {#t_integer{elements={MinIndex,_}},#t_tuple{}=T}
+ when MinIndex > 1 ->
+ %% First element is not updated. The result
+ %% will have the same type.
+ T;
+ {_,#t_tuple{}=T} ->
+ %% Position is 1 or unknown. May update the first
+ %% element of the tuple.
+ T#t_tuple{elements=[]};
+ {#t_integer{elements={MinIndex,_}},_} ->
+ #t_tuple{size=MinIndex};
+ {_,_} ->
+ #t_tuple{}
+ end;
+ {math,_,_} ->
+ case is_math_bif(Name, length(Args)) of
+ false -> any;
+ true -> float
+ end;
+ {_,_,_} ->
+ case erl_bifs:is_exit_bif(Mod, Name, length(Args)) of
+ true -> none;
+ false -> any
+ end
+ end;
+type(is_nonempty_list, [_], _Ts, _Ds) ->
+ t_boolean();
+type(is_tagged_tuple, [_,#b_literal{},#b_literal{}], _Ts, _Ds) ->
+ t_boolean();
+type(put_map, _Args, _Ts, _Ds) ->
+ map;
+type(put_list, _Args, _Ts, _Ds) ->
+ cons;
+type(put_tuple, Args, _Ts, _Ds) ->
+ case Args of
+ [#b_literal{val=First}|_] ->
+ #t_tuple{exact=true,size=length(Args),elements=[First]};
+ _ ->
+ #t_tuple{exact=true,size=length(Args)}
+ end;
+type(succeeded, [#b_var{}=Src], Ts, Ds) ->
+ case maps:get(Src, Ds) of
+ #b_set{op={bif,Bif},args=BifArgs} ->
+ Types = get_types(BifArgs, Ts),
+ case {Bif,Types} of
+ {BoolOp,[T1,T2]} when BoolOp =:= 'and'; BoolOp =:= 'or' ->
+ case t_is_boolean(T1) andalso t_is_boolean(T2) of
+ true -> t_atom(true);
+ false -> t_boolean()
+ end;
+ {byte_size,[{binary,_}]} ->
+ t_atom(true);
+ {bit_size,[{binary,_}]} ->
+ t_atom(true);
+ {map_size,[map]} ->
+ t_atom(true);
+ {'not',[Type]} ->
+ case t_is_boolean(Type) of
+ true -> t_atom(true);
+ false -> t_boolean()
+ end;
+ {size,[{binary,_}]} ->
+ t_atom(true);
+ {tuple_size,[#t_tuple{}]} ->
+ t_atom(true);
+ {_,_} ->
+ t_boolean()
+ end;
+ #b_set{op=get_hd} ->
+ t_atom(true);
+ #b_set{op=get_tl} ->
+ t_atom(true);
+ #b_set{op=get_tuple_element} ->
+ t_atom(true);
+ #b_set{op=wait} ->
+ t_atom(false);
+ #b_set{} ->
+ t_boolean()
+ end;
+type(_, _, _, _) -> any.
+
+arith_op_type(Args, Ts) ->
+ Types = get_types(Args, Ts),
+ foldl(fun(#t_integer{}, unknown) -> t_integer();
+ (#t_integer{}, number) -> number;
+ (#t_integer{}, float) -> float;
+ (#t_integer{}, #t_integer{}) -> t_integer();
+ (float, unknown) -> float;
+ (float, #t_integer{}) -> float;
+ (float, number) -> float;
+ (number, unknown) -> number;
+ (number, #t_integer{}) -> number;
+ (number, float) -> float;
+ (any, _) -> number;
+ (Same, Same) -> Same;
+ (_, _) -> none
+ end, unknown, Types).
+
+%% will_succeed(TestOperation, Type) -> yes|no|maybe.
+%% Test whether TestOperation applied to an argument of type Type
+%% will succeed. Return yes, no, or maybe.
+%%
+%% Type is a type as described in the comment for verified_type/1 at
+%% the very end of this file, but it will *never* be 'any'.
+
+will_succeed(is_atom, Type) ->
+ case Type of
+ #t_atom{} -> yes;
+ _ -> no
+ end;
+will_succeed(is_binary, Type) ->
+ case Type of
+ {binary,U} when U rem 8 =:= 0 -> yes;
+ {binary,_} -> maybe;
+ _ -> no
+ end;
+will_succeed(is_bitstring, Type) ->
+ case Type of
+ {binary,_} -> yes;
+ _ -> no
+ end;
+will_succeed(is_boolean, Type) ->
+ case Type of
+ #t_atom{elements=any} ->
+ maybe;
+ #t_atom{elements=Es} ->
+ case t_is_boolean(Type) of
+ true ->
+ yes;
+ false ->
+ case any(fun is_boolean/1, Es) of
+ true -> maybe;
+ false -> no
+ end
+ end;
+ _ ->
+ no
+ end;
+will_succeed(is_float, Type) ->
+ case Type of
+ float -> yes;
+ number -> maybe;
+ _ -> no
+ end;
+will_succeed(is_integer, Type) ->
+ case Type of
+ #t_integer{} -> yes;
+ number -> maybe;
+ _ -> no
+ end;
+will_succeed(is_list, Type) ->
+ case Type of
+ list -> yes;
+ cons -> yes;
+ _ -> no
+ end;
+will_succeed(is_map, Type) ->
+ case Type of
+ map -> yes;
+ _ -> no
+ end;
+will_succeed(is_number, Type) ->
+ case Type of
+ float -> yes;
+ #t_integer{} -> yes;
+ number -> yes;
+ _ -> no
+ end;
+will_succeed(is_tuple, Type) ->
+ case Type of
+ #t_tuple{} -> yes;
+ _ -> no
+ end;
+will_succeed(_, _) -> maybe.
+
+
+band_type([Other,#b_literal{val=Int}], Ts) when is_integer(Int) ->
+ band_type_1(Int, Other, Ts);
+band_type([_,_], _) -> t_integer().
+
+band_type_1(Int, OtherSrc, Ts) ->
+ Type = band_type_2(Int, 0),
+ OtherType = get_type(OtherSrc, Ts),
+ meet(Type, OtherType).
+
+band_type_2(N, Bits) when Bits < 64 ->
+ case 1 bsl Bits of
+ P when P =:= N + 1 ->
+ t_integer(0, N);
+ P when P > N + 1 ->
+ t_integer();
+ _ ->
+ band_type_2(N, Bits+1)
+ end;
+band_type_2(_, _) ->
+ %% Negative or large positive number. Give up.
+ t_integer().
+
+bs_match_type([#b_literal{val=Type}|Args]) ->
+ bs_match_type(Type, Args).
+
+bs_match_type(binary, Args) ->
+ [_,_,_,#b_literal{val=U}] = Args,
+ {binary,U};
+bs_match_type(float, _) ->
+ float;
+bs_match_type(integer, Args) ->
+ case Args of
+ [_,
+ #b_literal{val=Flags},
+ #b_literal{val=Size},
+ #b_literal{val=Unit}] when Size * Unit < 64 ->
+ NumBits = Size * Unit,
+ case member(unsigned, Flags) of
+ true ->
+ t_integer(0, (1 bsl NumBits)-1);
+ false ->
+ %% Signed integer. Don't bother.
+ t_integer()
+ end;
+ [_|_] ->
+ t_integer()
+ end;
+bs_match_type(skip, _) ->
+ any;
+bs_match_type(string, _) ->
+ any;
+bs_match_type(utf8, _) ->
+ ?UNICODE_INT;
+bs_match_type(utf16, _) ->
+ ?UNICODE_INT;
+bs_match_type(utf32, _) ->
+ ?UNICODE_INT.
+
+simplify_switch_int(#b_switch{list=List0}=Sw, {Min,Max}) ->
+ List1 = sort(List0),
+ Vs = [V || {#b_literal{val=V},_} <- List1],
+ case eq_ranges(Vs, Min, Max) of
+ true ->
+ {_,LastL} = last(List1),
+ List = droplast(List1),
+ Sw#b_switch{fail=LastL,list=List};
+ false ->
+ Sw
+ end.
+
+eq_ranges([H], H, H) -> true;
+eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
+eq_ranges(_, _, _) -> false.
+
+simplify_switch_bool(#b_switch{arg=B,list=List0}=Sw, Ts, Ds) ->
+ List = sort(List0),
+ case List of
+ [{#b_literal{val=false},Fail},{#b_literal{val=true},Succ}] ->
+ simplify_not(#b_br{bool=B,succ=Succ,fail=Fail}, Ts, Ds);
+ [_|_] ->
+ Sw
+ end.
+
+simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) ->
+ case Ds of
+ #{V:=#b_set{op={bif,'not'},args=[Bool]}} ->
+ case t_is_boolean(get_type(Bool, Ts)) of
+ true ->
+ Br = Br0#b_br{bool=Bool,succ=Fail,fail=Succ},
+ beam_ssa:normalize(Br);
+ false ->
+ Br0
+ end;
+ #{} ->
+ Br0
+ end.
+
+get_types(Values, Ts) ->
+ [get_type(Val, Ts) || Val <- Values].
+-spec get_type(beam_ssa:value(), type_db()) -> type().
+
+get_type(#b_var{}=V, Ts) ->
+ #{V:=T} = Ts,
+ T;
+get_type(#b_literal{val=Val}, _Ts) ->
+ if
+ is_atom(Val) ->
+ t_atom(Val);
+ is_float(Val) ->
+ float;
+ is_integer(Val) ->
+ t_integer(Val);
+ is_list(Val), Val =/= [] ->
+ cons;
+ is_map(Val) ->
+ map;
+ Val =:= {} ->
+ #t_tuple{exact=true};
+ is_tuple(Val) ->
+ #t_tuple{exact=true,size=tuple_size(Val),
+ elements=[element(1, Val)]};
+ Val =:= [] ->
+ nil;
+ true ->
+ any
+ end.
+
+infer_types(#b_var{}=V, Ts, #d{ds=Ds}) ->
+ #{V:=#b_set{op=Op,args=Args}} = Ds,
+ Types = infer_type(Op, Args, Ds),
+ meet_types(Types, Ts).
+
+infer_type({bif,element}, [#b_literal{val=Pos},#b_var{}=Tuple], _Ds) ->
+ if
+ is_integer(Pos), 1 =< Pos ->
+ [{Tuple,#t_tuple{size=Pos}}];
+ true ->
+ []
+ end;
+infer_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ds) ->
+ Def = maps:get(Src, Ds),
+ Type = get_type(Lit, #{}),
+ [{Src,Type}|infer_tuple_size(Def, Lit) ++
+ infer_first_element(Def, Lit)];
+infer_type({bif,Bif}, [#b_var{}=Src]=Args, _Ds) ->
+ case inferred_bif_type(Bif, Args) of
+ any -> [];
+ T -> [{Src,T}]
+ end;
+infer_type({bif,is_map_key}, [_,#b_var{}=Src], _Ds) ->
+ [{Src,map}];
+infer_type({bif,map_get}, [_,#b_var{}=Src], _Ds) ->
+ [{Src,map}];
+infer_type(bs_start_match, [#b_var{}=Bin], _Ds) ->
+ [{Bin,{binary,1}}];
+infer_type(is_nonempty_list, [#b_var{}=Src], _Ds) ->
+ [{Src,cons}];
+infer_type(is_tagged_tuple, [#b_var{}=Src,#b_literal{val=Size},
+ #b_literal{val=Tag}], _Ds) ->
+ [{Src,#t_tuple{exact=true,size=Size,elements=[Tag]}}];
+infer_type(succeeded, [#b_var{}=Src], Ds) ->
+ #b_set{op=Op,args=Args} = maps:get(Src, Ds),
+ infer_type(Op, Args, Ds);
+infer_type(_Op, _Args, _Ds) ->
+ [].
+
+%% bif_type(Name, Args) -> Type
+%% Return the return type for the guard BIF or operator Name with
+%% arguments Args.
+%%
+%% Note that that the following BIFs are handle elsewhere:
+%%
+%% band/2
+
+bif_type(abs, [_]) -> number;
+bif_type(bit_size, [_]) -> t_integer();
+bif_type(byte_size, [_]) -> t_integer();
+bif_type(ceil, [_]) -> t_integer();
+bif_type(float, [_]) -> float;
+bif_type(floor, [_]) -> t_integer();
+bif_type(is_map_key, [_,_]) -> t_boolean();
+bif_type(length, [_]) -> t_integer();
+bif_type(map_size, [_]) -> t_integer();
+bif_type(node, []) -> #t_atom{};
+bif_type(node, [_]) -> #t_atom{};
+bif_type(round, [_]) -> t_integer();
+bif_type(size, [_]) -> t_integer();
+bif_type(trunc, [_]) -> t_integer();
+bif_type(tuple_size, [_]) -> t_integer();
+bif_type('bnot', [_]) -> t_integer();
+bif_type('bor', [_,_]) -> t_integer();
+bif_type('bsl', [_,_]) -> t_integer();
+bif_type('bsr', [_,_]) -> t_integer();
+bif_type('bxor', [_,_]) -> t_integer();
+bif_type('div', [_,_]) -> t_integer();
+bif_type('rem', [_,_]) -> t_integer();
+bif_type('/', [_,_]) -> float;
+bif_type(Name, Args) ->
+ Arity = length(Args),
+ case erl_internal:new_type_test(Name, Arity) orelse
+ erl_internal:bool_op(Name, Arity) orelse
+ erl_internal:comp_op(Name, Arity) of
+ true ->
+ t_boolean();
+ false ->
+ case erl_internal:arith_op(Name, Arity) of
+ true -> number;
+ false -> any
+ end
+ end.
+
+inferred_bif_type(is_atom, [_]) -> t_atom();
+inferred_bif_type(is_binary, [_]) -> {binary,8};
+inferred_bif_type(is_bitstring, [_]) -> {binary,1};
+inferred_bif_type(is_boolean, [_]) -> t_boolean();
+inferred_bif_type(is_float, [_]) -> float;
+inferred_bif_type(is_integer, [_]) -> t_integer();
+inferred_bif_type(is_list, [_]) -> list;
+inferred_bif_type(is_map, [_]) -> map;
+inferred_bif_type(is_number, [_]) -> number;
+inferred_bif_type(is_tuple, [_]) -> #t_tuple{};
+inferred_bif_type(abs, [_]) -> number;
+inferred_bif_type(bit_size, [_]) -> {binary,1};
+inferred_bif_type(byte_size, [_]) -> {binary,1};
+inferred_bif_type(ceil, [_]) -> number;
+inferred_bif_type(float, [_]) -> number;
+inferred_bif_type(floor, [_]) -> number;
+inferred_bif_type(hd, [_]) -> cons;
+inferred_bif_type(length, [_]) -> list;
+inferred_bif_type(map_size, [_]) -> map;
+inferred_bif_type(round, [_]) -> number;
+inferred_bif_type(trunc, [_]) -> number;
+inferred_bif_type(tl, [_]) -> cons;
+inferred_bif_type(tuple_size, [_]) -> #t_tuple{};
+inferred_bif_type(_, _) -> any.
+
+infer_tuple_size(#b_set{op={bif,tuple_size},args=[#b_var{}=Tuple]},
+ #b_literal{val=Size}) when is_integer(Size) ->
+ [{Tuple,#t_tuple{exact=true,size=Size}}];
+infer_tuple_size(_, _) -> [].
+
+infer_first_element(#b_set{op=get_tuple_element,
+ args=[#b_var{}=Tuple,#b_literal{val=0}]},
+ #b_literal{val=First}) ->
+ [{Tuple,#t_tuple{size=1,elements=[First]}}];
+infer_first_element(_, _) -> [].
+
+is_math_bif(cos, 1) -> true;
+is_math_bif(cosh, 1) -> true;
+is_math_bif(sin, 1) -> true;
+is_math_bif(sinh, 1) -> true;
+is_math_bif(tan, 1) -> true;
+is_math_bif(tanh, 1) -> true;
+is_math_bif(acos, 1) -> true;
+is_math_bif(acosh, 1) -> true;
+is_math_bif(asin, 1) -> true;
+is_math_bif(asinh, 1) -> true;
+is_math_bif(atan, 1) -> true;
+is_math_bif(atanh, 1) -> true;
+is_math_bif(erf, 1) -> true;
+is_math_bif(erfc, 1) -> true;
+is_math_bif(exp, 1) -> true;
+is_math_bif(log, 1) -> true;
+is_math_bif(log2, 1) -> true;
+is_math_bif(log10, 1) -> true;
+is_math_bif(sqrt, 1) -> true;
+is_math_bif(atan2, 2) -> true;
+is_math_bif(pow, 2) -> true;
+is_math_bif(ceil, 1) -> true;
+is_math_bif(floor, 1) -> true;
+is_math_bif(fmod, 2) -> true;
+is_math_bif(pi, 0) -> true;
+is_math_bif(_, _) -> false.
+
+join_types(Ts0, Ts1) ->
+ if
+ map_size(Ts0) < map_size(Ts1) ->
+ join_types_1(maps:keys(Ts0), Ts1, Ts0);
+ true ->
+ join_types_1(maps:keys(Ts1), Ts0, Ts1)
+ end.
+
+join_types_1([V|Vs], Ts0, Ts1) ->
+ case {Ts0,Ts1} of
+ {#{V:=Same},#{V:=Same}} ->
+ join_types_1(Vs, Ts0, Ts1);
+ {#{V:=T0},#{V:=T1}} ->
+ case join(T0, T1) of
+ T1 ->
+ join_types_1(Vs, Ts0, Ts1);
+ T ->
+ join_types_1(Vs, Ts0, Ts1#{V:=T})
+ end;
+ {#{},#{V:=_}} ->
+ join_types_1(Vs, Ts0, Ts1)
+ end;
+join_types_1([], Ts0, Ts1) ->
+ maps:merge(Ts0, Ts1).
+
+join([T1,T2|Ts]) ->
+ join([join(T1, T2)|Ts]);
+join([T]) -> T.
+
+get_literal_from_type(#t_atom{elements=[Atom]}) ->
+ #b_literal{val=Atom};
+get_literal_from_type(#t_integer{elements={Int,Int}}) ->
+ #b_literal{val=Int};
+get_literal_from_type(nil) ->
+ #b_literal{val=[]};
+get_literal_from_type(_) -> none.
+
+t_atom() ->
+ #t_atom{elements=any}.
+
+t_atom(Atom) when is_atom(Atom) ->
+ #t_atom{elements=[Atom]}.
+
+t_boolean() ->
+ #t_atom{elements=[false,true]}.
+
+t_integer() ->
+ #t_integer{elements=any}.
+
+t_integer(Int) when is_integer(Int) ->
+ #t_integer{elements={Int,Int}}.
+
+t_integer(Min, Max) when is_integer(Min), is_integer(Max) ->
+ #t_integer{elements={Min,Max}}.
+
+t_is_boolean(#t_atom{elements=[F,T]}) ->
+ F =:= false andalso T =:= true;
+t_is_boolean(#t_atom{elements=[B]}) ->
+ is_boolean(B);
+t_is_boolean(_) -> false.
+
+t_tuple_size(#t_tuple{size=Size,exact=false}) ->
+ {at_least,Size};
+t_tuple_size(#t_tuple{size=Size,exact=true}) ->
+ {exact,Size};
+t_tuple_size(_) ->
+ none.
+
+%% join(Type1, Type2) -> Type
+%% Return the "join" of Type1 and Type2. The join is a more general
+%% type than Type1 and Type2. For example:
+%%
+%% join(#t_integer{elements=any}, #t_integer=elements={0,3}}) ->
+%% #t_integer{}
+%%
+%% The join for two different types result in 'any', which is
+%% the top element for our type lattice:
+%%
+%% join(#t_integer{}, map) -> any
+
+-spec join(type(), type()) -> type().
+
+join(T, T) ->
+ verified_type(T);
+join(none, T) ->
+ verified_type(T);
+join(T, none) ->
+ verified_type(T);
+join(any, _) -> any;
+join(_, any) -> any;
+join(#t_atom{elements=[_|_]=Set1}, #t_atom{elements=[_|_]=Set2}) ->
+ Set = ordsets:union(Set1, Set2),
+ case ordsets:size(Set) of
+ Size when Size =< ?ATOM_SET_SIZE ->
+ #t_atom{elements=Set};
+ _Size ->
+ #t_atom{elements=any}
+ end;
+join(#t_atom{elements=any}=T, #t_atom{elements=[_|_]}) -> T;
+join(#t_atom{elements=[_|_]}, #t_atom{elements=any}=T) -> T;
+join({binary,U1}, {binary,U2}) ->
+ {binary,gcd(U1, U2)};
+join(#t_integer{}, #t_integer{}) -> t_integer();
+join(list, cons) -> list;
+join(cons, list) -> list;
+join(nil, cons) -> list;
+join(cons, nil) -> list;
+join(nil, list) -> list;
+join(list, nil) -> list;
+join(#t_integer{}, float) -> number;
+join(float, #t_integer{}) -> number;
+join(#t_integer{}, number) -> number;
+join(number, #t_integer{}) -> number;
+join(float, number) -> number;
+join(number, float) -> number;
+join(#t_tuple{size=Sz,exact=Exact1}, #t_tuple{size=Sz,exact=Exact2}) ->
+ Exact = Exact1 and Exact2,
+ #t_tuple{size=Sz,exact=Exact};
+join(#t_tuple{size=Sz1}, #t_tuple{size=Sz2}) ->
+ #t_tuple{size=min(Sz1, Sz2)};
+join(_T1, _T2) ->
+ %%io:format("~p ~p\n", [_T1,_T2]),
+ any.
+
+gcd(A, B) ->
+ case A rem B of
+ 0 -> B;
+ X -> gcd(B, X)
+ end.
+
+meet_types([{V,T0}|Vs], Ts) ->
+ #{V:=T1} = Ts,
+ T = meet(T0, T1),
+ meet_types(Vs, Ts#{V:=T});
+meet_types([], Ts) -> Ts.
+
+meet([T1,T2|Ts]) ->
+ meet([meet(T1, T2)|Ts]);
+meet([T]) -> T.
+
+%% meet(Type1, Type2) -> Type
+%% Return the "meet" of Type1 and Type2. The meet is a narrower
+%% type than Type1 and Type2. For example:
+%%
+%% meet(#t_integer{elements=any}, #t_integer{elements={0,3}}) ->
+%% #t_integer{elements={0,3}}
+%%
+%% The meet for two different types result in 'none', which is
+%% the bottom element for our type lattice:
+%%
+%% meet(#t_integer{}, map) -> none
+
+-spec meet(type(), type()) -> type().
+
+meet(T, T) ->
+ verified_type(T);
+meet(#t_atom{elements=[_|_]=Set1}, #t_atom{elements=[_|_]=Set2}) ->
+ case ordsets:intersection(Set1, Set2) of
+ [] ->
+ none;
+ [_|_]=Set ->
+ #t_atom{elements=Set}
+ end;
+meet(#t_atom{elements=[_|_]}=T, #t_atom{elements=any}) ->
+ T;
+meet(#t_atom{elements=any}, #t_atom{elements=[_|_]}=T) ->
+ T;
+meet(#t_integer{elements={_,_}}=T, #t_integer{elements=any}) ->
+ T;
+meet(#t_integer{elements=any}, #t_integer{elements={_,_}}=T) ->
+ T;
+meet(#t_integer{elements={Min1,Max1}},
+ #t_integer{elements={Min2,Max2}}) ->
+ #t_integer{elements={max(Min1, Min2),min(Max1, Max2)}};
+meet(#t_integer{}=T, number) -> T;
+meet(float=T, number) -> T;
+meet(number, #t_integer{}=T) -> T;
+meet(number, float=T) -> T;
+meet(list, cons) -> cons;
+meet(list, nil) -> nil;
+meet(cons, list) -> cons;
+meet(nil, list) -> nil;
+meet(#t_tuple{}=T1, #t_tuple{}=T2) ->
+ meet_tuples(T1, T2);
+meet({binary,U1}, {binary,U2}) ->
+ {binary,max(U1, U2)};
+meet(any, T) ->
+ verified_type(T);
+meet(T, any) ->
+ verified_type(T);
+meet(_, _) ->
+ %% Inconsistent types. There will be an exception at runtime.
+ none.
+
+meet_tuples(#t_tuple{elements=[E1]}, #t_tuple{elements=[E2]})
+ when E1 =/= E2 ->
+ none;
+meet_tuples(#t_tuple{size=Sz1,exact=true},
+ #t_tuple{size=Sz2,exact=true}) when Sz1 =/= Sz2 ->
+ none;
+meet_tuples(#t_tuple{size=Sz1,exact=Ex1,elements=Es1},
+ #t_tuple{size=Sz2,exact=Ex2,elements=Es2}) ->
+ Size = max(Sz1, Sz2),
+ Exact = Ex1 or Ex2,
+ Es = case {Es1,Es2} of
+ {[],[_|_]} -> Es2;
+ {[_|_],[]} -> Es1;
+ {_,_} -> Es1
+ end,
+ #t_tuple{size=Size,exact=Exact,elements=Es}.
+
+%% verified_type(Type) -> Type
+%% Returns the passed in type if it is one of the defined types.
+%% Crashes if there is anything wrong with the type.
+%%
+%% Here are all possible types:
+%%
+%% any Any Erlang term (top element for the type lattice).
+%%
+%% #t_atom{} Any atom or some specific atoms.
+%% {binary,Unit} Binary/bitstring aligned to unit Unit.
+%% float Floating point number.
+%% #t_integer{} Integer
+%% list Empty or nonempty list.
+%% map Map.
+%% nil Empty list.
+%% cons Cons (nonempty list).
+%% number A number (float or integer).
+%% #t_tuple{} Tuple.
+%%
+%% none No type (bottom element for the type lattice).
+
+-spec verified_type(T) -> T when
+ T :: type().
+
+verified_type(any=T) -> T;
+verified_type(none=T) -> T;
+verified_type(#t_atom{elements=any}=T) -> T;
+verified_type(#t_atom{elements=[_|_]}=T) -> T;
+verified_type({binary,U}=T) when is_integer(U) -> T;
+verified_type(#t_integer{elements=any}=T) -> T;
+verified_type(#t_integer{elements={Min,Max}}=T)
+ when is_integer(Min), is_integer(Max) -> T;
+verified_type(list=T) -> T;
+verified_type(map=T) -> T;
+verified_type(nil=T) -> T;
+verified_type(cons=T) -> T;
+verified_type(number=T) -> T;
+verified_type(#t_tuple{}=T) -> T;
+verified_type(float=T) -> T.
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 4da0985085..1acbedd45b 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -288,7 +288,7 @@ frame_size([{get_map_elements,{f,L},_,_}|Is], Safe) ->
frame_size([{deallocate,N}|_], _) -> N;
frame_size([{line,_}|Is], Safe) ->
frame_size(Is, Safe);
-frame_size([_|_], _) -> throw(not_possible).
+frame_size(_, _) -> throw(not_possible).
frame_size_branch(0, Is, Safe) ->
frame_size(Is, Safe);
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
deleted file mode 100644
index b5c979e529..0000000000
--- a/lib/compiler/src/beam_type.erl
+++ /dev/null
@@ -1,1117 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose: Type-based optimisations. See the comment for verified_type/1
-%% the very end of this file for a description of the types in the
-%% type database.
-
--module(beam_type).
-
--export([module/2]).
-
--import(lists, [foldl/3,member/2,reverse/1,reverse/2,sort/1]).
-
--define(UNICODE_INT, {integer,{0,16#10FFFF}}).
-
--spec module(beam_utils:module_code(), [compile:option()]) ->
- {'ok',beam_utils:module_code()}.
-
-module({Mod,Exp,Attr,Fs0,Lc}, _Opts) ->
- Fs = [function(F) || F <- Fs0],
- {ok,{Mod,Exp,Attr,Fs,Lc}}.
-
-function({function,Name,Arity,CLabel,Asm0}) ->
- try
- Asm1 = beam_utils:live_opt(Asm0),
- Asm2 = opt(Asm1, [], tdb_new()),
- Asm3 = beam_utils:live_opt(Asm2),
- Asm = beam_utils:delete_annos(Asm3),
- {function,Name,Arity,CLabel,Asm}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-%% opt([Instruction], Accumulator, TypeDb) -> {[Instruction'],TypeDb'}
-%% Keep track of type information; try to simplify.
-
-opt([{block,Body1}|Is], [{block,Body0}|Acc], Ts0) ->
- {Body2,Ts} = simplify(Body1, Ts0),
- Body = merge_blocks(Body0, Body2),
- opt(Is, [{block,Body}|Acc], Ts);
-opt([{block,Body0}|Is], Acc, Ts0) ->
- {Body,Ts} = simplify(Body0, Ts0),
- opt(Is, [{block,Body}|Acc], Ts);
-opt([I0|Is], Acc, Ts0) ->
- case simplify_basic([I0], Ts0) of
- {[],Ts} -> opt(Is, Acc, Ts);
- {[I],Ts} -> opt(Is, [I|Acc], Ts)
- end;
-opt([], Acc, _) -> reverse(Acc).
-
-%% simplify(Instruction, TypeDb) -> NewInstruction
-%% Simplify an instruction using type information (this is
-%% technically a "strength reduction").
-
-simplify(Is0, TypeDb0) ->
- {Is,_} = BasicRes = simplify_basic(Is0, TypeDb0),
- case simplify_float(Is, TypeDb0) of
- not_possible -> BasicRes;
- {_,_}=Res -> Res
- end.
-
-%% simplify_basic([Instruction], TypeDatabase) -> {[Instruction],TypeDatabase'}
-%% Basic simplification, mostly tuples, no floating point optimizations.
-
-simplify_basic(Is, Ts) ->
- simplify_basic(Is, Ts, []).
-
-simplify_basic([I0|Is], Ts0, Acc) ->
- case simplify_instr(I0, Ts0) of
- [] ->
- simplify_basic(Is, Ts0, Acc);
- [I] ->
- Ts = update(I, Ts0),
- simplify_basic(Is, Ts, [I|Acc])
- end;
-simplify_basic([], Ts, Acc) ->
- {reverse(Acc),Ts}.
-
-%% simplify_instr(Instruction, Ts) -> [Instruction].
-
-%% Simplify a simple instruction using type information. Return an
-%% empty list if the instruction should be removed, or a list with
-%% the original or modified instruction.
-
-simplify_instr({set,[D],[{integer,Index},Reg],{bif,element,_}}=I, Ts) ->
- case max_tuple_size(Reg, Ts) of
- Sz when 0 < Index, Index =< Sz ->
- [{set,[D],[Reg],{get_tuple_element,Index-1}}];
- _ -> [I]
- end;
-simplify_instr({test,Test,Fail,[R]}=I, Ts) ->
- case tdb_find(R, Ts) of
- any ->
- [I];
- Type ->
- case will_succeed(Test, Type) of
- yes -> [];
- no -> [{jump,Fail}];
- maybe -> [I]
- end
- end;
-simplify_instr({set,[D],[TupleReg],{get_tuple_element,0}}=I, Ts) ->
- case tdb_find(TupleReg, Ts) of
- {tuple,_,_,[Contents]} ->
- [{set,[D],[Contents],move}];
- _ ->
- [I]
- end;
-simplify_instr({test,test_arity,_,[R,Arity]}=I, Ts) ->
- case tdb_find(R, Ts) of
- {tuple,exact_size,Arity,_} -> [];
- _ -> [I]
- end;
-simplify_instr({test,is_eq_exact,Fail,[R,{atom,A}=Atom]}=I, Ts) ->
- case tdb_find(R, Ts) of
- {atom,_}=Atom -> [];
- boolean when is_boolean(A) -> [I];
- any -> [I];
- _ -> [{jump,Fail}]
- end;
-simplify_instr({test,is_record,_,[R,{atom,_}=Tag,{integer,Arity}]}=I, Ts) ->
- case tdb_find(R, Ts) of
- {tuple,exact_size,Arity,[Tag]} -> [];
- _ -> [I]
- end;
-simplify_instr({select,select_val,Reg,_,_}=I, Ts) ->
- [case tdb_find(Reg, Ts) of
- {integer,Range} ->
- simplify_select_val_int(I, Range);
- boolean ->
- simplify_select_val_bool(I);
- _ ->
- I
- end];
-simplify_instr({test,bs_test_unit,_,[Src,Unit]}=I, Ts) ->
- case tdb_find(Src, Ts) of
- {binary,U} when U rem Unit =:= 0 -> [];
- _ -> [I]
- end;
-simplify_instr(I, _) -> [I].
-
-simplify_select_val_int({select,select_val,R,_,L0}=I, {Min,Max}) ->
- Vs = sort([V || {integer,V} <- L0]),
- case eq_ranges(Vs, Min, Max) of
- false -> I;
- true -> simplify_select_val_1(L0, {integer,Max}, R, [])
- end.
-
-simplify_select_val_bool({select,select_val,R,_,L}=I) ->
- Vs = sort([V || {atom,V} <- L]),
- case Vs of
- [false,true] ->
- simplify_select_val_1(L, {atom,false}, R, []);
- _ ->
- I
- end.
-
-simplify_select_val_1([Val,F|T], Val, R, Acc) ->
- L = reverse(Acc, T),
- {select,select_val,R,F,L};
-simplify_select_val_1([V,F|T], Val, R, Acc) ->
- simplify_select_val_1(T, Val, R, [F,V|Acc]).
-
-eq_ranges([H], H, H) -> true;
-eq_ranges([H|T], H, Max) -> eq_ranges(T, H+1, Max);
-eq_ranges(_, _, _) -> false.
-
-%% will_succeed(TestOperation, Type) -> yes|no|maybe.
-%% Test whether TestOperation applied to an argument of type Type
-%% will succeed. Return yes, no, or maybe.
-%%
-%% Type is a type as described in the comment for verified_type/1 at
-%% the very end of this file, but it will *never* be 'any'.
-
-will_succeed(is_atom, Type) ->
- case Type of
- {atom,_} -> yes;
- boolean -> yes;
- _ -> no
- end;
-will_succeed(is_binary, Type) ->
- case Type of
- {binary,U} when U rem 8 =:= 0 -> yes;
- {binary,_} -> maybe;
- _ -> no
- end;
-will_succeed(is_bitstr, Type) ->
- case Type of
- {binary,_} -> yes;
- _ -> no
- end;
-will_succeed(is_integer, Type) ->
- case Type of
- integer -> yes;
- {integer,_} -> yes;
- _ -> no
- end;
-will_succeed(is_map, Type) ->
- case Type of
- map -> yes;
- _ -> no
- end;
-will_succeed(is_nonempty_list, Type) ->
- case Type of
- nonempty_list -> yes;
- _ -> no
- end;
-will_succeed(is_tuple, Type) ->
- case Type of
- {tuple,_,_,_} -> yes;
- _ -> no
- end;
-will_succeed(_, _) -> maybe.
-
-%% simplify_float([Instruction], TypeDatabase) ->
-%% {[Instruction],TypeDatabase'} | not_possible
-%% Simplify floating point operations in blocks.
-%%
-simplify_float(Is0, Ts0) ->
- {Is1,Ts} = simplify_float_1(Is0, Ts0, [], []),
- Is2 = opt_fmoves(Is1, []),
- Is3 = flt_need_heap(Is2),
- try
- {flt_liveness(Is3),Ts}
- catch
- throw:not_possible -> not_possible
- end.
-
-simplify_float_1([{set,[],[],fclearerror}|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, clearerror(Acc));
-simplify_float_1([{set,[],[],fcheckerror}|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, checkerror(Acc));
-simplify_float_1([{set,[{fr,_}],_,_}=I|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, [I|Acc]);
-simplify_float_1([{set,[D0],[A0],{alloc,_,{gc_bif,'-',{f,0}}}}=I|Is]=Is0,
- Ts0, Rs0, Acc0) ->
- case tdb_find(A0, Ts0) of
- float ->
- A = coerce_to_float(A0),
- {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
- {D,Rs} = find_dest(D0, Rs1),
- Areg = fetch_reg(A, Rs),
- Acc = [{set,[D],[Areg],{bif,fnegate,{f,0}}}|clearerror(Acc1)],
- Ts = tdb_store(D0, float, Ts0),
- simplify_float_1(Is, Ts, Rs, Acc);
- _Other ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)])
- end;
-simplify_float_1([{set,[D0],[A0,B0],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0,
- Ts0, Rs0, Acc0) ->
- case float_op(Op0, A0, B0, Ts0) of
- no ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]);
- {yes,Op} ->
- A = coerce_to_float(A0),
- B = coerce_to_float(B0),
- {Rs1,Acc1} = load_reg(A, Ts0, Rs0, Acc0),
- {Rs2,Acc2} = load_reg(B, Ts0, Rs1, Acc1),
- {D,Rs} = find_dest(D0, Rs2),
- Areg = fetch_reg(A, Rs),
- Breg = fetch_reg(B, Rs),
- Acc = [{set,[D],[Areg,Breg],{bif,Op,{f,0}}}|clearerror(Acc2)],
- Ts = tdb_store(D0, float, Ts0),
- simplify_float_1(Is, Ts, Rs, Acc)
- end;
-simplify_float_1([{set,_,_,{try_catch,_,_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
- Acc = flush_all(Rs0, Is0, Acc0),
- simplify_float_1(Is, tdb_new(), Rs0, [I|Acc]);
-simplify_float_1([{set,_,_,{line,_}}=I|Is], Ts, Rs, Acc) ->
- simplify_float_1(Is, Ts, Rs, [I|Acc]);
-simplify_float_1([I|Is], Ts0, [], Acc) ->
- Ts = update(I, Ts0),
- simplify_float_1(Is, Ts, [], [I|Acc]);
-simplify_float_1([I|Is]=Is0, Ts0, Rs0, Acc0) ->
- Ts = update(I, Ts0),
- {Rs,Acc} = flush(Rs0, Is0, Acc0),
- simplify_float_1(Is, Ts, Rs, [I|checkerror(Acc)]);
-simplify_float_1([], Ts, [], Acc) ->
- Is = reverse(Acc),
- {Is,Ts}.
-
-coerce_to_float({integer,I}=Int) ->
- try float(I) of
- F ->
- {float,F}
- catch _:_ ->
- %% Let the overflow happen at run-time.
- Int
- end;
-coerce_to_float(Other) -> Other.
-
-opt_fmoves([{set,[{x,_}=R],[{fr,_}]=Src,fmove}=I1,
- {set,[_]=Dst,[{x,_}=R],move}=I2|Is], Acc) ->
- case beam_utils:is_killed_block(R, Is) of
- false -> opt_fmoves(Is, [I2,I1|Acc]);
- true -> opt_fmoves(Is, [{set,Dst,Src,fmove}|Acc])
- end;
-opt_fmoves([I|Is], Acc) ->
- opt_fmoves(Is, [I|Acc]);
-opt_fmoves([], Acc) -> reverse(Acc).
-
-clearerror(Is) ->
- clearerror(Is, Is).
-
-clearerror([{set,[],[],fclearerror}|_], OrigIs) -> OrigIs;
-clearerror([{set,[],[],fcheckerror}|_], OrigIs) -> [{set,[],[],fclearerror}|OrigIs];
-clearerror([_|Is], OrigIs) -> clearerror(Is, OrigIs);
-clearerror([], OrigIs) -> [{set,[],[],fclearerror}|OrigIs].
-
-%% merge_blocks(Block1, Block2) -> Block.
-%% Combine two blocks and eliminate any move instructions that assign
-%% to registers that are killed later in the block.
-%%
-merge_blocks(B1, [{'%anno',_}|B2]) ->
- merge_blocks_1(B1++[{set,[],[],stop_here}|B2]).
-
-merge_blocks_1([{set,[],_,stop_here}|Is]) -> Is;
-merge_blocks_1([{set,[D],_,move}=I|Is]) ->
- case beam_utils:is_killed_block(D, Is) of
- true -> merge_blocks_1(Is);
- false -> [I|merge_blocks_1(Is)]
- end;
-merge_blocks_1([I|Is]) -> [I|merge_blocks_1(Is)].
-
-%% flt_need_heap([Instruction]) -> [Instruction]
-%% Insert need heap allocation instructions in the instruction stream
-%% to properly account for both inserted floating point operations and
-%% normal term build operations (such as put_list/3).
-%%
-%% Ignore old heap allocation instructions (except if they allocate a stack
-%% frame too), as they may be in the wrong place (because gc_bif instructions
-%% could have been converted to floating point operations).
-
-flt_need_heap(Is) ->
- flt_need_heap_1(reverse(Is), 0, 0, []).
-
-flt_need_heap_1([{set,[],[],{alloc,_,Alloc}}|Is], H, Fl, Acc) ->
- case Alloc of
- {_,nostack,_,_} ->
- %% Remove any existing test_heap/2 instruction.
- flt_need_heap_1(Is, H, Fl, Acc);
- {Z,Stk,_,Inits} when is_integer(Stk) ->
- %% Keep any allocate*/2 instruction and recalculate heap need.
- I = {set,[],[],{alloc,regs,{Z,Stk,build_alloc(H, Fl),Inits}}},
- flt_need_heap_1(Is, 0, 0, [I|Acc])
- end;
-flt_need_heap_1([I|Is], H0, Fl0, Acc) ->
- {Ns,H1,Fl1} = flt_need_heap_2(I, H0, Fl0),
- flt_need_heap_1(Is, H1, Fl1, [I|Ns]++Acc);
-flt_need_heap_1([], H, Fl, Acc) ->
- flt_alloc(H, Fl) ++ Acc.
-
-%% First come all instructions that build. We pass through, while we
-%% add to the need for heap words and floats on the heap.
-flt_need_heap_2({set,[_],[{fr,_}],fmove}, H, Fl) ->
- {[],H,Fl+1};
-flt_need_heap_2({set,_,_,put_list}, H, Fl) ->
- {[],H+2,Fl};
-flt_need_heap_2({set,_,_,{put_tuple,_}}, H, Fl) ->
- {[],H+1,Fl};
-flt_need_heap_2({set,_,_,put}, H, Fl) ->
- {[],H+1,Fl};
-%% The following instructions cause the insertion of an allocation
-%% instruction if needed.
-flt_need_heap_2({set,_,_,{alloc,_,_}}, H, Fl) ->
- {flt_alloc(H, Fl),0,0};
-flt_need_heap_2({set,_,_,{set_tuple_element,_}}, H, Fl) ->
- {flt_alloc(H, Fl),0,0};
-flt_need_heap_2({'%anno',_}, H, Fl) ->
- {flt_alloc(H, Fl),0,0};
-%% All other instructions are "neutral". We just pass them.
-flt_need_heap_2(_, H, Fl) ->
- {[],H,Fl}.
-
-flt_alloc(0, 0) ->
- [];
-flt_alloc(H, 0) ->
- [{set,[],[],{alloc,regs,{nozero,nostack,H,[]}}}];
-flt_alloc(H, F) ->
- [{set,[],[],{alloc,regs,{nozero,nostack,
- build_alloc(H, F),[]}}}].
-
-build_alloc(Words, 0) -> Words;
-build_alloc(Words, Floats) -> {alloc,[{words,Words},{floats,Floats}]}.
-
-
-%% flt_liveness([Instruction]) -> [Instruction]
-%% (Re)calculate the number of live registers for each heap allocation
-%% function. We base liveness of the number of register map at the
-%% beginning of the instruction sequence.
-%%
-%% A 'not_possible' term will be thrown if the set of live registers
-%% is not continous at an allocation function (e.g. if {x,0} and {x,2}
-%% are live, but not {x,1}).
-
-flt_liveness([{'%anno',{used,Regs}}=LiveInstr|Is]) ->
- flt_liveness_1(Is, Regs, [LiveInstr]).
-
-flt_liveness_1([{set,Ds,Ss,{alloc,Live0,Alloc}}|Is], Regs0, Acc) ->
- Live = min(Live0, live_regs(Regs0)),
- I = {set,Ds,Ss,{alloc,Live,Alloc}},
- Regs1 = init_regs(Live),
- Regs = x_live(Ds, Regs1),
- flt_liveness_1(Is, Regs, [I|Acc]);
-flt_liveness_1([{set,Ds,_,_}=I|Is], Regs0, Acc) ->
- Regs = x_live(Ds, Regs0),
- flt_liveness_1(Is, Regs, [I|Acc]);
-flt_liveness_1([{'%anno',_}], _Regs, Acc) ->
- reverse(Acc).
-
-init_regs(Live) ->
- (1 bsl Live) - 1.
-
-live_regs(Regs) ->
- live_regs_1(Regs, 0).
-
-live_regs_1(0, N) -> N;
-live_regs_1(R, N) ->
- case R band 1 of
- 0 -> throw(not_possible);
- 1 -> live_regs_1(R bsr 1, N+1)
- end.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
-
-%% update(Instruction, TypeDb) -> NewTypeDb
-%% Update the type database to account for executing an instruction.
-%%
-%% First the cases for instructions inside basic blocks.
-update({'%anno',_}, Ts) ->
- Ts;
-update({set,[D],[S],move}, Ts) ->
- tdb_copy(S, D, Ts);
-update({set,[D],[Index,Reg],{bif,element,_}}, Ts0) ->
- MinSize = case Index of
- {integer,I} -> I;
- _ -> 0
- end,
- Ts = tdb_meet(Reg, {tuple,min_size,MinSize,[]}, Ts0),
- tdb_store(D, any, Ts);
-update({set,[D],[_Key,Map],{bif,map_get,_}}, Ts0) ->
- Ts = tdb_meet(Map, map, Ts0),
- tdb_store(D, any, Ts);
-update({set,[D],Args,{bif,N,_}}, Ts) ->
- Ar = length(Args),
- BoolOp = erl_internal:new_type_test(N, Ar) orelse
- erl_internal:comp_op(N, Ar) orelse
- erl_internal:bool_op(N, Ar),
- Type = case BoolOp of
- true -> boolean;
- false -> unary_op_type(N)
- end,
- tdb_store(D, Type, Ts);
-update({set,[D],[S],{get_tuple_element,0}}, Ts0) ->
- if
- D =:= S ->
- tdb_store(D, any, Ts0);
- true ->
- Ts = tdb_store(D, {tuple_element,S,0}, Ts0),
- tdb_store(S, {tuple,min_size,1,[]}, Ts)
- end;
-update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) ->
- %% Make sure we reject non-numeric literal argument.
- case possibly_numeric(S) of
- true -> tdb_store(D, float, Ts0);
- false -> Ts0
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,'band',{f,0}}}}, Ts) ->
- Type = band_type(S1, S2, Ts),
- tdb_store(D, Type, Ts);
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,'/',{f,0}}}}, Ts) ->
- %% Make sure we reject non-numeric literals.
- case possibly_numeric(S1) andalso possibly_numeric(S2) of
- true -> tdb_store(D, float, Ts);
- false -> Ts
- end;
-update({set,[D],[S1,S2],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts0) ->
- case op_type(Op) of
- integer ->
- tdb_store(D, integer, Ts0);
- {float,_} ->
- case {tdb_find(S1, Ts0),tdb_find(S2, Ts0)} of
- {float,_} -> tdb_store(D, float, Ts0);
- {_,float} -> tdb_store(D, float, Ts0);
- {_,_} -> tdb_store(D, any, Ts0)
- end;
- Type ->
- tdb_store(D, Type, Ts0)
- end;
-update({set,[D],[_],{alloc,_,{gc_bif,Op,{f,0}}}}, Ts) ->
- tdb_store(D, unary_op_type(Op), Ts);
-update({set,[],_Src,_Op}, Ts) ->
- Ts;
-update({set,[D],_Src,_Op}, Ts) ->
- tdb_store(D, any, Ts);
-update({kill,D}, Ts) ->
- tdb_store(D, any, Ts);
-
-%% Instructions outside of blocks.
-update({test,test_arity,_Fail,[Src,Arity]}, Ts) ->
- tdb_meet(Src, {tuple,exact_size,Arity,[]}, Ts);
-update({get_map_elements,_,Src,{list,Elems0}}, Ts0) ->
- Ts1 = tdb_meet(Src, map, Ts0),
- {_Ss,Ds} = beam_utils:split_even(Elems0),
- foldl(fun(Dst, A) -> tdb_store(Dst, any, A) end, Ts1, Ds);
-update({test,is_eq_exact,_,[Reg,{atom,_}=Atom]}, Ts0) ->
- Ts = case tdb_find_source_tuple(Reg, Ts0) of
- {source_tuple,TupleReg} ->
- tdb_meet(TupleReg, {tuple,min_size,1,[Atom]}, Ts0);
- none ->
- Ts0
- end,
- tdb_meet(Reg, Atom, Ts);
-update({test,is_record,_Fail,[Src,Tag,{integer,Arity}]}, Ts) ->
- tdb_meet(Src, {tuple,exact_size,Arity,[Tag]}, Ts);
-
-%% Binaries and binary matching.
-
-update({test,bs_get_integer2,_,_,Args,Dst}, Ts) ->
- tdb_store(Dst, get_bs_integer_type(Args), Ts);
-update({test,bs_get_utf8,_,_,_,Dst}, Ts) ->
- tdb_store(Dst, ?UNICODE_INT, Ts);
-update({test,bs_get_utf16,_,_,_,Dst}, Ts) ->
- tdb_store(Dst, ?UNICODE_INT, Ts);
-update({test,bs_get_utf32,_,_,_,Dst}, Ts) ->
- tdb_store(Dst, ?UNICODE_INT, Ts);
-update({bs_init,_,{bs_init2,_,_},_,_,Dst}, Ts) ->
- tdb_store(Dst, {binary,8}, Ts);
-update({bs_init,_,_,_,_,Dst}, Ts) ->
- tdb_store(Dst, {binary,1}, Ts);
-update({bs_put,_,_,_}, Ts) ->
- Ts;
-update({bs_save2,_,_}, Ts) ->
- Ts;
-update({bs_restore2,_,_}, Ts) ->
- Ts;
-update({bs_context_to_binary,Dst}, Ts) ->
- tdb_store(Dst, any, Ts);
-update({test,bs_start_match2,_,_,[Src,_],Dst}, Ts0) ->
- Ts = tdb_meet(Src, {binary,1}, Ts0),
- tdb_copy(Src, Dst, Ts);
-update({test,bs_get_binary2,_,_,[_,_,Unit,_],Dst}, Ts) ->
- true = is_integer(Unit), %Assertion.
- tdb_store(Dst, {binary,Unit}, Ts);
-update({test,bs_get_float2,_,_,_,Dst}, Ts) ->
- tdb_store(Dst, float, Ts);
-update({test,bs_test_unit,_,[Src,Unit]}, Ts) ->
- tdb_meet(Src, {binary,Unit}, Ts);
-
-%% Other test instructions
-update({test,Test,_Fail,[Src]}, Ts) ->
- Type = case Test of
- is_binary -> {binary,8};
- is_bitstr -> {binary,1};
- is_boolean -> boolean;
- is_float -> float;
- is_integer -> integer;
- is_map -> map;
- is_nonempty_list -> nonempty_list;
- _ -> any
- end,
- tdb_meet(Src, Type, Ts);
-update({test,_Test,_Fail,_Other}, Ts) ->
- Ts;
-
-%% Calls
-
-update({call_ext,Ar,{extfunc,math,Math,Ar}}, Ts) ->
- case is_math_bif(Math, Ar) of
- true -> tdb_store({x,0}, float, Ts);
- false -> tdb_kill_xregs(Ts)
- end;
-update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
- Ts = tdb_kill_xregs(Ts0),
- case tdb_find({x,1}, Ts0) of
- {tuple,SzKind,Sz,_}=T0 ->
- T = case tdb_find({x,0}, Ts0) of
- {integer,{I,I}} when I > 1 ->
- %% First element is not changed. The result
- %% will have the same type.
- T0;
- _ ->
- %% Position is 1 or unknown. May change the
- %% first element of the tuple.
- {tuple,SzKind,Sz,[]}
- end,
- tdb_store({x,0}, T, Ts);
- _ ->
- Ts
- end;
-update({call,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
-update({call_ext,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
-update({make_fun2,_,_,_,_}, Ts) -> tdb_kill_xregs(Ts);
-update({call_fun, _}, Ts) -> tdb_kill_xregs(Ts);
-update({apply, _}, Ts) -> tdb_kill_xregs(Ts);
-
-update({line,_}, Ts) -> Ts;
-update({'%',_}, Ts) -> Ts;
-
-%% The instruction is unknown. Kill all information.
-update(_I, _Ts) -> tdb_new().
-
-band_type({integer,Int}, Other, Ts) ->
- band_type_1(Int, Other, Ts);
-band_type(Other, {integer,Int}, Ts) ->
- band_type_1(Int, Other, Ts);
-band_type(_, _, _) -> integer.
-
-band_type_1(Int, OtherSrc, Ts) ->
- Type = band_type_2(Int, 0),
- OtherType = tdb_find(OtherSrc, Ts),
- meet(Type, OtherType).
-
-band_type_2(N, Bits) when Bits < 64 ->
- case 1 bsl Bits of
- P when P =:= N + 1 ->
- {integer,{0,N}};
- P when P > N + 1 ->
- integer;
- _ ->
- band_type_2(N, Bits+1)
- end;
-band_type_2(_, _) ->
- %% Negative or large positive number. Give up.
- integer.
-
-get_bs_integer_type([_,{integer,N},U,{field_flags,Fl}])
- when N*U < 64 ->
- NumBits = N*U,
- case member(unsigned, Fl) of
- true ->
- {integer,{0,(1 bsl NumBits)-1}};
- false ->
- %% Signed integer. Don't bother.
- integer
- end;
-get_bs_integer_type(_) ->
- %% Avoid creating ranges with a huge upper limit.
- integer.
-
-is_math_bif(cos, 1) -> true;
-is_math_bif(cosh, 1) -> true;
-is_math_bif(sin, 1) -> true;
-is_math_bif(sinh, 1) -> true;
-is_math_bif(tan, 1) -> true;
-is_math_bif(tanh, 1) -> true;
-is_math_bif(acos, 1) -> true;
-is_math_bif(acosh, 1) -> true;
-is_math_bif(asin, 1) -> true;
-is_math_bif(asinh, 1) -> true;
-is_math_bif(atan, 1) -> true;
-is_math_bif(atanh, 1) -> true;
-is_math_bif(erf, 1) -> true;
-is_math_bif(erfc, 1) -> true;
-is_math_bif(exp, 1) -> true;
-is_math_bif(log, 1) -> true;
-is_math_bif(log2, 1) -> true;
-is_math_bif(log10, 1) -> true;
-is_math_bif(sqrt, 1) -> true;
-is_math_bif(atan2, 2) -> true;
-is_math_bif(pow, 2) -> true;
-is_math_bif(ceil, 1) -> true;
-is_math_bif(floor, 1) -> true;
-is_math_bif(fmod, 2) -> true;
-is_math_bif(pi, 0) -> true;
-is_math_bif(_, _) -> false.
-
-%% Reject non-numeric literals.
-possibly_numeric({x,_}) -> true;
-possibly_numeric({y,_}) -> true;
-possibly_numeric({integer,_}) -> true;
-possibly_numeric({float,_}) -> true;
-possibly_numeric(_) -> false.
-
-max_tuple_size(Reg, Ts) ->
- case tdb_find(Reg, Ts) of
- {tuple,_,Sz,_} -> Sz;
- _Other -> 0
- end.
-
-float_op('/', A, B, _) ->
- case possibly_numeric(A) andalso possibly_numeric(B) of
- true -> {yes,fdiv};
- false -> no
- end;
-float_op(Op, {float,_}, B, _) ->
- case possibly_numeric(B) of
- true -> arith_op(Op);
- false -> no
- end;
-float_op(Op, A, {float,_}, _) ->
- case possibly_numeric(A) of
- true -> arith_op(Op);
- false -> no
- end;
-float_op(Op, A, B, Ts) ->
- case {tdb_find(A, Ts),tdb_find(B, Ts)} of
- {float,_} -> arith_op(Op);
- {_,float} -> arith_op(Op);
- {_,_} -> no
- end.
-
-find_dest(V, Rs0) ->
- case find_reg(V, Rs0) of
- {ok,FR} ->
- {FR,mark(V, Rs0, dirty)};
- error ->
- Rs = put_reg(V, Rs0, dirty),
- {ok,FR} = find_reg(V, Rs),
- {FR,Rs}
- end.
-
-load_reg({float,_}=F, _, Rs0, Is0) ->
- Rs = put_reg(F, Rs0, clean),
- {ok,FR} = find_reg(F, Rs),
- Is = [{set,[FR],[F],fmove}|Is0],
- {Rs,Is};
-load_reg(V, Ts, Rs0, Is0) ->
- case find_reg(V, Rs0) of
- {ok,_FR} -> {Rs0,Is0};
- error ->
- Rs = put_reg(V, Rs0, clean),
- {ok,FR} = find_reg(V, Rs),
- Op = case tdb_find(V, Ts) of
- float -> fmove;
- _ -> fconv
- end,
- Is = [{set,[FR],[V],Op}|Is0],
- {Rs,Is}
- end.
-
-arith_op(Op) ->
- case op_type(Op) of
- {float,Instr} -> {yes,Instr};
- _ -> no
- end.
-
-op_type('+') -> {float,fadd};
-op_type('-') -> {float,fsub};
-op_type('*') -> {float,fmul};
-%% '/' and 'band' are specially handled.
-op_type('bor') -> integer;
-op_type('bxor') -> integer;
-op_type('bsl') -> integer;
-op_type('bsr') -> integer;
-op_type('div') -> integer;
-op_type(_) -> any.
-
-unary_op_type(bit_size) -> integer;
-unary_op_type(byte_size) -> integer;
-unary_op_type(length) -> integer;
-unary_op_type(map_size) -> integer;
-unary_op_type(size) -> integer;
-unary_op_type(tuple_size) -> integer;
-unary_op_type(_) -> any.
-
-flush(Rs, [{set,[_],[_,_,_],{bif,is_record,_}}|_]=Is0, Acc0) ->
- Acc = flush_all(Rs, Is0, Acc0),
- {[],Acc};
-flush(Rs, [{set,[_],[],{put_tuple,_}}|_]=Is0, Acc0) ->
- Acc = flush_all(Rs, Is0, Acc0),
- {[],Acc};
-flush(Rs0, [{set,Ds,Ss,_Op}|_], Acc0) ->
- Save = cerl_sets:from_list(Ss),
- Acc = save_regs(Rs0, Save, Acc0),
- Rs1 = foldl(fun(S, A) -> mark(S, A, clean) end, Rs0, Ss),
- Kill = cerl_sets:from_list(Ds),
- Rs = kill_regs(Rs1, Kill),
- {Rs,Acc};
-flush(Rs0, Is, Acc0) ->
- Acc = flush_all(Rs0, Is, Acc0),
- {[],Acc}.
-
-flush_all([{_,{float,_},_}|Rs], Is, Acc) ->
- flush_all(Rs, Is, Acc);
-flush_all([{I,V,dirty}|Rs], Is, Acc0) ->
- Acc = checkerror(Acc0),
- case beam_utils:is_killed_block(V, Is) of
- true -> flush_all(Rs, Is, Acc);
- false -> flush_all(Rs, Is, [{set,[V],[{fr,I}],fmove}|Acc])
- end;
-flush_all([{_,_,clean}|Rs], Is, Acc) -> flush_all(Rs, Is, Acc);
-flush_all([free|Rs], Is, Acc) -> flush_all(Rs, Is, Acc);
-flush_all([], _, Acc) -> Acc.
-
-save_regs(Rs, Save, Acc) ->
- foldl(fun(R, A) -> save_reg(R, Save, A) end, Acc, Rs).
-
-save_reg({I,V,dirty}, Save, Acc) ->
- case cerl_sets:is_element(V, Save) of
- true -> [{set,[V],[{fr,I}],fmove}|checkerror(Acc)];
- false -> Acc
- end;
-save_reg(_, _, Acc) -> Acc.
-
-kill_regs(Rs, Kill) ->
- [kill_reg(R, Kill) || R <- Rs].
-
-kill_reg({_,V,_}=R, Kill) ->
- case cerl_sets:is_element(V, Kill) of
- true -> free;
- false -> R
- end;
-kill_reg(R, _) -> R.
-
-mark(V, [{I,V,_}|Rs], Mark) -> [{I,V,Mark}|Rs];
-mark(V, [R|Rs], Mark) -> [R|mark(V, Rs, Mark)];
-mark(_, [], _) -> [].
-
-fetch_reg(V, [{I,V,_}|_]) -> {fr,I};
-fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
-
-find_reg(V, [{I,V,_}|_]) -> {ok,{fr,I}};
-find_reg(V, [_|SRs]) -> find_reg(V, SRs);
-find_reg(_, []) -> error.
-
-put_reg(V, Rs, Dirty) -> put_reg_1(V, Rs, Dirty, 0).
-
-put_reg_1(V, [free|Rs], Dirty, I) -> [{I,V,Dirty}|Rs];
-put_reg_1(V, [R|Rs], Dirty, I) -> [R|put_reg_1(V, Rs, Dirty, I+1)];
-put_reg_1(V, [], Dirty, I) -> [{I,V,Dirty}].
-
-checkerror(Is) ->
- checkerror_1(Is, Is).
-
-checkerror_1([{set,[],[],fcheckerror}|_], OrigIs) -> OrigIs;
-checkerror_1([{set,_,_,{bif,fadd,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fsub,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fmul,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fdiv,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([{set,_,_,{bif,fnegate,_}}|_], OrigIs) -> checkerror_2(OrigIs);
-checkerror_1([_|Is], OrigIs) -> checkerror_1(Is, OrigIs);
-checkerror_1([], OrigIs) -> OrigIs.
-
-checkerror_2(OrigIs) -> [{set,[],[],fcheckerror}|OrigIs].
-
-
-%%% Routines for maintaining a type database. The type database
-%%% associates type information with registers.
-%%%
-%%% See the comment for verified_type/1 at the end of module for
-%%% a description of the possible types.
-
-%% tdb_new() -> EmptyDataBase
-%% Creates a new, empty type database.
-
-tdb_new() -> [].
-
-%% tdb_find(Register, Db) -> Type
-%% Returns type information or the atom error if there is no type
-%% information available for Register.
-%%
-%% See the comment for verified_type/1 at the end of module for
-%% a description of the possible types.
-
-tdb_find(Reg, Ts) ->
- case tdb_find_raw(Reg, Ts) of
- {tuple_element,_,_} -> any;
- Type -> Type
- end.
-
-%% tdb_find_source_tuple(Register, Ts) -> {source_tuple,Register} | 'none'.
-%% Find the tuple whose first element was fetched to the register Register.
-
-tdb_find_source_tuple(Reg, Ts) ->
- case tdb_find_raw(Reg, Ts) of
- {tuple_element,Src,0} ->
- {source_tuple,Src};
- _ ->
- none
- end.
-
-%% tdb_copy(Source, Dest, Db) -> Db'
-%% Update the type information for Dest to have the same type
-%% as the Source.
-
-tdb_copy({Tag,_}=S, D, Ts) when Tag =:= x; Tag =:= y ->
- case tdb_find_raw(S, Ts) of
- any -> orddict:erase(D, Ts);
- Type -> orddict:store(D, Type, Ts)
- end;
-tdb_copy(Literal, D, Ts) ->
- Type = case Literal of
- {atom,_} -> Literal;
- {float,_} -> float;
- {integer,Int} -> {integer,{Int,Int}};
- {literal,[_|_]} -> nonempty_list;
- {literal,#{}} -> map;
- {literal,Tuple} when tuple_size(Tuple) >= 1 ->
- Lit = tag_literal(element(1, Tuple)),
- {tuple,exact_size,tuple_size(Tuple),[Lit]};
- _ -> any
- end,
- tdb_store(D, verified_type(Type), Ts).
-
-%% tdb_store(Register, Type, Ts0) -> Ts.
-%% Store a new type for register Register. Return the update type
-%% database. Use this function when a new value is assigned to
-%% a register.
-%%
-%% See the comment for verified_type/1 at the end of module for
-%% a description of the possible types.
-
-tdb_store(Reg, any, Ts) ->
- erase(Reg, Ts);
-tdb_store(Reg, Type, Ts) ->
- store(Reg, verified_type(Type), Ts).
-
-store(Key, New, [{K,_}|_]=Dict) when Key < K ->
- [{Key,New}|Dict];
-store(Key, New, [{K,Val}=E|Dict]) when Key > K ->
- case Val of
- {tuple_element,Key,_} -> store(Key, New, Dict);
- _ -> [E|store(Key, New, Dict)]
- end;
-store(Key, New, [{_K,Old}|Dict]) -> %Key == K
- case Old of
- {tuple,_,_,_} ->
- [{Key,New}|erase_tuple_element(Key, Dict)];
- _ ->
- [{Key,New}|Dict]
- end;
-store(Key, New, []) -> [{Key,New}].
-
-erase(Key, [{K,_}=E|Dict]) when Key < K ->
- [E|Dict];
-erase(Key, [{K,Val}=E|Dict]) when Key > K ->
- case Val of
- {tuple_element,Key,_} -> erase(Key, Dict);
- _ -> [E|erase(Key, Dict)]
- end;
-erase(Key, [{_K,Val}|Dict]) -> %Key == K
- case Val of
- {tuple,_,_,_} -> erase_tuple_element(Key, Dict);
- _ -> Dict
- end;
-erase(_, []) -> [].
-
-erase_tuple_element(Key, [{_,{tuple_element,Key,_}}|Dict]) ->
- erase_tuple_element(Key, Dict);
-erase_tuple_element(Key, [E|Dict]) ->
- [E|erase_tuple_element(Key, Dict)];
-erase_tuple_element(_Key, []) -> [].
-
-%% tdb_meet(Register, Type, Ts0) -> Ts.
-%% Update information of a register that is used as the source for an
-%% instruction. The type Type will be combined using the meet operation
-%% with the previous type information for the register, resulting in
-%% narrower (more specific) type.
-%%
-%% For example, if the previous type is {tuple,min_size,2,[]} and the
-%% the new type is {tuple,exact_size,5,[]}, the meet of the types will
-%% be {tuple,exact_size,5,[]}.
-%%
-%% See the comment for verified_type/1 at the end of module for
-%% a description of the possible types.
-
-tdb_meet(Reg, NewType, Ts) ->
- Update = fun(Type0) -> meet(Type0, NewType) end,
- orddict:update(Reg, Update, NewType, Ts).
-
-%%%
-%%% Here follows internal helper functions for accessing and
-%%% updating the type database.
-%%%
-
-tdb_find_raw({x,_}=K, Ts) -> tdb_find_raw_1(K, Ts);
-tdb_find_raw({y,_}=K, Ts) -> tdb_find_raw_1(K, Ts);
-tdb_find_raw(_, _) -> any.
-
-tdb_find_raw_1(K, Ts) ->
- case orddict:find(K, Ts) of
- {ok,Val} -> Val;
- error -> any
- end.
-
-tag_literal(A) when is_atom(A) -> {atom,A};
-tag_literal(F) when is_float(F) -> {float,F};
-tag_literal(I) when is_integer(I) -> {integer,I};
-tag_literal([]) -> nil;
-tag_literal(Lit) -> {literal,Lit}.
-
-%% tdb_kill_xregs(Db) -> NewDb
-%% Kill all information about x registers. Also kill all tuple_element
-%% dependencies from y registers to x registers.
-
-tdb_kill_xregs([{{x,_},_Type}|Db]) -> tdb_kill_xregs(Db);
-tdb_kill_xregs([{{y,_},{tuple_element,{x,_},_}}|Db]) -> tdb_kill_xregs(Db);
-tdb_kill_xregs([Any|Db]) -> [Any|tdb_kill_xregs(Db)];
-tdb_kill_xregs([]) -> [].
-
-%% meet(Type1, Type2) -> Type
-%% Returns the "meet" of Type1 and Type2. The meet is a narrower
-%% type than Type1 and Type2. For example:
-%%
-%% meet(integer, {integer,{0,3}}) -> {integer,{0,3}}
-%%
-%% The meet for two different types result in 'none', which is
-%% the bottom element for our type lattice:
-%%
-%% meet(integer, map) -> none
-
-meet(T, T) ->
- T;
-meet({integer,_}=T, integer) ->
- T;
-meet(integer, {integer,_}=T) ->
- T;
-meet({integer,{Min1,Max1}}, {integer,{Min2,Max2}}) ->
- {integer,{max(Min1, Min2),min(Max1, Max2)}};
-meet({tuple,min_size,Sz1,Same}, {tuple,min_size,Sz2,Same}=Max) when Sz1 < Sz2 ->
- Max;
-meet({tuple,min_size,Sz1,Same}=Max, {tuple,min_size,Sz2,Same}) when Sz1 > Sz2 ->
- Max;
-meet({tuple,exact_size,_,Same}=Exact, {tuple,_,_,Same}) ->
- Exact;
-meet({tuple,_,_,Same},{tuple,exact_size,_,Same}=Exact) ->
- Exact;
-meet({tuple,SzKind1,Sz1,[]}, {tuple,_SzKind2,_Sz2,First}=Tuple2) ->
- meet({tuple,SzKind1,Sz1,First}, Tuple2);
-meet({tuple,_SzKind1,_Sz1,First}=Tuple1, {tuple,SzKind2,Sz2,_}) ->
- meet(Tuple1, {tuple,SzKind2,Sz2,First});
-meet({binary,U1}, {binary,U2}) ->
- {binary,max(U1, U2)};
-meet(T1, T2) ->
- case is_any(T1) of
- true ->
- verified_type(T2);
- false ->
- case is_any(T2) of
- true ->
- verified_type(T1);
- false ->
- none %The bottom element.
- end
- end.
-
-is_any(any) -> true;
-is_any({tuple_element,_,_}) -> true;
-is_any(_) -> false.
-
-%% verified_type(Type) -> Type
-%% Returns the passed in type if it is one of the defined types.
-%% Crashes if there is anything wrong with the type.
-%%
-%% Here are all possible types:
-%%
-%% any Any Erlang term (top element for the type lattice).
-%%
-%% {atom,Atom} The specific atom Atom.
-%% {binary,Unit} Binary/bitstring aligned to unit Unit.
-%% boolean 'true' | 'false'
-%% float Floating point number.
-%% integer Integer.
-%% {integer,{Min,Max}} Integer in the inclusive range Min through Max.
-%% map Map.
-%% nonempty_list Nonempty list.
-%% {tuple,_,_,_} Tuple (see below).
-%%
-%% none No type (bottom element for the type lattice).
-%%
-%% {tuple,min_size,Size,First} means that the corresponding register
-%% contains a tuple with *at least* Size elements (conversely,
-%% {tuple,exact_size,Size,First} means that it contains a tuple with
-%% *exactly* Size elements). An tuple with unknown size is
-%% represented as {tuple,min_size,0,[]}. First is either [] (meaning
-%% that the tuple's first element is unknown) or [FirstElement] (the
-%% contents of the first element).
-%%
-%% There is also a pseudo-type called {tuple_element,_,_}:
-%%
-%% {tuple_element,SrcTuple,ElementNumber}
-%%
-%% that does not provide any information about the type of the
-%% register itself, but provides a link back to the source tuple that
-%% the register got its value from.
-%%
-%% Note that {tuple_element,_,_} will *never* be returned by tdb_find/2.
-%% Use tdb_find_source_tuple/2 to locate the source tuple for a register.
-
-verified_type(any=T) -> T;
-verified_type({atom,_}=T) -> T;
-verified_type({binary,U}=T) when is_integer(U) -> T;
-verified_type(boolean=T) -> T;
-verified_type(integer=T) -> T;
-verified_type({integer,{Min,Max}}=T)
- when is_integer(Min), is_integer(Max) -> T;
-verified_type(map=T) -> T;
-verified_type(nonempty_list=T) -> T;
-verified_type({tuple,_,Sz,[]}=T) when is_integer(Sz) -> T;
-verified_type({tuple,_,Sz,[_]}=T) when is_integer(Sz) -> T;
-verified_type({tuple_element,_,_}=T) -> T;
-verified_type(float=T) -> T.
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 3bb671f034..5156a04f6b 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -21,18 +21,14 @@
%%
-module(beam_utils).
--export([is_killed_block/2,is_killed/3,is_killed_at/3,
- is_not_used/3,usage/3,
+-export([is_killed/3,is_killed_at/3,is_not_used/3,
empty_label_index/0,index_label/3,index_labels/1,replace_labels/4,
- code_at/2,bif_to_test/3,is_pure_test/1,
- live_opt/1,delete_annos/1,combine_heap_needs/2,
- anno_defs/1,
- split_even/1
- ]).
+ code_at/2,is_pure_test/1,
+ split_even/1]).
-export_type([code_index/0,module_code/0,instruction/0]).
--import(lists, [flatmap/2,map/2,member/2,sort/1,reverse/1,splitwith/2]).
+-import(lists, [map/2,member/2,sort/1,reverse/1]).
-define(is_const(Val), (Val =:= nil orelse
element(1, Val) =:= integer orelse
@@ -40,7 +36,7 @@
element(1, Val) =:= atom orelse
element(1, Val) =:= literal)).
-%% instruction() describes all instructions that are used during optimzation
+%% instruction() describes all instructions that are used during optimization
%% (from beam_a to beam_z).
-type instruction() :: atom() | tuple().
@@ -62,46 +58,6 @@
{lbl :: code_index(), %Label to code index.
res :: result_cache()}). %Result cache for each label.
-%% usage(Register, [Instruction], State) -> killed|not_used|used.
-%% Determine the usage of Register in the instruction sequence.
-%% The return value is one of:
-%%
-%% killed - The register is not used in any way.
-%% not_used - The register is referenced only by an allocating instruction
-%% (the actual value does not matter).
-%% used - The register is used (its value do matter).
-
--spec usage(beam_asm:reg(), [instruction()], code_index()) ->
- 'killed' | 'not_used' | 'used'.
-
-usage(R, Is, D) ->
- St = #live{lbl=D,res=gb_trees:empty()},
- {Usage,_} = check_liveness(R, Is, St),
- Usage.
-
-
-%% is_killed_block(Register, [Instruction]) -> true|false
-%% Determine whether a register is killed by the instruction sequence inside
-%% a block.
-%%
-%% If true is returned, it means that the register will not be
-%% referenced in ANY way (not even indirectly by an allocate instruction);
-%% i.e. it is OK to enter the instruction sequence with Register
-%% containing garbage.
-
--spec is_killed_block(beam_asm:reg(), [instruction()]) -> boolean().
-
-is_killed_block({x,X}, [{set,_,_,{alloc,Live,_}}|_]) ->
- X >= Live;
-is_killed_block(R, [{set,Ds,Ss,_Op}|Is]) ->
- not member(R, Ss) andalso (member(R, Ds) orelse is_killed_block(R, Is));
-is_killed_block(R, [{'%anno',{used,Regs}}|Is]) ->
- case R of
- {x,X} when (Regs bsr X) band 1 =:= 0 -> true;
- _ -> is_killed_block(R, Is)
- end;
-is_killed_block(_, []) -> false.
-
%% is_killed(Register, [Instruction], State) -> true|false
%% Determine whether a register is killed by the instruction sequence.
%% If true is returned, it means that the register will not be
@@ -200,49 +156,6 @@ code_at(L, Ll) ->
replace_labels(Is, Acc, D, Fb) ->
replace_labels_1(Is, Acc, D, Fb).
-%% bif_to_test(Bif, [Op], Fail) -> {test,Test,Fail,[Op]}
-%% Convert a BIF to a test. Fail if not possible.
-
--spec bif_to_test(atom(), list(), fail()) -> test().
-
-bif_to_test(is_atom, [_]=Ops, Fail) -> {test,is_atom,Fail,Ops};
-bif_to_test(is_boolean, [_]=Ops, Fail) -> {test,is_boolean,Fail,Ops};
-bif_to_test(is_binary, [_]=Ops, Fail) -> {test,is_binary,Fail,Ops};
-bif_to_test(is_bitstring,[_]=Ops, Fail) -> {test,is_bitstr,Fail,Ops};
-bif_to_test(is_float, [_]=Ops, Fail) -> {test,is_float,Fail,Ops};
-bif_to_test(is_function, [_]=Ops, Fail) -> {test,is_function,Fail,Ops};
-bif_to_test(is_function, [_,_]=Ops, Fail) -> {test,is_function2,Fail,Ops};
-bif_to_test(is_integer, [_]=Ops, Fail) -> {test,is_integer,Fail,Ops};
-bif_to_test(is_list, [_]=Ops, Fail) -> {test,is_list,Fail,Ops};
-bif_to_test(is_map, [_]=Ops, Fail) -> {test,is_map,Fail,Ops};
-bif_to_test(is_number, [_]=Ops, Fail) -> {test,is_number,Fail,Ops};
-bif_to_test(is_pid, [_]=Ops, Fail) -> {test,is_pid,Fail,Ops};
-bif_to_test(is_port, [_]=Ops, Fail) -> {test,is_port,Fail,Ops};
-bif_to_test(is_reference, [_]=Ops, Fail) -> {test,is_reference,Fail,Ops};
-bif_to_test(is_tuple, [_]=Ops, Fail) -> {test,is_tuple,Fail,Ops};
-bif_to_test('=<', [A,B], Fail) -> {test,is_ge,Fail,[B,A]};
-bif_to_test('>', [A,B], Fail) -> {test,is_lt,Fail,[B,A]};
-bif_to_test('<', [_,_]=Ops, Fail) -> {test,is_lt,Fail,Ops};
-bif_to_test('>=', [_,_]=Ops, Fail) -> {test,is_ge,Fail,Ops};
-bif_to_test('==', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('==', [nil,A], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('==', [C,A], Fail) when ?is_const(C) ->
- {test,is_eq,Fail,[A,C]};
-bif_to_test('==', [_,_]=Ops, Fail) -> {test,is_eq,Fail,Ops};
-bif_to_test('/=', [C,A], Fail) when ?is_const(C) ->
- {test,is_ne,Fail,[A,C]};
-bif_to_test('/=', [_,_]=Ops, Fail) -> {test,is_ne,Fail,Ops};
-bif_to_test('=:=', [A,nil], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('=:=', [nil,A], Fail) -> {test,is_nil,Fail,[A]};
-bif_to_test('=:=', [C,A], Fail) when ?is_const(C) ->
- {test,is_eq_exact,Fail,[A,C]};
-bif_to_test('=:=', [_,_]=Ops, Fail) -> {test,is_eq_exact,Fail,Ops};
-bif_to_test('=/=', [C,A], Fail) when ?is_const(C) ->
- {test,is_ne_exact,Fail,[A,C]};
-bif_to_test('=/=', [_,_]=Ops, Fail) -> {test,is_ne_exact,Fail,Ops};
-bif_to_test(is_record, [_,_,_]=Ops, Fail) -> {test,is_record,Fail,Ops}.
-
-
%% is_pure_test({test,Op,Fail,Ops}) -> true|false.
%% Return 'true' if the test instruction does not modify any
%% registers and/or bit syntax matching state.
@@ -256,8 +169,8 @@ is_pure_test({test,is_eq_exact,_,[_,_]}) -> true;
is_pure_test({test,is_ne_exact,_,[_,_]}) -> true;
is_pure_test({test,is_ge,_,[_,_]}) -> true;
is_pure_test({test,is_lt,_,[_,_]}) -> true;
-is_pure_test({test,is_nil,_,[_]}) -> true;
is_pure_test({test,is_nonempty_list,_,[_]}) -> true;
+is_pure_test({test,is_tagged_tuple,_,[_,_,_]}) -> true;
is_pure_test({test,test_arity,_,[_,_]}) -> true;
is_pure_test({test,has_map_fields,_,[_|_]}) -> true;
is_pure_test({test,is_bitstr,_,[_]}) -> true;
@@ -265,73 +178,6 @@ is_pure_test({test,is_function2,_,[_,_]}) -> true;
is_pure_test({test,Op,_,Ops}) ->
erl_internal:new_type_test(Op, length(Ops)).
-
-%% live_opt([Instruction]) -> [Instruction].
-%% Go through the instruction sequence in reverse execution
-%% order, keep track of liveness and remove 'move' instructions
-%% whose destination is a register that will not be used.
-%% Also insert {used,Regs} annotations at the beginning
-%% and end of each block.
-
--spec live_opt([instruction()]) -> [instruction()].
-
-live_opt(Is0) ->
- {[{label,Fail}|_]=Bef,[Fi|Is]} =
- splitwith(fun({func_info,_,_,_}) -> false;
- (_) -> true
- end, Is0),
- {func_info,_,_,Live} = Fi,
- D = gb_trees:insert(Fail, live_call(Live), gb_trees:empty()),
- Bef ++ [Fi|live_opt(reverse(Is), 0, D, [])].
-
-
-%% delete_annos([Instruction]) -> [Instruction].
-%% Delete all annotations.
-
--spec delete_annos([instruction()]) -> [instruction()].
-
-delete_annos([{block,Bl0}|Is]) ->
- case delete_annos(Bl0) of
- [] -> delete_annos(Is);
- [_|_]=Bl -> [{block,Bl}|delete_annos(Is)]
- end;
-delete_annos([{'%anno',_}|Is]) ->
- delete_annos(Is);
-delete_annos([I|Is]) ->
- [I|delete_annos(Is)];
-delete_annos([]) -> [].
-
-%% combine_heap_needs(HeapNeed1, HeapNeed2) -> HeapNeed
-%% Combine the heap need for two allocation instructions.
-
--type heap_need_tag() :: 'floats' | 'words'.
--type heap_need() :: non_neg_integer() |
- {'alloc',[{heap_need_tag(),non_neg_integer()}]}.
--spec combine_heap_needs(heap_need(), heap_need()) -> heap_need().
-
-combine_heap_needs(H1, H2) when is_integer(H1), is_integer(H2) ->
- H1 + H2;
-combine_heap_needs(H1, H2) ->
- {alloc,combine_alloc_lists([H1,H2])}.
-
-
-%% anno_defs(Instructions) -> Instructions'
-%% Add {def,RegisterBitmap} annotations to the beginning of
-%% each block. Iff bit X is set in the the bitmap, it means
-%% that {x,X} is defined when the block is entered.
-
--spec anno_defs([instruction()]) -> [instruction()].
-
-anno_defs(Is0) ->
- {Bef,[Fi|Is1]} =
- splitwith(fun({func_info,_,_,_}) -> false;
- (_) -> true
- end, Is0),
- {func_info,_,_,Arity} = Fi,
- Regs = init_def_regs(Arity),
- Is = defs(Is1, Regs, #{}),
- Bef ++ [Fi|Is].
-
%% split_even/1
%% [1,2,3,4,5,6] -> {[1,3,5],[2,4,6]}
@@ -559,11 +405,6 @@ check_liveness(R, [{get_tuple_element,S,_,D}|Is], St) ->
D -> {killed,St};
_ -> check_liveness(R, Is, St)
end;
-check_liveness(R, [{bs_context_to_binary,S}|Is], St) ->
- case R of
- S -> {used,St};
- _ -> check_liveness(R, Is, St)
- end;
check_liveness(R, [{loop_rec,{f,_},{x,0}}|_], St) ->
case R of
{x,_} ->
@@ -835,481 +676,9 @@ label(Old, D, Fb) ->
_ -> Fb(Old)
end.
-%% Help function for combine_heap_needs.
-
-combine_alloc_lists(Al0) ->
- Al1 = flatmap(fun(Words) when is_integer(Words) ->
- [{words,Words}];
- ({alloc,List}) ->
- List
- end, Al0),
- Al2 = sofs:relation(Al1),
- Al3 = sofs:relation_to_family(Al2),
- Al4 = sofs:to_external(Al3),
- [{Tag,lists:sum(L)} || {Tag,L} <- Al4].
-
%% live_opt/4.
-%% Bit syntax instructions.
-live_opt([{bs_context_to_binary,Src}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init,Fail,_,none,Ss,Dst}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, x_dead([Dst], Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init,Fail,Info,Live0,Ss,Dst}|Is], Regs0, D, Acc) ->
- Regs1 = x_dead([Dst], Regs0),
- Live = live_regs(Regs1),
- true = Live =< Live0, %Assertion.
- Regs2 = live_call(Live),
- Regs3 = x_live(Ss, Regs2),
- Regs = live_join_label(Fail, D, Regs3),
- I = {bs_init,Fail,Info,Live,Ss,Dst},
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_put,Fail,_,Ss}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_restore2,Src,_}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_save2,Src,_}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], Regs0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{test,bs_start_match2,Fail,Live,[Src,_],_}=I|Is], _, D, Acc) ->
- Regs0 = live_call(Live),
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% Other instructions.
-live_opt([{block,Bl0}|Is], Regs0, D, Acc) ->
- Live0 = make_anno({used,Regs0}),
- {Bl,Regs} = live_opt_block(reverse(Bl0), Regs0, D, [Live0]),
- Live = make_anno({used,Regs}),
- live_opt(Is, Regs, D, [{block,[Live|Bl]}|Acc]);
-live_opt([build_stacktrace=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
-live_opt([raw_raise=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(3), D, [I|Acc]);
-live_opt([{label,L}=I|Is], Regs, D0, Acc) ->
- D = gb_trees:insert(L, Regs, D0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{jump,{f,L}}=I|Is], _, D, Acc) ->
- Regs = gb_trees:get(L, D),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([return=I|Is], _, D, Acc) ->
- live_opt(Is, 1, D, [I|Acc]);
-live_opt([{catch_end,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(1), D, [I|Acc]);
-live_opt([{badmatch,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{case_end,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_case_end,Src}=I|Is], _, D, Acc) ->
- Regs = x_live([Src], 0),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([if_end=I|Is], _, D, Acc) ->
- Regs = 0,
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{call,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_ext,Arity,_}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{call_fun,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+1), D, [I|Acc]);
-live_opt([{apply,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity+2), D, [I|Acc]);
-live_opt([{make_fun2,_,_,_,Arity}=I|Is], _, D, Acc) ->
- live_opt(Is, live_call(Arity), D, [I|Acc]);
-live_opt([{test,_,Fail,Ss}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{test,_,Fail,Live,Ss,_}=I|Is], _, D, Acc) ->
- Regs0 = live_call(Live),
- Regs1 = x_live(Ss, Regs0),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{select,_,Src,Fail,List}=I|Is], _, D, Acc) ->
- Regs0 = 0,
- Regs1 = x_live([Src], Regs0),
- Regs = live_join_labels([Fail|List], D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_case,Y}=I|Is], Regs0, D, Acc) ->
- Regs = live_call(1),
- case Regs0 of
- 0 ->
- live_opt(Is, Regs, D, [{try_end,Y}|Acc]);
- _ ->
- live_opt(Is, live_call(1), D, [I|Acc])
- end;
-live_opt([{loop_rec,_Fail,_Dst}=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([timeout=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([{wait,_}=I|Is], _, D, Acc) ->
- live_opt(Is, 0, D, [I|Acc]);
-live_opt([{get_map_elements,Fail,Src,{list,List}}=I|Is], Regs0, D, Acc) ->
- {Ss,Ds} = split_even(List),
- Regs1 = x_live([Src|Ss], x_dead(Ds, Regs0)),
- Regs = live_join_label(Fail, D, Regs1),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{gc_bif,N,F,R,As,Dst}=I|Is], Regs0, D, Acc) ->
- Bl = [{set,[Dst],As,{alloc,R,{gc_bif,N,F}}}],
- {_,Regs} = live_opt_block(Bl, Regs0, D, []),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bif,N,F,As,Dst}=I|Is], Regs0, D, Acc) ->
- Bl = [{set,[Dst],As,{bif,N,F}}],
- {_,Regs} = live_opt_block(Bl, Regs0, D, []),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{get_tuple_element,Src,Idx,Dst}=I|Is], Regs0, D, Acc) ->
- Bl = [{set,[Dst],[Src],{get_tuple_element,Idx}}],
- {_,Regs} = live_opt_block(Bl, Regs0, D, []),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{move,Src,Dst}=I|Is], Regs0, D, Acc) ->
- Regs = x_live([Src], x_dead([Dst], Regs0)),
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{put_map,F,Op,S,Dst,R,{list,Puts}}=I|Is], Regs0, D, Acc) ->
- Bl = [{set,[Dst],[S|Puts],{alloc,R,{put_map,Op,F}}}],
- {_,Regs} = live_opt_block(Bl, Regs0, D, []),
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% Transparent instructions - they neither use nor modify x registers.
-live_opt([{deallocate,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{kill,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{try_end,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{loop_rec_end,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{wait_timeout,_,nil}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{wait_timeout,_,{Tag,_}}=I|Is], Regs, D, Acc) when Tag =/= x ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{line,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'catch',_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'try',_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-
-%% The following instructions can occur if the "compilation" has been
-%% started from a .S file using the 'from_asm' option.
-live_opt([{trim,_,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{'%',_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{recv_set,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{recv_mark,_}=I|Is], Regs, D, Acc) ->
- live_opt(Is, Regs, D, [I|Acc]);
-
-live_opt([], _, _, Acc) -> Acc.
-
-live_opt_block([{set,[{x,X}]=Ds,Ss,move}=I|Is], Regs0, D, Acc) ->
- Regs = x_live(Ss, x_dead(Ds, Regs0)),
- case is_live(X, Regs0) of
- true ->
- live_opt_block(Is, Regs, D, [I|Acc]);
- false ->
- %% Useless move, will never be used.
- live_opt_block(Is, Regs, D, Acc)
- end;
-live_opt_block([{set,Ds,Ss,{alloc,Live0,AllocOp}}|Is], Regs0, D, Acc) ->
- %% Calculate liveness from the point of view of the GC.
- %% There will never be a GC if the instruction fails, so we should
- %% ignore the failure branch.
- GcRegs1 = x_dead(Ds, Regs0),
- GcRegs = x_live(Ss, GcRegs1),
- Live = live_regs(GcRegs),
-
- %% The life-time analysis used by the code generator is sometimes too
- %% conservative, so it may be possible to lower the number of live
- %% registers based on the exact liveness information. The main benefit is
- %% that more optimizations that depend on liveness information (such as the
- %% beam_dead pass) may be applied.
- true = Live =< Live0, %Assertion.
- I = {set,Ds,Ss,{alloc,Live,AllocOp}},
-
- %% Calculate liveness from the point of view of the preceding instruction.
- %% The liveness is the union of live registers in the GC and the live
- %% registers at the failure label.
- Regs1 = live_call(Live),
- Regs = live_join_alloc(AllocOp, D, Regs1),
- live_opt_block(Is, Regs, D, [I|Acc]);
-live_opt_block([{set,Ds,Ss,{bif,_,Fail}}=I|Is], Regs0, D, Acc) ->
- Regs1 = x_dead(Ds, Regs0),
- Regs2 = x_live(Ss, Regs1),
- Regs = live_join_label(Fail, D, Regs2),
- live_opt_block(Is, Regs, D, [I|Acc]);
-live_opt_block([{set,Ds,Ss,_}=I|Is], Regs0, D, Acc) ->
- Regs = x_live(Ss, x_dead(Ds, Regs0)),
- live_opt_block(Is, Regs, D, [I|Acc]);
-live_opt_block([{'%anno',_}|Is], Regs, D, Acc) ->
- live_opt_block(Is, Regs, D, Acc);
-live_opt_block([], Regs, _, Acc) -> {Acc,Regs}.
-
-live_join_alloc({Kind,_Name,Fail}, D, Regs) when Kind =:= gc_bif; Kind =:= put_map ->
- live_join_label(Fail, D, Regs);
-live_join_alloc(_, _, Regs) -> Regs.
-
-live_join_labels([{f,L}|T], D, Regs0) when L =/= 0 ->
- Regs = gb_trees:get(L, D) bor Regs0,
- live_join_labels(T, D, Regs);
-live_join_labels([_|T], D, Regs) ->
- live_join_labels(T, D, Regs);
-live_join_labels([], _, Regs) -> Regs.
-
-live_join_label({f,0}, _, Regs) ->
- Regs;
-live_join_label({f,L}, D, Regs) ->
- gb_trees:get(L, D) bor Regs.
-
-live_call(Live) -> (1 bsl Live) - 1.
-
-live_regs(Regs) ->
- live_regs_1(0, Regs).
-
-live_regs_1(N, 0) -> N;
-live_regs_1(N, Regs) -> live_regs_1(N+1, Regs bsr 1).
-
-x_dead([{x,N}|Rs], Regs) -> x_dead(Rs, Regs band (bnot (1 bsl N)));
-x_dead([_|Rs], Regs) -> x_dead(Rs, Regs);
-x_dead([], Regs) -> Regs.
-
-x_live([{x,N}|Rs], Regs) -> x_live(Rs, Regs bor (1 bsl N));
-x_live([_|Rs], Regs) -> x_live(Rs, Regs);
-x_live([], Regs) -> Regs.
-
-is_live(X, Regs) -> ((Regs bsr X) band 1) =:= 1.
-
split_even([], Ss, Ds) ->
{reverse(Ss),reverse(Ds)};
split_even([S,D|Rs], Ss, Ds) ->
split_even(Rs, [S|Ss], [D|Ds]).
-
-%%%
-%%% Add annotations for defined registers.
-%%%
-%%% This analysis is done by scanning the instructions in
-%%% execution order.
-%%%
-
-defs([{apply,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{bif,_,{f,Fail},_Src,Dst}=I|Is], Regs0, D) ->
- Regs = def_regs([Dst], Regs0),
- [I|defs(Is, Regs, update_regs(Fail, Regs0, D))];
-defs([{block,Block0}|Is], Regs0, D0) ->
- {Block,Regs,D} = defs_list(Block0, Regs0, D0),
- [{block,[make_anno({def,Regs0})|Block]}|defs(Is, Regs, D)];
-defs([{bs_init,{f,L},_,Live,_,Dst}=I|Is], Regs0, D) ->
- Regs1 = case Live of
- none -> Regs0;
- _ -> init_def_regs(Live)
- end,
- Regs = def_regs([Dst], Regs1),
- [I|defs(Is, Regs, update_regs(L, Regs, D))];
-defs([{bs_put,{f,L},_,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, update_regs(L, Regs, D))];
-defs([build_stacktrace=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{call,_,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{call_ext,_,{extfunc,M,F,A}}=I|Is], _Regs, D) ->
- case erl_bifs:is_exit_bif(M, F, A) of
- false ->
- [I|defs(Is, 1, D)];
- true ->
- [I|defs_unreachable(Is, D)]
- end;
-defs([{call_ext,_,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{call_fun,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{'catch',_,{f,L}}=I|Is], Regs, D) ->
- RegsAtLabel = init_def_regs(1),
- [I|defs(Is, Regs, update_regs(L, RegsAtLabel, D))];
-defs([{catch_end,_}=I|Is], _Regs, D) ->
- Regs = init_def_regs(1),
- [I|defs(Is, Regs, D)];
-defs([{gc_bif,_,{f,Fail},Live,_Src,Dst}=I|Is], Regs0, D) ->
- true = all_defined(Live, Regs0), %Assertion.
- Regs = def_regs([Dst], init_def_regs(Live)),
- [I|defs(Is, Regs, update_regs(Fail, Regs0, D))];
-defs([{get_map_elements,{f,L},_Src,{list,DstList}}=I|Is], Regs0, D) ->
- {_,Ds} = beam_utils:split_even(DstList),
- Regs = def_regs(Ds, Regs0),
- [I|defs(Is, Regs, update_regs(L, Regs0, D))];
-defs([{get_tuple_element,_,_,Dst}=I|Is], Regs0, D) ->
- Regs = def_regs([Dst], Regs0),
- [I|defs(Is, Regs, D)];
-defs([{jump,{f,L}}=I|Is], Regs, D) ->
- [I|defs_unreachable(Is, update_regs(L, Regs, D))];
-defs([{label,L}=I|Is], Regs0, D) ->
- case D of
- #{L:=Regs1} ->
- Regs = Regs0 band Regs1,
- [I|defs(Is, Regs, D)];
- #{} ->
- [I|defs(Is, Regs0, D)]
- end;
-defs([{loop_rec,{f,L},{x,0}}=I|Is], _Regs, D0) ->
- RegsAtLabel = init_def_regs(0),
- D = update_regs(L, RegsAtLabel, D0),
- [I|defs(Is, init_def_regs(1), D)];
-defs([{loop_rec_end,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 0, D)];
-defs([{make_fun2,_,_,_,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([{move,_,Dst}=I|Is], Regs0, D) ->
- Regs = def_regs([Dst], Regs0),
- [I|defs(Is, Regs, D)];
-defs([{put_map,{f,Fail},_,_,Dst,_,_}=I|Is], Regs0, D) ->
- Regs = def_regs([Dst], Regs0),
- [I|defs(Is, Regs, update_regs(Fail, Regs0, D))];
-defs([raw_raise=I|Is], _Regs, D) ->
- [I|defs(Is, 1, D)];
-defs([return=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-defs([{select,_,_Src,Fail,List}=I|Is], Regs, D0) ->
- D = update_list([Fail|List], Regs, D0),
- [I|defs_unreachable(Is, D)];
-defs([{test,_,{f,L},_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, update_regs(L, Regs, D))];
-defs([{test,_,{f,L},Live,_,Dst}=I|Is], Regs0, D) ->
- true = all_defined(Live, Regs0), %Assertion.
- Regs = def_regs([Dst], init_def_regs(Live)),
- [I|defs(Is, Regs, update_regs(L, Regs0, D))];
-defs([{'try',_,{f,L}}=I|Is], Regs, D) ->
- RegsAtLabel = init_def_regs(3),
- [I|defs(Is, Regs, update_regs(L, RegsAtLabel, D))];
-defs([{try_case,_}=I|Is], _Regs, D) ->
- [I|defs(Is, init_def_regs(3), D)];
-defs([{wait,_}=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-defs([{wait_timeout,_,_}=I|Is], _Regs, D) ->
- [I|defs(Is, 0, D)];
-
-%% Exceptions.
-defs([{badmatch,_}=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-defs([{case_end,_}=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-defs([if_end=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-defs([{try_case_end,_}=I|Is], _Regs, D) ->
- [I|defs_unreachable(Is, D)];
-
-%% Neutral instructions
-defs([{bs_context_to_binary,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{bs_restore2,_,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{bs_save2,_,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{deallocate,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{kill,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{line,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{recv_mark,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{recv_set,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([timeout=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{trim,_,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{try_end,_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([{'%',_}=I|Is], Regs, D) ->
- [I|defs(Is, Regs, D)];
-defs([], _, _) -> [].
-
-defs_unreachable([{label,L}=I|Is], D) ->
- case D of
- #{L:=Regs} ->
- [I|defs(Is, Regs, D)];
- #{} ->
- defs_unreachable(Is, D)
- end;
-defs_unreachable([_|Is], D) ->
- defs_unreachable(Is, D);
-defs_unreachable([], _D) -> [].
-
-defs_list(Is, Regs, D) ->
- defs_list(Is, Regs, D, []).
-
-defs_list([{set,Ds,_,{alloc,Live,Info}}=I|Is], Regs0, D0, Acc) ->
- true = all_defined(Live, Regs0), %Assertion.
- D = case Info of
- {gc_bif,_,{f,Fail}} ->
- update_regs(Fail, Regs0, D0);
- {put_map,_,{f,Fail}} ->
- update_regs(Fail, Regs0, D0);
- _ ->
- D0
- end,
- Regs = def_regs(Ds, init_def_regs(Live)),
- defs_list(Is, Regs, D, [I|Acc]);
-defs_list([{set,Ds,_,Info}=I|Is], Regs0, D0, Acc) ->
- D = case Info of
- {bif,_,{f,Fail}} ->
- update_regs(Fail, Regs0, D0);
- {try_catch,'catch',{f,Fail}} ->
- update_regs(Fail, init_def_regs(1), D0);
- {try_catch,'try',{f,Fail}} ->
- update_regs(Fail, init_def_regs(3), D0);
- _ ->
- D0
- end,
- Regs = def_regs(Ds, Regs0),
- defs_list(Is, Regs, D, [I|Acc]);
-defs_list([], Regs, D, Acc) ->
- {reverse(Acc),Regs,D}.
-
-init_def_regs(Arity) ->
- (1 bsl Arity) - 1.
-
-def_regs([{x,X}|T], Regs) ->
- def_regs(T, Regs bor (1 bsl X));
-def_regs([_|T], Regs) ->
- def_regs(T, Regs);
-def_regs([], Regs) -> Regs.
-
-update_list([{f,L}|T], Regs, D0) ->
- D = update_regs(L, Regs, D0),
- update_list(T, Regs, D);
-update_list([_|T], Regs, D) ->
- update_list(T, Regs, D);
-update_list([], _Regs, D) -> D.
-
-update_regs(L, Regs0, D) ->
- case D of
- #{L:=Regs1} ->
- Regs = Regs0 band Regs1,
- D#{L:=Regs};
- #{} ->
- D#{L=>Regs0}
- end.
-
-all_defined(Live, Regs) ->
- All = (1 bsl Live) - 1,
- Regs band All =:= All.
-
-%%%
-%%% Utilities.
-%%%
-
-%% make_anno(Anno) -> WrappedAnno.
-%% Wrap an annotation term.
-
-make_anno(Anno) ->
- {'%anno',Anno}.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index a1b71251b7..7d908df3bf 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -27,7 +27,7 @@
%% Interface for compiler.
-export([module/2, format_error/1]).
--import(lists, [any/2,dropwhile/2,foldl/3,foreach/2,reverse/1]).
+-import(lists, [any/2,dropwhile/2,foldl/3,map/2,foreach/2,reverse/1]).
%% To be called by the compiler.
@@ -90,33 +90,30 @@ format_error(Error) ->
%% format as used in the compiler and in .S files.
validate(Module, Fs) ->
- Ft = index_bs_start_match(Fs, []),
+ Ft = index_parameter_types(Fs, []),
validate_0(Module, Fs, Ft).
-index_bs_start_match([{function,_,_,Entry,Code0}|Fs], Acc0) ->
+index_parameter_types([{function,_,_,Entry,Code0}|Fs], Acc0) ->
Code = dropwhile(fun({label,L}) when L =:= Entry -> false;
(_) -> true
end, Code0),
case Code of
[{label,Entry}|Is] ->
- Acc = index_bs_start_match_1(Is, Entry, Acc0),
- index_bs_start_match(Fs, Acc);
+ Acc = index_parameter_types_1(Is, Entry, Acc0),
+ index_parameter_types(Fs, Acc);
_ ->
%% Something serious is wrong. Ignore it for now.
%% It will be detected and diagnosed later.
- index_bs_start_match(Fs, Acc0)
+ index_parameter_types(Fs, Acc0)
end;
-index_bs_start_match([], Acc) ->
+index_parameter_types([], Acc) ->
gb_trees:from_orddict(lists:sort(Acc)).
-index_bs_start_match_1([{test,bs_start_match2,_,_,_,_}=I|_], Entry, Acc) ->
- [{Entry,[I]}|Acc];
-index_bs_start_match_1([{test,_,{f,F},_},{bs_context_to_binary,_}|Is0], Entry, Acc) ->
- [{label,F}|Is] = dropwhile(fun({label,L}) when L =:= F -> false;
- (_) -> true
- end, Is0),
- index_bs_start_match_1(Is, Entry, Acc);
-index_bs_start_match_1(_, _, Acc) -> Acc.
+index_parameter_types_1([{'%', {type_info, Reg, Type}} | Is], Entry, Acc) ->
+ Key = {Entry, Reg},
+ index_parameter_types_1(Is, Entry, [{Key, Type} | Acc]);
+index_parameter_types_1(_, _, Acc) ->
+ Acc.
validate_0(_Module, [], _) -> [];
validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
@@ -145,7 +142,9 @@ validate_0(Module, [{function,Name,Ar,Entry,Code}|Fs], Ft) ->
fls=undefined, %Floating point state.
ct=[], %List of hot catch/try labels
setelem=false, %Previous instruction was setelement/3.
- puts_left=none %put/1 instructions left.
+ puts_left=none, %put/1 instructions left.
+ defs=#{}, %Defining expression for each register.
+ aliases=#{}
}).
-type label() :: integer().
@@ -203,6 +202,12 @@ validate_fun_info_branches([], _, _) -> ok.
validate_fun_info_branches_1(Arity, {_,_,Arity}, _) -> ok;
validate_fun_info_branches_1(X, {Mod,Name,Arity}=MFA, Vst) ->
try
+ case Vst of
+ #vst{current=#st{numy=none}} ->
+ ok;
+ #vst{current=#st{numy=Size}} ->
+ error({unexpected_stack_frame,Size})
+ end,
get_term_type({x,X}, Vst)
catch Error ->
I = {func_info,{atom,Mod},{atom,Name},Arity},
@@ -280,18 +285,22 @@ valfun_1({try_case_end,Src}, Vst) ->
verify_y_init(Vst),
assert_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
-valfun_1({bs_context_to_binary,Ctx}, #vst{current=#st{x=Xs}}=Vst) ->
- case Ctx of
- {Tag,X} when Tag =:= x; Tag =:= y ->
- Type = case gb_trees:lookup(X, Xs) of
- {value,#ms{}} -> term;
- _ -> get_term_type(Ctx, Vst)
- end,
- set_type_reg(Type, Ctx, Vst);
- _ ->
- error({bad_source,Ctx})
- end;
+%% Instructions that cannot cause exceptions
+valfun_1({bs_get_tail,Ctx,Dst,Live}, Vst0) ->
+ verify_live(Live, Vst0),
+ verify_y_init(Vst0),
+ Vst = prune_x_regs(Live, Vst0),
+ #vst{current=#st{x=Xs,y=Ys}} = Vst,
+ {Reg, Tree} = case Ctx of
+ {x,X} -> {X, Xs};
+ {y,Y} -> {Y, Ys};
+ _ -> error({bad_source,Ctx})
+ end,
+ Type = case gb_trees:lookup(Reg, Tree) of
+ {value,#ms{}} -> propagate_fragility(term, [Ctx], Vst);
+ _ -> error({bad_context,Reg})
+ end,
+ set_type_reg(Type, Dst, Vst);
valfun_1(bs_init_writable=I, Vst) ->
call(I, 1, Vst);
valfun_1(build_stacktrace=I, Vst) ->
@@ -304,9 +313,10 @@ valfun_1({move,{y,_}=Src,{y,_}=Dst}, Vst) ->
{trytag,_} -> error({trytag,Src});
Type -> set_type_reg(Type, Dst, Vst)
end;
-valfun_1({move,Src,Dst}, Vst) ->
- Type = get_move_term_type(Src, Vst),
- set_type_reg(Type, Dst, Vst);
+valfun_1({move,Src,Dst}, Vst0) ->
+ Type = get_move_term_type(Src, Vst0),
+ Vst = set_type_reg(Type, Dst, Vst0),
+ set_alias(Src, Dst, Vst);
valfun_1({fmove,Src,{fr,_}=Dst}, Vst) ->
assert_type(float, Src, Vst),
set_freg(Dst, Vst);
@@ -332,7 +342,7 @@ valfun_1({bif,Op,{f,_},Src,Dst}=I, Vst) ->
%% catch state).
validate_src(Src, Vst),
Type = bif_type(Op, Src, Vst),
- set_type_reg(Type, Dst, Vst)
+ set_type_reg_expr(Type, I, Dst, Vst)
end;
%% Put instructions.
valfun_1({put_list,A,B,Dst}, Vst0) ->
@@ -340,6 +350,12 @@ valfun_1({put_list,A,B,Dst}, Vst0) ->
assert_term(B, Vst0),
Vst = eat_heap(2, Vst0),
set_type_reg(cons, Dst, Vst);
+valfun_1({put_tuple2,Dst,{list,Elements}}, Vst0) ->
+ _ = [assert_term(El, Vst0) || El <- Elements],
+ Size = length(Elements),
+ Vst = eat_heap(Size+1, Vst0),
+ Type = {tuple,Size},
+ set_type_reg(Type, Dst, Vst);
valfun_1({put_tuple,Sz,Dst}, Vst0) when is_integer(Sz) ->
Vst1 = eat_heap(1, Vst0),
Vst = set_type_reg(tuple_in_progress, Dst, Vst1),
@@ -370,6 +386,25 @@ valfun_1(remove_message, Vst) ->
%% The message term is no longer fragile. It can be used
%% without restrictions.
remove_fragility(Vst);
+valfun_1({'%', {type_info, Reg, Info0}}, Vst0) ->
+ %% Explicit type information inserted by optimization passes to indicate
+ %% that Reg has a certain type, so that we can accept cross-function type
+ %% optimizations.
+ %%
+ %% At the moment we only allow this when narrowing from 'term' which is
+ %% what to expect with function parameters, but in theory any narrowing
+ %% conversion should be legal.
+ case get_move_term_type(Reg, Vst0) of
+ term ->
+ Type0 = case Info0 of
+ match_context -> #ms{};
+ _ -> Info0
+ end,
+ Type = propagate_fragility(Type0, [Reg], Vst0),
+ set_type_reg(Type, Reg, Vst0);
+ _ ->
+ error(bad_type_info)
+ end;
valfun_1({'%',_}, Vst) ->
Vst;
valfun_1({line,_}, Vst) ->
@@ -408,35 +443,27 @@ valfun_1({trim,N,Remaining}, #vst{current=#st{y=Yregs0,numy=NumY}=St}=Vst) ->
N =< NumY, N+Remaining =:= NumY ->
Yregs1 = [{Y-N,Type} || {Y,Type} <- gb_trees:to_list(Yregs0), Y >= N],
Yregs = gb_trees_from_list(Yregs1),
- Vst#vst{current=St#st{y=Yregs,numy=NumY-N}};
+ Vst#vst{current=St#st{y=Yregs,numy=NumY-N,aliases=#{}}};
true ->
error({trim,N,Remaining,allocated,NumY})
end;
%% Catch & try.
-valfun_1({'catch',Dst,{f,Fail}}, Vst0) when Fail /= none ->
- Vst = #vst{current=#st{ct=Fails}=St} =
- set_type_y({catchtag,[Fail]}, Dst, Vst0),
- Vst#vst{current=St#st{ct=[[Fail]|Fails]}};
-valfun_1({'try',Dst,{f,Fail}}, Vst0) ->
- Vst = #vst{current=#st{ct=Fails}=St} =
- set_type_y({trytag,[Fail]}, Dst, Vst0),
- Vst#vst{current=St#st{ct=[[Fail]|Fails]}};
+valfun_1({'catch',Dst,{f,Fail}}, Vst) when Fail =/= none ->
+ init_try_catch_branch(catchtag, Dst, Fail, Vst);
+valfun_1({'try',Dst,{f,Fail}}, Vst) when Fail =/= none ->
+ init_try_catch_branch(trytag, Dst, Fail, Vst);
valfun_1({catch_end,Reg}, #vst{current=#st{ct=[Fail|Fails]}}=Vst0) ->
case get_special_y_type(Reg, Vst0) of
{catchtag,Fail} ->
Vst = #vst{current=St} = set_catch_end(Reg, Vst0),
- Xs = gb_trees_from_list([{0,term}]),
- Vst#vst{current=St#st{x=Xs,ct=Fails,fls=undefined}};
+ Xregs = gb_trees:enter(0, term, St#st.x),
+ Vst#vst{current=St#st{x=Xregs,ct=Fails,fls=undefined,aliases=#{}}};
Type ->
error({bad_type,Type})
end;
-valfun_1({try_end,Reg}, #vst{current=#st{ct=[Fail|Fails]}=St0}=Vst0) ->
- case get_special_y_type(Reg, Vst0) of
+valfun_1({try_end,Reg}, #vst{current=#st{ct=[Fail|Fails]}=St0}=Vst) ->
+ case get_special_y_type(Reg, Vst) of
{trytag,Fail} ->
- Vst = case Fail of
- [FailLabel] -> branch_state(FailLabel, Vst0);
- _ -> Vst0
- end,
St = St0#st{ct=Fails,fls=undefined},
set_catch_end(Reg, Vst#vst{current=St});
Type ->
@@ -447,18 +474,55 @@ valfun_1({try_case,Reg}, #vst{current=#st{ct=[Fail|Fails]}}=Vst0) ->
{trytag,Fail} ->
Vst = #vst{current=St} = set_catch_end(Reg, Vst0),
Xs = gb_trees_from_list([{0,{atom,[]}},{1,term},{2,term}]),
- Vst#vst{current=St#st{x=Xs,ct=Fails,fls=undefined}};
+ Vst#vst{current=St#st{x=Xs,ct=Fails,fls=undefined,aliases=#{}}};
Type ->
error({bad_type,Type})
end;
+valfun_1({get_list,Src,D1,D2}, Vst0) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst0),
+ Vst = set_type_reg(term, Src, D1, Vst0),
+ set_type_reg(term, Src, D2, Vst);
+valfun_1({get_hd,Src,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
+valfun_1({get_tl,Src,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type(cons, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
+valfun_1({get_tuple_element,Src,I,Dst}, Vst) ->
+ assert_not_literal(Src),
+ assert_type({tuple_element,I+1}, Src, Vst),
+ set_type_reg(term, Src, Dst, Vst);
+valfun_1({jump,{f,Lbl}}, Vst) ->
+ kill_state(branch_state(Lbl, Vst));
valfun_1(I, Vst) ->
valfun_2(I, Vst).
+init_try_catch_branch(Tag, Dst, Fail, Vst0) ->
+ Vst1 = set_type_y({Tag,[Fail]}, Dst, Vst0),
+ #vst{current=#st{ct=Fails}=St0} = Vst1,
+ CurrentSt = St0#st{ct=[[Fail]|Fails]},
+
+ %% Set the initial state at the try/catch label.
+ %% Assume that Y registers contain terms or try/catch
+ %% tags.
+ Yregs0 = map(fun({Y,uninitialized}) -> {Y,term};
+ ({Y,initialized}) -> {Y,term};
+ (E) -> E
+ end, gb_trees:to_list(CurrentSt#st.y)),
+ Yregs = gb_trees:from_orddict(Yregs0),
+ BranchSt = CurrentSt#st{y=Yregs},
+
+ Vst = branch_state(Fail, Vst1#vst{current=BranchSt}),
+ Vst#vst{current=CurrentSt}.
+
%% Update branched state if necessary and try next set of instructions.
valfun_2(I, #vst{current=#st{ct=[]}}=Vst) ->
valfun_3(I, Vst);
valfun_2(I, #vst{current=#st{ct=[[Fail]|_]}}=Vst) when is_integer(Fail) ->
- %% Update branched state
+ %% Update branched state.
valfun_3(I, branch_state(Fail, Vst));
valfun_2(_, _) ->
error(ambiguous_catch_try_state).
@@ -528,18 +592,18 @@ valfun_4({call_ext_last,_,_,_}, #vst{current=#st{numy=NumY}}) ->
valfun_4({make_fun2,_,_,_,Live}, Vst) ->
call(make_fun, Live, Vst);
%% Other BIFs
-valfun_4({bif,tuple_size,{f,Fail},[Tuple],Dst}, Vst0) ->
+valfun_4({bif,tuple_size,{f,Fail},[Tuple],Dst}=I, Vst0) ->
TupleType0 = get_term_type(Tuple, Vst0),
Vst1 = branch_state(Fail, Vst0),
TupleType = upgrade_tuple_type({tuple,[0]}, TupleType0),
- Vst = set_type(TupleType, Tuple, Vst1),
- set_type_reg({integer,[]}, Dst, Vst);
+ Vst = set_aliased_type(TupleType, Tuple, Vst1),
+ set_type_reg_expr({integer,[]}, I, Dst, Vst);
valfun_4({bif,element,{f,Fail},[Pos,Tuple],Dst}, Vst0) ->
TupleType0 = get_term_type(Tuple, Vst0),
PosType = get_term_type(Pos, Vst0),
Vst1 = branch_state(Fail, Vst0),
TupleType = upgrade_tuple_type({tuple,[get_tuple_size(PosType)]}, TupleType0),
- Vst = set_type(TupleType, Tuple, Vst1),
+ Vst = set_aliased_type(TupleType, Tuple, Vst1),
set_type_reg(term, Tuple, Dst, Vst);
valfun_4({bif,raise,{f,0},Src,_Dst}, Vst) ->
validate_src(Src, Vst),
@@ -549,9 +613,23 @@ valfun_4(raw_raise=I, Vst) ->
valfun_4({bif,map_get,{f,Fail},[_Key,Map]=Src,Dst}, Vst0) ->
validate_src(Src, Vst0),
Vst1 = branch_state(Fail, Vst0),
- Vst = set_type(map, Map, Vst1),
+ Vst = set_aliased_type(map, Map, Vst1),
Type = propagate_fragility(term, Src, Vst),
set_type_reg(Type, Dst, Vst);
+valfun_4({bif,is_map_key,{f,Fail},[_Key,Map]=Src,Dst}, Vst0) ->
+ validate_src(Src, Vst0),
+ Vst1 = branch_state(Fail, Vst0),
+ Vst = set_aliased_type(map, Map, Vst1),
+ Type = propagate_fragility(bool, Src, Vst),
+ set_type_reg(Type, Dst, Vst);
+valfun_4({bif,Op,{f,Fail},[Cons]=Src,Dst}, Vst0)
+ when Op =:= hd; Op =:= tl ->
+ validate_src(Src, Vst0),
+ Vst1 = branch_state(Fail, Vst0),
+ Vst = set_aliased_type(cons, Cons, Vst1),
+ Type0 = bif_type(Op, Src, Vst),
+ Type = propagate_fragility(Type0, Src, Vst),
+ set_type_reg(Type, Dst, Vst);
valfun_4({bif,Op,{f,Fail},Src,Dst}, Vst0) ->
validate_src(Src, Vst0),
Vst = branch_state(Fail, Vst0),
@@ -564,7 +642,13 @@ valfun_4({gc_bif,Op,{f,Fail},Live,Src,Dst}, #vst{current=St0}=Vst0) ->
St = kill_heap_allocation(St0),
Vst1 = Vst0#vst{current=St},
Vst2 = branch_state(Fail, Vst1),
- Vst = prune_x_regs(Live, Vst2),
+ Vst3 = prune_x_regs(Live, Vst2),
+ Vst = case Op of
+ map_size ->
+ set_type(map, hd(Src), Vst3);
+ _ ->
+ Vst3
+ end,
validate_src(Src, Vst),
Type0 = bif_type(Op, Src, Vst),
Type = propagate_fragility(Type0, Src, Vst),
@@ -574,8 +658,6 @@ valfun_4(return, #vst{current=#st{numy=none}}=Vst) ->
kill_state(Vst);
valfun_4(return, #vst{current=#st{numy=NumY}}) ->
error({stack_frame,NumY});
-valfun_4({jump,{f,Lbl}}, Vst) ->
- kill_state(branch_state(Lbl, Vst));
valfun_4({loop_rec,{f,Fail},Dst}, Vst0) ->
Vst = branch_state(Fail, Vst0),
%% This term may not be part of the root set until
@@ -602,54 +684,60 @@ valfun_4({set_tuple_element,Src,Tuple,I}, Vst) ->
assert_type({tuple_element,I+1}, Tuple, Vst),
Vst;
%% Match instructions.
-valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
- assert_term(Src, Vst),
- Lbls = [L || {f,L} <- Choices]++[Fail],
- kill_state(foldl(fun(L, S) -> branch_state(L, S) end, Vst, Lbls));
+valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst0) ->
+ assert_term(Src, Vst0),
+ assert_choices(Choices),
+ Vst = branch_state(Fail, Vst0),
+ kill_state(select_val_branches(Src, Choices, Vst));
valfun_4({select_tuple_arity,Tuple,{f,Fail},{list,Choices}}, Vst) ->
assert_type(tuple, Tuple, Vst),
- kill_state(branch_arities(Choices, Tuple, branch_state(Fail, Vst)));
-valfun_4({get_list,Src,D1,D2}, Vst0) ->
- assert_type(cons, Src, Vst0),
- Vst = set_type_reg(term, Src, D1, Vst0),
- set_type_reg(term, Src, D2, Vst);
-valfun_4({get_hd,Src,Dst}, Vst) ->
- assert_type(cons, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
-valfun_4({get_tl,Src,Dst}, Vst) ->
- assert_type(cons, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
-valfun_4({get_tuple_element,Src,I,Dst}, Vst) ->
- assert_type({tuple_element,I+1}, Src, Vst),
- set_type_reg(term, Src, Dst, Vst);
+ assert_arities(Choices),
+ TupleType = case get_term_type(Tuple, Vst) of
+ {fragile,TupleType0} -> TupleType0;
+ TupleType0 -> TupleType0
+ end,
+ kill_state(branch_arities(Choices, Tuple, TupleType,
+ branch_state(Fail, Vst)));
%% New bit syntax matching instructions.
-valfun_4({test,bs_start_match2,{f,Fail},Live,[Ctx,NeedSlots],Ctx}, Vst0) ->
- %% If source and destination registers are the same, match state
- %% is OK as input.
- CtxType = get_move_term_type(Ctx, Vst0),
+valfun_4({test,bs_start_match3,{f,Fail},Live,[Src],Dst}, Vst0) ->
+ %% Match states are always okay as input.
+ SrcType = get_move_term_type(Src, Vst0),
+ DstType = propagate_fragility(bsm_match_state(), [Src], Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
Vst1 = prune_x_regs(Live, Vst0),
- BranchVst = case CtxType of
- #ms{} ->
- %% The failure branch will never be taken when Ctx
- %% is a match context. Therefore, the type for Ctx
- %% at the failure label must not be match_context
- %% (or we could reject legal code).
- set_type_reg(term, Ctx, Vst1);
- _ ->
- Vst1
- end,
+ BranchVst = case SrcType of
+ #ms{} ->
+ %% The failure branch will never be taken when Src is a
+ %% match context. Therefore, the type for Src at the
+ %% failure label must not be match_context (or we could
+ %% reject legal code).
+ set_type_reg(term, Src, Vst1);
+ _ ->
+ Vst1
+ end,
Vst = branch_state(Fail, BranchVst),
- set_type_reg(bsm_match_state(NeedSlots), Ctx, Vst);
+ set_type_reg(DstType, Dst, Vst);
valfun_4({test,bs_start_match2,{f,Fail},Live,[Src,Slots],Dst}, Vst0) ->
- assert_term(Src, Vst0),
+ %% Match states are always okay as input.
+ SrcType = get_move_term_type(Src, Vst0),
+ DstType = propagate_fragility(bsm_match_state(Slots), [Src], Vst0),
verify_live(Live, Vst0),
verify_y_init(Vst0),
Vst1 = prune_x_regs(Live, Vst0),
- Vst = branch_state(Fail, Vst1),
- set_type_reg(bsm_match_state(Slots), Src, Dst, Vst);
+ BranchVst = case SrcType of
+ #ms{} ->
+ %% The failure branch will never be taken when Src is a
+ %% match context. Therefore, the type for Src at the
+ %% failure label must not be match_context (or we could
+ %% reject legal code).
+ set_type_reg(term, Src, Vst1);
+ _ ->
+ Vst1
+ end,
+ Vst = branch_state(Fail, BranchVst),
+ set_type_reg(DstType, Dst, Vst);
valfun_4({test,bs_match_string,{f,Fail},[Ctx,_,_]}, Vst) ->
bsm_validate_context(Ctx, Vst),
branch_state(Fail, Vst);
@@ -686,6 +774,16 @@ valfun_4({bs_save2,Ctx,SavePoint}, Vst) ->
bsm_save(Ctx, SavePoint, Vst);
valfun_4({bs_restore2,Ctx,SavePoint}, Vst) ->
bsm_restore(Ctx, SavePoint, Vst);
+valfun_4({bs_get_position, Ctx, Dst, Live}, Vst0) ->
+ bsm_validate_context(Ctx, Vst0),
+ verify_live(Live, Vst0),
+ verify_y_init(Vst0),
+ Vst = prune_x_regs(Live, Vst0),
+ set_type_reg(bs_position, Dst, Vst);
+valfun_4({bs_set_position, Ctx, Pos}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ assert_type(bs_position, Pos, Vst),
+ Vst;
%% Other test instructions.
valfun_4({test,is_float,{f,Lbl},[Float]}, Vst) ->
@@ -694,16 +792,19 @@ valfun_4({test,is_float,{f,Lbl},[Float]}, Vst) ->
valfun_4({test,is_tuple,{f,Lbl},[Tuple]}, Vst) ->
Type0 = get_term_type(Tuple, Vst),
Type = upgrade_tuple_type({tuple,[0]}, Type0),
- set_type(Type, Tuple, branch_state(Lbl, Vst));
+ set_aliased_type(Type, Tuple, branch_state(Lbl, Vst));
valfun_4({test,is_nonempty_list,{f,Lbl},[Cons]}, Vst) ->
assert_term(Cons, Vst),
- set_type(cons, Cons, branch_state(Lbl, Vst));
+ Type = cons,
+ set_aliased_type(Type, Cons, branch_state(Lbl, Vst));
valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
assert_type(tuple, Tuple, Vst),
- set_type_reg({tuple,Sz}, Tuple, branch_state(Lbl, Vst));
+ Type = {tuple,Sz},
+ set_aliased_type(Type, Tuple, branch_state(Lbl, Vst));
valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,_Atom]}, Vst) ->
validate_src([Src], Vst),
- set_type_reg({tuple, Sz}, Src, branch_state(Lbl, Vst));
+ Type = {tuple,Sz},
+ set_aliased_type(Type, Src, branch_state(Lbl, Vst));
valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
assert_type(map, Src, Vst),
assert_unique_map_keys(List),
@@ -712,11 +813,26 @@ valfun_4({test,is_map,{f,Lbl},[Src]}, Vst0) ->
Vst = branch_state(Lbl, Vst0),
case Src of
{Tag,_} when Tag =:= x; Tag =:= y ->
- set_type_reg(map, Src, Vst);
+ Type = map,
+ set_aliased_type(Type, Src, Vst);
{literal,Map} when is_map(Map) ->
- Vst;
+ Vst0;
_ ->
- kill_state(Vst)
+ kill_state(Vst0)
+ end;
+valfun_4({test,is_eq_exact,{f,Lbl},[Src,Val]=Ss}, Vst0) ->
+ validate_src(Ss, Vst0),
+ Infer = infer_types(Src, Vst0),
+ Vst1 = Infer(Val, Vst0),
+ Vst = branch_state(Lbl, Vst1),
+ case Val of
+ {literal,Tuple} when is_tuple(Tuple) ->
+ Type0 = get_term_type(Val, Vst),
+ Type = upgrade_tuple_type({tuple,tuple_size(Tuple)},
+ Type0),
+ set_aliased_type(Type, Src, Vst);
+ _ ->
+ Vst
end;
valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
validate_src(Src, Vst),
@@ -805,6 +921,7 @@ valfun_4(_, _) ->
error(unknown_instruction).
verify_get_map(Fail, Src, List, Vst0) ->
+ assert_not_literal(Src), %OTP 22.
assert_type(map, Src, Vst0),
Vst1 = foldl(fun(D, Vsti) ->
case is_reg_defined(D,Vsti) of
@@ -879,21 +996,15 @@ val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=true}}=Vst) ->
Vst;
+val_dsetel({get_tuple_element,_,_,_}, Vst) ->
+ Vst;
val_dsetel({line,_}, Vst) ->
Vst;
val_dsetel(_, #vst{current=#st{setelem=true}=St}=Vst) ->
Vst#vst{current=St#st{setelem=false}};
val_dsetel(_, Vst) -> Vst.
-kill_state(#vst{current=#st{ct=[[Fail]|_]}}=Vst) when is_integer(Fail) ->
- %% There is an active catch. Make sure that we merge the state into
- %% the catch label before clearing it, so that that we can be sure
- %% that the label gets a state.
- kill_state_1(branch_state(Fail, Vst));
kill_state(Vst) ->
- kill_state_1(Vst).
-
-kill_state_1(Vst) ->
Vst#vst{current=none}.
%% A "plain" call.
@@ -906,7 +1017,7 @@ call(Name, Live, #vst{current=St}=Vst) ->
Type when Type =/= exception ->
%% Type is never 'exception' because it has been handled earlier.
Xs = gb_trees_from_list([{0,Type}]),
- Vst#vst{current=St#st{x=Xs,f=init_fregs()}}
+ Vst#vst{current=St#st{x=Xs,f=init_fregs(),aliases=#{}}}
end.
%% Tail call.
@@ -935,26 +1046,12 @@ verify_call_args_1(N, Vst) ->
verify_call_args_1(X, Vst).
verify_local_call(Lbl, Live, Vst) ->
- case all_ms_in_x_regs(Live, Vst) of
- [{R,Ctx}] ->
- %% Verify that there is a suitable bs_start_match2 instruction.
- verify_call_match_context(Lbl, R, Vst),
-
- %% Since the callee has consumed the match context,
- %% there must be no additional copies in Y registers.
- #ms{id=Id} = Ctx,
- case ms_in_y_regs(Id, Vst) of
- [] ->
- ok;
- [_|_]=Ys ->
- error({multiple_match_contexts,[R|Ys]})
- end;
- [_,_|_]=Xs0 ->
- Xs = [R || {R,_} <- Xs0],
- error({multiple_match_contexts,Xs});
- [] ->
- ok
- end.
+ F = fun({R, _Ctx}) ->
+ verify_call_match_context(Lbl, R, Vst)
+ end,
+ MsRegs = all_ms_in_x_regs(Live, Vst),
+ verify_no_ms_aliases(MsRegs),
+ foreach(F, MsRegs).
all_ms_in_x_regs(0, _Vst) ->
[];
@@ -962,24 +1059,26 @@ all_ms_in_x_regs(Live0, Vst) ->
Live = Live0 - 1,
R = {x,Live},
case get_move_term_type(R, Vst) of
- #ms{}=M ->
- [{R,M}|all_ms_in_x_regs(Live, Vst)];
- _ ->
- all_ms_in_x_regs(Live, Vst)
+ #ms{}=M -> [{R,M} | all_ms_in_x_regs(Live, Vst)];
+ _ -> all_ms_in_x_regs(Live, Vst)
end.
-ms_in_y_regs(Id, #vst{current=#st{y=Ys0}}) ->
- Ys = gb_trees:to_list(Ys0),
- [{y,Y} || {Y,#ms{id=OtherId}} <- Ys, OtherId =:= Id].
+%% Verifies that the same match context isn't present twice.
+verify_no_ms_aliases(MsRegs) ->
+ CtxIds = [Id || {_, #ms{id=Id}} <- MsRegs],
+ UniqueCtxIds = ordsets:from_list(CtxIds),
+ if
+ length(UniqueCtxIds) < length(CtxIds) ->
+ error({multiple_match_contexts, MsRegs});
+ length(UniqueCtxIds) =:= length(CtxIds) ->
+ ok
+ end.
+%% Verifies that the target label accepts match contexts in the given register.
verify_call_match_context(Lbl, Ctx, #vst{ft=Ft}) ->
- case gb_trees:lookup(Lbl, Ft) of
- none ->
- error(no_bs_start_match2);
- {value,[{test,bs_start_match2,_,_,[Ctx,_],Ctx}|_]} ->
- ok;
- {value,[{test,bs_start_match2,_,_,_,_}=I|_]} ->
- error({unsuitable_bs_start_match2,I})
+ case gb_trees:lookup({Lbl, Ctx}, Ft) of
+ {value, match_context} -> ok;
+ none -> error(no_bs_start_match2)
end.
allocate(Zero, Stk, Heap, Live, #vst{current=#st{numy=none}}=Vst0) ->
@@ -1019,13 +1118,50 @@ heap_alloc_2([{floats,Floats}|T], St0) ->
St = St0#st{hf=Floats},
heap_alloc_2(T, St);
heap_alloc_2([], St) -> St.
-
-prune_x_regs(Live, #vst{current=#st{x=Xs0}=St0}=Vst) when is_integer(Live) ->
+
+prune_x_regs(Live, #vst{current=St0}=Vst)
+ when is_integer(Live) ->
+ #st{x=Xs0,defs=Defs0,aliases=Aliases0} = St0,
Xs1 = gb_trees:to_list(Xs0),
Xs = [P || {R,_}=P <- Xs1, R < Live],
- St = St0#st{x=gb_trees:from_orddict(Xs)},
+ Defs = maps:filter(fun({x,X}, _) -> X < Live;
+ ({y,_}, _) -> true
+ end, Defs0),
+ Aliases = maps:filter(fun({x,X1}, {x,X2}) ->
+ X1 < Live andalso X2 < Live;
+ ({x,X}, _) ->
+ X < Live;
+ (_, {x,X}) ->
+ X < Live;
+ (_, _) ->
+ true
+ end, Aliases0),
+ St = St0#st{x=gb_trees:from_orddict(Xs),defs=Defs,aliases=Aliases},
Vst#vst{current=St}.
+%% All choices in a select_val list must be integers, floats, or atoms.
+%% All must be of the same type.
+assert_choices([{Tag,_},{f,_}|T]) ->
+ if
+ Tag =:= atom; Tag =:= float; Tag =:= integer ->
+ assert_choices_1(T, Tag);
+ true ->
+ error(bad_select_list)
+ end;
+assert_choices([]) -> ok.
+
+assert_choices_1([{Tag,_},{f,_}|T], Tag) ->
+ assert_choices_1(T, Tag);
+assert_choices_1([_,{f,_}|_], _Tag) ->
+ error(bad_select_list);
+assert_choices_1([], _Tag) -> ok.
+
+assert_arities([Arity,{f,_}|T]) when is_integer(Arity) ->
+ assert_arities(T);
+assert_arities([]) -> ok;
+assert_arities(_) -> error(bad_tuple_arity_list).
+
+
%%%
%%% Floating point checking.
%%%
@@ -1111,6 +1247,8 @@ assert_unique_map_keys([_,_|_]=Ls) ->
%%% New binary matching instructions.
%%%
+bsm_match_state() ->
+ #ms{}.
bsm_match_state(Slots) ->
#ms{slots=Slots}.
@@ -1124,6 +1262,12 @@ bsm_get_context({x,X}=Reg, #vst{current=#st{x=Xs}}=_Vst) when is_integer(X) ->
{value,{fragile,#ms{}=Ctx}} -> Ctx;
_ -> error({no_bsm_context,Reg})
end;
+bsm_get_context({y,Y}=Reg, #vst{current=#st{y=Ys}}=_Vst) when is_integer(Y) ->
+ case gb_trees:lookup(Y, Ys) of
+ {value,#ms{}=Ctx} -> Ctx;
+ {value,{fragile,#ms{}=Ctx}} -> Ctx;
+ _ -> error({no_bsm_context,Reg})
+ end;
bsm_get_context(Reg, _) -> error({bad_source,Reg}).
bsm_save(Reg, {atom,start}, Vst) ->
@@ -1154,10 +1298,74 @@ bsm_restore(Reg, SavePoint, Vst) ->
_ -> error({illegal_restore,SavePoint,range})
end.
+
+select_val_branches(Src, Choices, Vst) ->
+ Infer = infer_types(Src, Vst),
+ select_val_branches_1(Choices, Infer, Vst).
+
+select_val_branches_1([Val,{f,L}|T], Infer, Vst0) ->
+ Vst = branch_state(L, Infer(Val, Vst0)),
+ select_val_branches_1(T, Infer, Vst);
+select_val_branches_1([], _, Vst) -> Vst.
+
+infer_types(Src, Vst) ->
+ case get_def(Src, Vst) of
+ {bif,is_map,{f,_},[Map],_} ->
+ fun({atom,true}, S) -> set_type_reg(map, Map, S);
+ (_, S) -> S
+ end;
+ {bif,tuple_size,{f,_},[Tuple],_} ->
+ fun({integer,Arity}, S) ->
+ Type0 = get_term_type(Tuple, S),
+ Type = upgrade_tuple_type({tuple,Arity}, Type0),
+ set_type(Type, Tuple, S);
+ (_, S) -> S
+ end;
+ {bif,'=:=',{f,_},[ArityReg,{integer,_}=Val],_} when ArityReg =/= Src ->
+ fun({atom,true}, S) ->
+ Infer = infer_types(ArityReg, S),
+ Infer(Val, S);
+ (_, S) -> S
+ end;
+ _ ->
+ fun(_, S) -> S end
+ end.
+
%%%
%%% Keeping track of types.
%%%
+set_alias(Reg1, Reg2, #vst{current=St0}=Vst) ->
+ case Reg1 of
+ {Kind,_} when Kind =:= x; Kind =:= y ->
+ #st{aliases=Aliases0} = St0,
+ Aliases = Aliases0#{Reg1=>Reg2,Reg2=>Reg1},
+ St = St0#st{aliases=Aliases},
+ Vst#vst{current=St};
+ _ ->
+ Vst
+ end.
+
+set_aliased_type(Type, Reg, #vst{current=#st{aliases=Aliases}}=Vst0) ->
+ Vst1 = set_type(Type, Reg, Vst0),
+ case Aliases of
+ #{Reg:=OtherReg} ->
+ Vst = set_type_reg(Type, OtherReg, Vst1),
+ #vst{current=St} = Vst,
+ Vst#vst{current=St#st{aliases=Aliases}};
+ #{} ->
+ Vst1
+ end.
+
+kill_aliases(Reg, #st{aliases=Aliases0}=St) ->
+ case Aliases0 of
+ #{Reg:=OtherReg} ->
+ Aliases = maps:without([Reg,OtherReg], Aliases0),
+ St#st{aliases=Aliases};
+ #{} ->
+ St
+ end.
+
set_type(Type, {x,_}=Reg, Vst) -> set_type_reg(Type, Reg, Vst);
set_type(Type, {y,_}=Reg, Vst) -> set_type_y(Type, Reg, Vst);
set_type(_, _, #vst{}=Vst) -> Vst.
@@ -1170,12 +1378,18 @@ set_type_reg(Type, Src, Dst, Vst) ->
set_type_reg(Type, Dst, Vst)
end.
-set_type_reg(Type, {x,_}=Reg, Vst) ->
- set_type_x(Type, Reg, Vst);
set_type_reg(Type, Reg, Vst) ->
- set_type_y(Type, Reg, Vst).
+ set_type_reg_expr(Type, none, Reg, Vst).
-set_type_x(Type, {x,X}=Reg, #vst{current=#st{x=Xs0}=St}=Vst)
+set_type_reg_expr(Type, Expr, {x,_}=Reg, Vst) ->
+ set_type_x(Type, Expr, Reg, Vst);
+set_type_reg_expr(Type, Expr, Reg, Vst) ->
+ set_type_y(Type, Expr, Reg, Vst).
+
+set_type_y(Type, Reg, Vst) ->
+ set_type_y(Type, none, Reg, Vst).
+
+set_type_x(Type, Expr, {x,X}=Reg, #vst{current=#st{x=Xs0,defs=Defs0}=St0}=Vst)
when is_integer(X), 0 =< X ->
check_limit(Reg),
Xs = case gb_trees:lookup(X, Xs0) of
@@ -1186,11 +1400,13 @@ set_type_x(Type, {x,X}=Reg, #vst{current=#st{x=Xs0}=St}=Vst)
{value,_} ->
gb_trees:update(X, Type, Xs0)
end,
- Vst#vst{current=St#st{x=Xs}};
-set_type_x(Type, Reg, #vst{}) ->
+ Defs = Defs0#{Reg=>Expr},
+ St = kill_aliases(Reg, St0),
+ Vst#vst{current=St#st{x=Xs,defs=Defs}};
+set_type_x(Type, _Expr, Reg, #vst{}) ->
error({invalid_store,Reg,Type}).
-set_type_y(Type, {y,Y}=Reg, #vst{current=#st{y=Ys0}=St}=Vst)
+set_type_y(Type, Expr, {y,Y}=Reg, #vst{current=#st{y=Ys0,defs=Defs0}=St0}=Vst)
when is_integer(Y), 0 =< Y ->
check_limit(Reg),
Ys = case gb_trees:lookup(Y, Ys0) of
@@ -1204,8 +1420,11 @@ set_type_y(Type, {y,Y}=Reg, #vst{current=#st{y=Ys0}=St}=Vst)
gb_trees:update(Y, Type, Ys0)
end,
check_try_catch_tags(Type, Y, Ys0),
- Vst#vst{current=St#st{y=Ys}};
-set_type_y(Type, Reg, #vst{}) -> error({invalid_store,Reg,Type}).
+ Defs = Defs0#{Reg=>Expr},
+ St = kill_aliases(Reg, St0),
+ Vst#vst{current=St#st{y=Ys,defs=Defs}};
+set_type_y(Type, _Expr, Reg, #vst{}) ->
+ error({invalid_store,Reg,Type}).
make_fragile({fragile,_}=Type) -> Type;
make_fragile(Type) -> {fragile,Type}.
@@ -1252,6 +1471,10 @@ assert_term(Src, Vst) ->
get_term_type(Src, Vst),
ok.
+assert_not_literal({x,_}) -> ok;
+assert_not_literal({y,_}) -> ok;
+assert_not_literal(Literal) -> error({literal_not_allowed,Literal}).
+
%% The possible types.
%%
%% First non-term types:
@@ -1417,6 +1640,8 @@ get_term_type_1({atom,A}=T, _) when is_atom(A) -> T;
get_term_type_1({float,F}=T, _) when is_float(F) -> T;
get_term_type_1({integer,I}=T, _) when is_integer(I) -> T;
get_term_type_1({literal,Map}, _) when is_map(Map) -> map;
+get_term_type_1({literal,Tuple}, _) when is_tuple(Tuple) ->
+ {tuple,tuple_size(Tuple)};
get_term_type_1({literal,_}=T, _) -> T;
get_term_type_1({x,X}=Reg, #vst{current=#st{x=Xs}}) when is_integer(X) ->
case gb_trees:lookup(X, Xs) of
@@ -1431,6 +1656,11 @@ get_term_type_1({y,Y}=Reg, #vst{current=#st{y=Ys}}) when is_integer(Y) ->
end;
get_term_type_1(Src, _) -> error({bad_source,Src}).
+get_def(Src, #vst{current=#st{defs=Defs}}) ->
+ case Defs of
+ #{Src:=Def} -> Def;
+ #{} -> none
+ end.
%% get_literal(Src) -> literal_value().
get_literal(nil) -> [];
@@ -1440,13 +1670,20 @@ get_literal({integer,I}) when is_integer(I) -> I;
get_literal({literal,L}) -> L;
get_literal(T) -> error({not_literal,T}).
-
-branch_arities([], _, #vst{}=Vst) -> Vst;
-branch_arities([Sz,{f,L}|T], Tuple, #vst{current=St}=Vst0)
- when is_integer(Sz) ->
- Vst1 = set_type_reg({tuple,Sz}, Tuple, Vst0),
+branch_arities([Sz,{f,L}|T], Tuple, {tuple,[_]}=Type0, Vst0) when is_integer(Sz) ->
+ Vst1 = set_aliased_type({tuple,Sz}, Tuple, Vst0),
Vst = branch_state(L, Vst1),
- branch_arities(T, Tuple, Vst#vst{current=St}).
+ branch_arities(T, Tuple, Type0, Vst);
+branch_arities([Sz,{f,L}|T], Tuple, {tuple,Sz}=Type, Vst0) when is_integer(Sz) ->
+ %% The type is already correct. (This test is redundant.)
+ Vst = branch_state(L, Vst0),
+ branch_arities(T, Tuple, Type, Vst);
+branch_arities([Sz0,{f,_}|T], Tuple, {tuple,Sz}=Type, Vst)
+ when is_integer(Sz), Sz0 =/= Sz ->
+ %% We already have an established different exact size for the tuple.
+ %% This label can't possibly be reached.
+ branch_arities(T, Tuple, Type, Vst);
+branch_arities([], _, _, #vst{}=Vst) -> Vst.
branch_state(0, #vst{}=Vst) ->
%% If the instruction fails, the stack may be scanned
@@ -1476,13 +1713,14 @@ merge_states(L, St, Branched) when L =/= 0 ->
{value,OtherSt} -> merge_states_1(St, OtherSt)
end.
-merge_states_1(#st{x=Xs0,y=Ys0,numy=NumY0,h=H0,ct=Ct0},
- #st{x=Xs1,y=Ys1,numy=NumY1,h=H1,ct=Ct1}) ->
+merge_states_1(#st{x=Xs0,y=Ys0,numy=NumY0,h=H0,ct=Ct0,aliases=Aliases0},
+ #st{x=Xs1,y=Ys1,numy=NumY1,h=H1,ct=Ct1,aliases=Aliases1}) ->
NumY = merge_stk(NumY0, NumY1),
Xs = merge_regs(Xs0, Xs1),
Ys = merge_y_regs(Ys0, Ys1),
Ct = merge_ct(Ct0, Ct1),
- #st{x=Xs,y=Ys,numy=NumY,h=min(H0, H1),ct=Ct}.
+ Aliases = merge_aliases(Aliases0, Aliases1),
+ #st{x=Xs,y=Ys,numy=NumY,h=min(H0, H1),ct=Ct,aliases=Aliases}.
merge_stk(S, S) -> S;
merge_stk(_, _) -> undecided.
@@ -1567,6 +1805,12 @@ merge_types(bool, {atom,A}) ->
merge_bool(A);
merge_types({atom,A}, bool) ->
merge_bool(A);
+merge_types(cons, {literal,[_|_]}) ->
+ cons;
+merge_types({literal,[_|_]}, cons) ->
+ cons;
+merge_types({literal,[_|_]}, {literal,[_|_]}) ->
+ cons;
merge_types(#ms{id=Id1,valid=B1,slots=Slots1},
#ms{id=Id2,valid=B2,slots=Slots2}) ->
Id = if
@@ -1585,7 +1829,17 @@ merge_bool([]) -> {atom,[]};
merge_bool(true) -> bool;
merge_bool(false) -> bool;
merge_bool(_) -> {atom,[]}.
-
+
+merge_aliases(Al0, Al1) when map_size(Al0) =< map_size(Al1) ->
+ maps:filter(fun(K, V) ->
+ case Al1 of
+ #{K:=V} -> true;
+ #{} -> false
+ end
+ end, Al0);
+merge_aliases(Al0, Al1) ->
+ merge_aliases(Al1, Al0).
+
verify_y_init(#vst{current=#st{y=Ys}}) ->
verify_y_init_1(gb_trees:to_list(Ys)).
@@ -1752,6 +2006,12 @@ is_bif_safe(self, 0) -> true;
is_bif_safe(node, 0) -> true;
is_bif_safe(_, _) -> false.
+arith_type([A], Vst) ->
+ %% Unary '+' or '-'.
+ case get_term_type(A, Vst) of
+ {float,_} -> {float,[]};
+ _ -> number
+ end;
arith_type([A,B], Vst) ->
case {get_term_type(A, Vst),get_term_type(B, Vst)} of
{{float,_},_} -> {float,[]};
diff --git a/lib/compiler/src/beam_z.erl b/lib/compiler/src/beam_z.erl
index 1c9d762eb1..677094b3cd 100644
--- a/lib/compiler/src/beam_z.erl
+++ b/lib/compiler/src/beam_z.erl
@@ -110,6 +110,8 @@ undo_rename({test,has_map_fields,Fail,[Src|List]}) ->
{test,has_map_fields,Fail,Src,{list,List}};
undo_rename({get_map_elements,Fail,Src,{list,List}}) ->
{get_map_elements,Fail,Src,{list,List}};
+undo_rename({test,is_eq_exact,Fail,[Src,nil]}) ->
+ {test,is_nil,Fail,[Src]};
undo_rename({select,I,Reg,Fail,List}) ->
{I,Reg,Fail,{list,List}};
undo_rename(I) -> I.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 5ef9611504..65c4f140c9 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -31,6 +31,9 @@
%% Erlc interface.
-export([compile/3,compile_beam/3,compile_asm/3,compile_core/3]).
+%% Utility functions for compiler passes.
+-export([run_sub_passes/2]).
+
-export_type([option/0]).
-include("erl_compile.hrl").
@@ -39,6 +42,8 @@
-import(lists, [member/2,reverse/1,reverse/2,keyfind/3,last/1,
map/2,flatmap/2,foreach/2,foldr/3,any/2]).
+-define(SUB_PASS_TIMES, compile__sub_pass_times).
+
%%----------------------------------------------------------------------
-type abstract_code() :: [erl_parse:abstract_form()].
@@ -64,6 +69,7 @@
-type err_ret() :: 'error' | {'error', errors(), warnings()}.
-type comp_ret() :: mod_ret() | bin_ret() | err_ret().
+
%%----------------------------------------------------------------------
%%
@@ -143,6 +149,30 @@ noenv_output_generated(Opts) ->
env_compiler_options() -> env_default_opts().
+
+%%%
+%%% Run sub passes from a compiler pass.
+%%%
+
+-spec run_sub_passes([term()], term()) -> term().
+
+run_sub_passes(Ps, St) ->
+ case get(?SUB_PASS_TIMES) of
+ undefined ->
+ Runner = fun(_Name, Run, S) -> Run(S) end,
+ run_sub_passes_1(Ps, Runner, St);
+ Times when is_list(Times) ->
+ Runner = fun(Name, Run, S0) ->
+ T1 = erlang:monotonic_time(),
+ S = Run(S0),
+ T2 = erlang:monotonic_time(),
+ put(?SUB_PASS_TIMES,
+ [{Name,T2-T1}|get(?SUB_PASS_TIMES)]),
+ S
+ end,
+ run_sub_passes_1(Ps, Runner, St)
+ end.
+
%%
%% Local functions
%%
@@ -180,8 +210,11 @@ do_compile(Input, Opts0) ->
{error,Reason}
end
end,
- %% Dialyzer has already spawned workers.
- case lists:member(dialyzer, Opts) of
+ %% Some tools, like Dialyzer, has already spawned workers
+ %% and spawning extra workers actually slow the compilation
+ %% down instead of speeding it up, so we provide a mechanism
+ %% to bypass the compiler process.
+ case lists:member(no_spawn_compiler_process, Opts) of
true ->
IntFun();
false ->
@@ -218,23 +251,29 @@ expand_opt(report, Os) ->
[report_errors,report_warnings|Os];
expand_opt(return, Os) ->
[return_errors,return_warnings|Os];
+expand_opt(no_bsm3, Os) ->
+ %% The new bsm pass requires bsm3 instructions.
+ [no_bsm3,no_bsm_opt|Os];
expand_opt(r16, Os) ->
- [no_get_hd_tl,no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r17, Os) ->
- [no_get_hd_tl,no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r18, Os) ->
- [no_get_hd_tl,no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r19, Os) ->
- [no_get_hd_tl,no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
expand_opt(r20, Os) ->
- [no_get_hd_tl,no_record_opt,no_utf8_atoms|Os];
+ expand_opt_before_21(Os);
+expand_opt(r21, Os) ->
+ [no_put_tuple2 | expand_opt(no_bsm3, Os)];
expand_opt({debug_info_key,_}=O, Os) ->
[encrypt_debug_info,O|Os];
-expand_opt(no_float_opt, Os) ->
- %%Turn off the entire type optimization pass.
- [no_topt|Os];
expand_opt(O, Os) -> [O|Os].
+expand_opt_before_21(Os) ->
+ [no_put_tuple2, no_get_hd_tl, no_ssa_opt_record,
+ no_utf8_atoms | expand_opt(no_bsm3, Os)].
+
%% format_error(ErrorDescriptor) -> string()
-spec format_error(term()) -> iolist().
@@ -387,17 +426,57 @@ fold_comp([{Name,Pass}|Ps], Run, Code0, St0) ->
end;
fold_comp([], _Run, Code, St) -> {ok,Code,St}.
+run_sub_passes_1([{Name,Run}|Ps], Runner, St0)
+ when is_atom(Name), is_function(Run, 1) ->
+ try Runner(Name, Run, St0) of
+ St ->
+ run_sub_passes_1(Ps, Runner, St)
+ catch
+ C:E:Stk ->
+ io:format("Sub pass ~s\n", [Name]),
+ erlang:raise(C, E, Stk)
+ end;
+run_sub_passes_1([], _, St) -> St.
+
run_tc({Name,Fun}, Code, St) ->
+ put(?SUB_PASS_TIMES, []),
T1 = erlang:monotonic_time(),
Val = (catch Fun(Code, St)),
T2 = erlang:monotonic_time(),
- Elapsed = erlang:convert_time_unit(T2 - T1, native, millisecond),
+ Times = erase(?SUB_PASS_TIMES),
+ Elapsed = erlang:convert_time_unit(T2 - T1, native, microsecond),
Mem0 = erts_debug:flat_size(Val)*erlang:system_info(wordsize),
Mem = lists:flatten(io_lib:format("~.1f kB", [Mem0/1024])),
io:format(" ~-30s: ~10.3f s ~12s\n",
- [Name,Elapsed/1000,Mem]),
+ [Name,Elapsed/1000000,Mem]),
+ print_times(Times, Name),
Val.
+print_times(Times0, Name) ->
+ Fam0 = sofs:relation(Times0),
+ Fam1 = sofs:rel2fam(Fam0),
+ Fam2 = sofs:to_external(Fam1),
+ Fam3 = [{W,lists:sum(Times)} || {W,Times} <- Fam2],
+ Fam = reverse(lists:keysort(2, Fam3)),
+ Total = case lists:sum([T || {_,T} <- Fam]) of
+ 0 -> 1;
+ Total0 -> Total0
+ end,
+ case Fam of
+ [] ->
+ ok;
+ [_|_] ->
+ io:format(" %% Sub passes of ~s from slowest to fastest:\n", [Name]),
+ print_times_1(Fam, Total)
+ end.
+
+print_times_1([{Name,T}|Ts], Total) ->
+ Elapsed = erlang:convert_time_unit(T, native, microsecond),
+ io:format(" ~-27s: ~10.3f s ~3w %\n",
+ [Name,Elapsed/1000000,round(100*T/Total)]),
+ print_times_1(Ts, Total);
+print_times_1([], _Total) -> ok.
+
run_eprof({Name,Fun}, Code, Name, St) ->
io:format("~p: Running eprof\n", [Name]),
c:appcall(tools, eprof, start_profiling, [[self()]]),
@@ -741,8 +820,26 @@ kernel_passes() ->
?pass(v3_kernel),
{iff,dkern,{listing,"kernel"}},
{iff,'to_kernel',{done,"kernel"}},
- {pass,v3_codegen},
- {iff,dcg,{listing,"codegen"}}
+ {pass,beam_kernel_to_ssa},
+ {iff,dssa,{listing,"ssa"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_bsm_opt,{pass,beam_ssa_bsm}},
+ {iff,dssabsm,{listing,"ssabsm"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_fun_opt,{pass,beam_ssa_funs}},
+ {iff,dssafuns,{listing,"ssafuns"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_ssa_opt,{pass,beam_ssa_opt}},
+ {iff,dssaopt,{listing,"ssaopt"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {unless,no_recv_opt,{pass,beam_ssa_recv}},
+ {iff,drecv,{listing,"recv"}},
+ {pass,beam_ssa_pre_codegen},
+ {iff,dprecg,{listing,"precodegen"}},
+ {iff,ssalint,{pass,beam_ssa_lint}},
+ {pass,beam_ssa_codegen},
+ {iff,dcg,{listing,"codegen"}},
+ {iff,doldcg,{listing,"codegen"}}
| asm_passes()].
asm_passes() ->
@@ -751,34 +848,18 @@ asm_passes() ->
[{pass,beam_a},
{iff,da,{listing,"a"}},
{unless,no_postopt,
- [{unless,no_reorder,{pass,beam_reorder}},
- {iff,dre,{listing,"reorder"}},
- {pass,beam_block},
+ [{pass,beam_block},
{iff,dblk,{listing,"block"}},
{unless,no_except,{pass,beam_except}},
{iff,dexcept,{listing,"except"}},
{unless,no_bs_opt,{pass,beam_bs}},
{iff,dbs,{listing,"bs"}},
- {unless,no_topt,{pass,beam_type}},
- {iff,dtype,{listing,"type"}},
- {pass,beam_split},
- {iff,dsplit,{listing,"split"}},
- {unless,no_dead,{pass,beam_dead}},
- {iff,ddead,{listing,"dead"}},
{unless,no_jopt,{pass,beam_jump}},
{iff,djmp,{listing,"jump"}},
{unless,no_peep_opt,{pass,beam_peep}},
{iff,dpeep,{listing,"peep"}},
{pass,beam_clean},
{iff,dclean,{listing,"clean"}},
- {unless,no_bsm_opt,{pass,beam_bsm}},
- {iff,dbsm,{listing,"bsm"}},
- {unless,no_recv_opt,{pass,beam_receive}},
- {iff,drecv,{listing,"recv"}},
- {unless,no_record_opt,{pass,beam_record}},
- {iff,drecord,{listing,"record"}},
- {unless,no_blk2,?pass(block2)},
- {iff,dblk2,{listing,"block2"}},
{unless,no_stack_trimming,{pass,beam_trim}},
{iff,dtrim,{listing,"trim"}},
{pass,beam_flatten}]},
@@ -787,7 +868,9 @@ asm_passes() ->
%% need to do a few clean-ups to code.
{iff,no_postopt,[{pass,beam_clean}]},
+ {iff,diffable,?pass(diffable)},
{pass,beam_z},
+ {iff,diffable,{listing,"S"}},
{iff,dz,{listing,"z"}},
{iff,dopt,{listing,"optimize"}},
{iff,'S',{listing,"S"}},
@@ -931,11 +1014,17 @@ parse_module(_Code, St0) ->
end.
do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
+ SourceName0 = proplists:get_value(source, Opts, File),
+ SourceName = case member(deterministic, Opts) of
+ true -> filename:basename(SourceName0);
+ false -> SourceName0
+ end,
R = epp:parse_file(File,
- [{includes,[".",Dir|inc_paths(Opts)]},
- {macros,pre_defs(Opts)},
- {default_encoding,DefEncoding},
- extra]),
+ [{includes,[".",Dir|inc_paths(Opts)]},
+ {source_name, SourceName},
+ {macros,pre_defs(Opts)},
+ {default_encoding,DefEncoding},
+ extra]),
case R of
{ok,Forms,Extra} ->
Encoding = proplists:get_value(encoding, Extra),
@@ -1354,10 +1443,6 @@ v3_kernel(Code0, #compile{options=Opts,warnings=Ws0}=St) ->
{ok,Code,St}
end.
-block2(Code0, #compile{options=Opts}=St) ->
- {ok,Code} = beam_block:module(Code0, [no_blockify|Opts]),
- {ok,Code,St}.
-
test_old_inliner(#compile{options=Opts}) ->
%% The point of this test is to avoid loading the old inliner
%% if we know that it will not be used.
@@ -1432,16 +1517,30 @@ encrypt_debug_info(DebugInfo, Key, Opts) ->
end.
cleanup_compile_options(Opts) ->
- lists:filter(fun keep_compile_option/1, Opts).
-
+ IsDeterministic = lists:member(deterministic, Opts),
+ lists:filter(fun(Opt) ->
+ keep_compile_option(Opt, IsDeterministic)
+ end, Opts).
+
+%% Include paths and current directory don't affect compilation, but they might
+%% be helpful so we include them unless we're doing a deterministic build.
+keep_compile_option({i, _}, Deterministic) ->
+ not Deterministic;
+keep_compile_option({cwd, _}, Deterministic) ->
+ not Deterministic;
%% We are storing abstract, not asm or core.
-keep_compile_option(from_asm) -> false;
-keep_compile_option(from_core) -> false;
+keep_compile_option(from_asm, _Deterministic) ->
+ false;
+keep_compile_option(from_core, _Deterministic) ->
+ false;
%% Parse transform and macros have already been applied.
-keep_compile_option({parse_transform, _}) -> false;
-keep_compile_option({d, _, _}) -> false;
+keep_compile_option({parse_transform, _}, _Deterministic) ->
+ false;
+keep_compile_option({d, _, _}, _Deterministic) ->
+ false;
%% Do not affect compilation result on future calls.
-keep_compile_option(Option) -> effects_code_generation(Option).
+keep_compile_option(Option, _Deterministic) ->
+ effects_code_generation(Option).
start_crypto() ->
try crypto:start() of
@@ -1829,6 +1928,39 @@ restore_expand_module([F|Fs]) ->
[F|restore_expand_module(Fs)];
restore_expand_module([]) -> [].
+%%%
+%%% Transform the BEAM code to make it more friendly for
+%%% diffing: using function names instead of labels for
+%%% local calls and number labels relative to each function.
+%%%
+
+diffable(Code0, St) ->
+ {Mod,Exp,Attr,Fs0,NumLabels} = Code0,
+ EntryLabels0 = [{Entry,{Name,Arity}} ||
+ {function,Name,Arity,Entry,_} <- Fs0],
+ EntryLabels = maps:from_list(EntryLabels0),
+ Fs = [diffable_fix_function(F, EntryLabels) || F <- Fs0],
+ Code = {Mod,Exp,Attr,Fs,NumLabels},
+ {ok,Code,St}.
+
+diffable_fix_function({function,Name,Arity,Entry0,Is0}, LabelMap0) ->
+ Entry = maps:get(Entry0, LabelMap0),
+ {Is1,LabelMap} = diffable_label_map(Is0, 1, LabelMap0, []),
+ Fb = fun(Old) -> error({no_fb,Old}) end,
+ Is = beam_utils:replace_labels(Is1, [], LabelMap, Fb),
+ {function,Name,Arity,Entry,Is}.
+
+diffable_label_map([{label,Old}|Is], New, Map, Acc) ->
+ case Map of
+ #{Old:=NewLabel} ->
+ diffable_label_map(Is, New, Map, [{label,NewLabel}|Acc]);
+ #{} ->
+ diffable_label_map(Is, New+1, Map#{Old=>New}, [{label,New}|Acc])
+ end;
+diffable_label_map([I|Is], New, Map, Acc) ->
+ diffable_label_map(Is, New, Map, [I|Acc]);
+diffable_label_map([], _New, Map, Acc) ->
+ {Acc,Map}.
-spec options() -> 'ok'.
@@ -1950,21 +2082,24 @@ pre_load() ->
beam_asm,
beam_block,
beam_bs,
- beam_bsm,
beam_clean,
- beam_dead,
beam_dict,
beam_except,
beam_flatten,
beam_jump,
+ beam_kernel_to_ssa,
beam_opcodes,
beam_peep,
- beam_receive,
- beam_record,
- beam_reorder,
- beam_split,
+ beam_ssa,
+ beam_ssa_bsm,
+ beam_ssa_codegen,
+ beam_ssa_dead,
+ beam_ssa_funs,
+ beam_ssa_opt,
+ beam_ssa_pre_codegen,
+ beam_ssa_recv,
+ beam_ssa_type,
beam_trim,
- beam_type,
beam_utils,
beam_validator,
beam_z,
@@ -1983,7 +2118,6 @@ pre_load() ->
sys_core_bsm,
sys_core_dsetel,
sys_core_fold,
- v3_codegen,
v3_core,
v3_kernel],
_ = code:ensure_modules_loaded(L),
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index cf32fd251c..86259270bd 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -25,23 +25,28 @@
beam_asm,
beam_block,
beam_bs,
- beam_bsm,
beam_clean,
- beam_dead,
beam_dict,
beam_disasm,
beam_except,
beam_flatten,
beam_jump,
+ beam_kernel_to_ssa,
beam_listing,
beam_opcodes,
beam_peep,
- beam_receive,
- beam_reorder,
- beam_record,
- beam_split,
+ beam_ssa,
+ beam_ssa_bsm,
+ beam_ssa_codegen,
+ beam_ssa_dead,
+ beam_ssa_funs,
+ beam_ssa_lint,
+ beam_ssa_opt,
+ beam_ssa_pp,
+ beam_ssa_pre_codegen,
+ beam_ssa_recv,
+ beam_ssa_type,
beam_trim,
- beam_type,
beam_utils,
beam_validator,
beam_z,
@@ -65,7 +70,6 @@
sys_core_fold_lists,
sys_core_inline,
sys_pre_attributes,
- v3_codegen,
v3_core,
v3_kernel,
v3_kernel_pp
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index 71ab0e872a..ce9762899e 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -108,6 +108,7 @@ is_pure(erlang, list_to_atom, 1) -> true;
is_pure(erlang, list_to_binary, 1) -> true;
is_pure(erlang, list_to_float, 1) -> true;
is_pure(erlang, list_to_integer, 1) -> true;
+is_pure(erlang, list_to_integer, 2) -> true;
is_pure(erlang, list_to_pid, 1) -> true;
is_pure(erlang, list_to_tuple, 1) -> true;
is_pure(erlang, max, 2) -> true;
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index 02dead9e92..86590fad87 100755
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -142,8 +142,7 @@ BEAM_FORMAT_NUMBER=0
20: send/0
## @spec remove_message
-## @doc Unlink the current message from the message queue and store a
-## pointer to the message in x(0). Remove any timeout.
+## @doc Unlink the current message from the message queue. Remove any timeout.
21: remove_message/0
## @spec timeout
@@ -574,3 +573,26 @@ BEAM_FORMAT_NUMBER=0
## @doc Get the tail (or cdr) part of a list (a cons cell) from Source and
## put it into the register Tail.
163: get_tl/2
+
+# OTP 22
+
+## @spec put_tuple2 Destination Elements
+## @doc Build a tuple with the elements in the list Elements and put it
+## put into register Destination.
+164: put_tuple2/2
+
+## @spec bs_get_tail Ctx Dst Live
+## @doc Sets Dst to the tail of Ctx at the current position
+165: bs_get_tail/3
+
+## @spec bs_start_match3 Fail Bin Live Dst
+## @doc Starts a binary match sequence
+166: bs_start_match3/4
+
+## @spec bs_get_position Ctx Dst Live
+## @doc Sets Dst to the current position of Ctx
+167: bs_get_position/3
+
+## @spec bs_set_positon Ctx Pos
+## @doc Sets the current position of Ctx to Pos
+168: bs_set_position/2
diff --git a/lib/compiler/src/sys_core_bsm.erl b/lib/compiler/src/sys_core_bsm.erl
index d7b26c3a56..685e807e65 100644
--- a/lib/compiler/src/sys_core_bsm.erl
+++ b/lib/compiler/src/sys_core_bsm.erl
@@ -24,161 +24,52 @@
-export([module/2,format_error/1]).
-include("core_parse.hrl").
--import(lists, [member/2,reverse/1,usort/1]).
-spec module(cerl:c_module(), [compile:option()]) -> {'ok', cerl:c_module()}.
-module(#c_module{defs=Ds0}=Mod, Opts) ->
- {Ds,Ws0} = function(Ds0, [], []),
- case member(bin_opt_info, Opts) of
- false ->
- {ok,Mod#c_module{defs=Ds}};
- true ->
- Ws1 = [make_warning(Where, What) || {Where,What} <- Ws0],
- Ws = usort(Ws1),
- {ok,Mod#c_module{defs=Ds},Ws}
- end.
+module(#c_module{defs=Ds}=Mod, _Opts) ->
+ {ok,Mod#c_module{defs=function(Ds)}}.
-function([{#c_var{name={F,Arity}}=Name,B0}|Fs], FsAcc, Ws0) ->
- try cerl_trees:mapfold(fun bsm_an/2, Ws0, B0) of
- {B,Ws} ->
- function(Fs, [{Name,B}|FsAcc], Ws)
+function([{#c_var{name={F,Arity}}=Name,B0}|Fs]) ->
+ try cerl_trees:map(fun bsm_reorder/1, B0) of
+ B -> [{Name,B} | function(Fs)]
catch
Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [F,Arity]),
- erlang:raise(Class, Error, Stack)
+ io:fwrite("Function: ~w/~w\n", [F,Arity]),
+ erlang:raise(Class, Error, Stack)
end;
-function([], Fs, Ws) ->
- {reverse(Fs),Ws}.
+function([]) ->
+ [].
-type error() :: atom().
-spec format_error(error()) -> nonempty_string().
-format_error(bin_opt_alias) ->
- "INFO: the '=' operator will prevent delayed sub binary optimization";
-format_error(bin_partition) ->
- "INFO: matching non-variables after a previous clause matching a variable "
- "will prevent delayed sub binary optimization";
-format_error(bin_var_used) ->
- "INFO: using a matched out sub binary will prevent "
- "delayed sub binary optimization";
-format_error(orig_bin_var_used_in_guard) ->
- "INFO: using the original binary variable in a guard will prevent "
- "delayed sub binary optimization";
-format_error(bin_var_used_in_guard) ->
- "INFO: using a matched out sub binary in a guard will prevent "
- "delayed sub binary optimization".
-
+format_error(_) -> error(badarg).
-%%%
-%%% Annotate bit syntax matching to faciliate optimization in further passes.
-%%%
+%%% Reorder bit syntax matching to faciliate optimization in further passes.
-bsm_an(Core0, Ws0) ->
- case bsm_an(Core0) of
- {ok,Core} ->
- {Core,Ws0};
- {ok,Core,W} ->
- {Core,[W|Ws0]}
- end.
+bsm_reorder(#c_case{arg=#c_var{}=V}=Case) ->
+ bsm_reorder_1([V], Case);
+bsm_reorder(#c_case{arg=#c_values{es=Es}}=Case) ->
+ bsm_reorder_1(Es, Case);
+bsm_reorder(Core) ->
+ Core.
-bsm_an(#c_case{arg=#c_var{}=V}=Case) ->
- bsm_an_1([V], Case);
-bsm_an(#c_case{arg=#c_values{es=Es}}=Case) ->
- bsm_an_1(Es, Case);
-bsm_an(Other) ->
- {ok,Other}.
-
-bsm_an_1(Vs0, #c_case{clauses=Cs0}=Case) ->
+bsm_reorder_1(Vs0, #c_case{clauses=Cs0}=Case) ->
case bsm_leftmost(Cs0) of
- none ->
- {ok,Case};
- 1 ->
- bsm_an_2(Vs0, Cs0, Case);
- Pos ->
- Vs = move_from_col(Pos, Vs0),
- Cs = [C#c_clause{pats=move_from_col(Pos, Ps)} ||
- #c_clause{pats=Ps}=C <- Cs0],
- bsm_an_2(Vs, Cs, Case)
- end.
-
-bsm_an_2(Vs, Cs, Case) ->
- try
- bsm_ensure_no_partition(Cs),
- {ok,bsm_do_an(Vs, Cs, Case)}
- catch
- throw:{problem,Where,What} ->
- {ok,Case,{Where,What}}
+ Pos when Pos > 0, Pos =/= none ->
+ Vs = core_lib:make_values(move_from_col(Pos, Vs0)),
+ Cs = [C#c_clause{pats=move_from_col(Pos, Ps)}
+ || #c_clause{pats=Ps}=C <- Cs0],
+ Case#c_case{arg=Vs,clauses=Cs};
+ _ ->
+ Case
end.
move_from_col(Pos, L) ->
{First,[Col|Rest]} = lists:split(Pos - 1, L),
[Col|First] ++ Rest.
-bsm_do_an([#c_var{name=Vname}=V0|Vs0], Cs0, Case) ->
- Cs = bsm_do_an_var(Vname, Cs0),
- V = bsm_annotate_for_reuse(V0),
- Vs = core_lib:make_values([V|Vs0]),
- Case#c_case{arg=Vs,clauses=Cs};
-bsm_do_an(_Vs, _Cs, Case) -> Case.
-
-bsm_do_an_var(V, [#c_clause{pats=[P|_],guard=G,body=B0}=C0|Cs]) ->
- case P of
- #c_var{name=VarName} ->
- case core_lib:is_var_used(V, G) of
- true -> bsm_problem(C0, orig_bin_var_used_in_guard);
- false -> ok
- end,
- case core_lib:is_var_used(VarName, G) of
- true -> bsm_problem(C0, bin_var_used_in_guard);
- false -> ok
- end,
- B1 = bsm_maybe_ctx_to_binary(VarName, B0),
- B = bsm_maybe_ctx_to_binary(V, B1),
- C = C0#c_clause{body=B},
- [C|bsm_do_an_var(V, Cs)];
- #c_alias{} ->
- case bsm_could_match_binary(P) of
- false ->
- [C0|bsm_do_an_var(V, Cs)];
- true ->
- bsm_problem(C0, bin_opt_alias)
- end;
- _ ->
- case bsm_could_match_binary(P) andalso bsm_is_var_used(V, G, B0) of
- false ->
- [C0|bsm_do_an_var(V, Cs)];
- true ->
- bsm_problem(C0, bin_var_used)
- end
- end;
-bsm_do_an_var(_, []) -> [].
-
-bsm_annotate_for_reuse(#c_var{anno=Anno}=Var) ->
- Var#c_var{anno=[reuse_for_context|Anno]}.
-
-bsm_is_var_used(V, G, B) ->
- core_lib:is_var_used(V, G) orelse core_lib:is_var_used(V, B).
-
-bsm_maybe_ctx_to_binary(V, B) ->
- case core_lib:is_var_used(V, B) andalso not previous_ctx_to_binary(V, B) of
- false ->
- B;
- true ->
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]},
- body=B}
- end.
-
-previous_ctx_to_binary(V, Core) ->
- case Core of
- #c_seq{arg=#c_primop{name=#c_literal{val=bs_context_to_binary},
- args=[#c_var{name=V}]}} ->
- true;
- _ ->
- false
- end.
-
%% bsm_leftmost(Cs) -> none | ArgumentNumber
%% Find the leftmost argument that matches a nonempty binary.
%% Return either 'none' or the argument number (1-N).
@@ -200,94 +91,3 @@ bsm_leftmost_2([_|Ps], Cs, N, Pos) ->
bsm_leftmost_2(Ps, Cs, N+1, Pos);
bsm_leftmost_2([], Cs, _, Pos) ->
bsm_leftmost_1(Cs, Pos).
-
-%% bsm_ensure_no_partition(Cs) -> ok (exception if problem)
-%% There must only be a single bs_start_match2 instruction if we
-%% are to reuse the binary variable for the match context.
-%%
-%% To make sure that there is only a single bs_start_match2
-%% instruction, we will check for partitions such as:
-%%
-%% foo(<<...>>) -> ...
-%% foo(<Variable>) when ... -> ...
-%% foo(<Non-variable pattern>) ->
-%%
-%% If there is such partition, we reject the optimization.
-
-bsm_ensure_no_partition(Cs) ->
- bsm_ensure_no_partition_1(Cs, before).
-
-%% Loop through each clause.
-bsm_ensure_no_partition_1([#c_clause{pats=Ps,guard=G}|Cs], State0) ->
- State = bsm_ensure_no_partition_2(Ps, G, State0),
- case State of
- 'after' ->
- bsm_ensure_no_partition_after(Cs);
- _ ->
- ok
- end,
- bsm_ensure_no_partition_1(Cs, State);
-bsm_ensure_no_partition_1([], _) -> ok.
-
-bsm_ensure_no_partition_2([#c_binary{}|_], _, _State) ->
- within;
-bsm_ensure_no_partition_2([#c_alias{}=Alias|_], N, State) ->
- %% Retrieve the real pattern that the alias refers to and check that.
- P = bsm_real_pattern(Alias),
- bsm_ensure_no_partition_2([P], N, State);
-bsm_ensure_no_partition_2([_|_], _, before=State) ->
- %% No binary matching yet - therefore no partition.
- State;
-bsm_ensure_no_partition_2([P|_], _, State) ->
- case bsm_could_match_binary(P) of
- false ->
- State;
- true ->
- %% The pattern P *may* match a binary, so we must update the state.
- %% (P must be a variable.)
- 'after'
- end.
-
-bsm_ensure_no_partition_after([#c_clause{pats=Ps}=C|Cs]) ->
- case Ps of
- [#c_var{}|_] ->
- bsm_ensure_no_partition_after(Cs);
- _ ->
- bsm_problem(C, bin_partition)
- end;
-bsm_ensure_no_partition_after([]) -> ok.
-
-bsm_could_match_binary(#c_alias{pat=P}) -> bsm_could_match_binary(P);
-bsm_could_match_binary(#c_cons{}) -> false;
-bsm_could_match_binary(#c_tuple{}) -> false;
-bsm_could_match_binary(#c_literal{val=Lit}) -> is_bitstring(Lit);
-bsm_could_match_binary(_) -> true.
-
-bsm_real_pattern(#c_alias{pat=P}) -> bsm_real_pattern(P);
-bsm_real_pattern(P) -> P.
-
-bsm_problem(Where, What) ->
- throw({problem,Where,What}).
-
-make_warning(Core, Term) ->
- case should_suppress_warning(Core) of
- true ->
- ok;
- false ->
- Anno = cerl:get_ann(Core),
- Line = get_line(Anno),
- File = get_file(Anno),
- {File,[{Line,?MODULE,Term}]}
- end.
-
-should_suppress_warning(Core) ->
- Ann = cerl:get_ann(Core),
- member(compiler_generated, Ann).
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|T]) -> get_line(T);
-get_line([]) -> none.
-
-get_file([{file,File}|_]) -> File;
-get_file([_|T]) -> get_file(T);
-get_file([]) -> "no_file". % should not happen
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 0aa58a46e4..d848cd8f19 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -115,13 +115,6 @@ module(#c_module{defs=Ds0}=Mod, Opts) ->
{ok,Mod#c_module{defs=Ds1},get_warnings()}.
function_1({#c_var{name={F,Arity}}=Name,B0}) ->
- %% Find a suitable starting value for the variable counter. Note
- %% that this pass assumes that new_var_name/1 returns a variable
- %% name distinct from any variable used in the entire body of
- %% the function. We use integers as variable names to avoid
- %% filling up the atom table when compiling huge functions.
- Count = cerl_trees:next_free_variable_name(B0),
- put(new_var_num, Count),
try
%% Find a suitable starting value for the variable
%% counter. Note that this pass assumes that new_var_name/1
@@ -352,7 +345,12 @@ expr(#c_letrec{body=#c_var{}}=Letrec, effect, _Sub) ->
void();
expr(#c_letrec{defs=Fs0,body=B0}=Letrec, Ctxt, Sub) ->
Fs1 = map(fun ({Name,Fb}) ->
- {Name,expr(Fb, {letrec,Ctxt}, Sub)}
+ case Ctxt =:= effect andalso is_fun_effect_safe(Name, B0) of
+ true ->
+ {Name,expr(Fb, {letrec, effect}, Sub)};
+ false ->
+ {Name,expr(Fb, {letrec, value}, Sub)}
+ end
end, Fs0),
B1 = body(B0, Ctxt, Sub),
Letrec#c_letrec{defs=Fs1,body=B1};
@@ -480,9 +478,101 @@ expr(#c_try{anno=A,arg=E0,vars=Vs0,body=B0,evars=Evs0,handler=H0}=Try, _, Sub0)
false ->
{Evs1,Sub2} = var_list(Evs0, Sub0),
H1 = body(H0, value, Sub2),
- Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H1}
+ H2 = opt_try_handler(H1, lists:last(Evs1)),
+ Try#c_try{arg=E1,vars=Vs1,body=B1,evars=Evs1,handler=H2}
end.
+%% Attempts to convert old erlang:get_stacktrace/0 calls into the new
+%% three-argument catch, with possibility of further optimisations.
+opt_try_handler(#c_call{anno=A,module=#c_literal{val=erlang},name=#c_literal{val=get_stacktrace},args=[]}, Var) ->
+ #c_primop{anno=A,name=#c_literal{val=build_stacktrace},args=[Var]};
+opt_try_handler(#c_case{clauses=Cs0} = Case, Var) ->
+ Cs = [C#c_clause{body=opt_try_handler(B, Var)} || #c_clause{body=B} = C <- Cs0],
+ Case#c_case{clauses=Cs};
+opt_try_handler(#c_let{arg=Arg} = Let, Var) ->
+ Let#c_let{arg=opt_try_handler(Arg, Var)};
+opt_try_handler(X, _) -> X.
+
+%% If a fun or its application is used as an argument, then it's unsafe to
+%% handle it in effect context as the side-effects may rely on its return
+%% value. The following is a minimal example of where it can go wrong:
+%%
+%% do letrec 'f'/0 = fun () -> ... whatever ...
+%% in call 'side':'effect'(apply 'f'/0())
+%% 'ok'
+%%
+%% This function returns 'true' if Body definitely does not rely on a
+%% value produced by FVar, or 'false' if Body depends on or might depend on
+%% a value produced by FVar.
+
+is_fun_effect_safe(#c_var{}=FVar, Body) ->
+ ifes_1(FVar, Body, true).
+
+ifes_1(FVar, #c_alias{pat=Pat}, _Safe) ->
+ ifes_1(FVar, Pat, false);
+ifes_1(FVar, #c_apply{op=Op,args=Args}, Safe) ->
+ %% FVar(...) is safe as long its return value is ignored, but it's never
+ %% okay to pass FVar as an argument.
+ ifes_list(FVar, Args, false) andalso ifes_1(FVar, Op, Safe);
+ifes_1(FVar, #c_binary{segments=Segments}, _Safe) ->
+ ifes_list(FVar, Segments, false);
+ifes_1(FVar, #c_bitstr{val=Val,size=Size,unit=Unit}, _Safe) ->
+ ifes_list(FVar, [Val, Size, Unit], false);
+ifes_1(FVar, #c_call{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_case{arg=Arg,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_catch{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_clause{pats=Pats,guard=Guard,body=Body}, Safe) ->
+ ifes_list(FVar, Pats, false) andalso
+ ifes_1(FVar, Guard, false) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_cons{hd=Hd,tl=Tl}, _Safe) ->
+ ifes_1(FVar, Hd, false) andalso ifes_1(FVar, Tl, false);
+ifes_1(FVar, #c_fun{body=Body}, _Safe) ->
+ ifes_1(FVar, Body, false);
+ifes_1(FVar, #c_let{arg=Arg,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_letrec{defs=Defs,body=Body}, Safe) ->
+ Funs = [Fun || {_,Fun} <- Defs],
+ ifes_list(FVar, Funs, false) andalso ifes_1(FVar, Body, Safe);
+ifes_1(_FVar, #c_literal{}, _Safe) ->
+ true;
+ifes_1(FVar, #c_map{arg=Arg,es=Elements}, _Safe) ->
+ ifes_1(FVar, Arg, false) andalso ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_map_pair{key=Key,val=Val}, _Safe) ->
+ ifes_1(FVar, Key, false) andalso ifes_1(FVar, Val, false);
+ifes_1(FVar, #c_primop{args=Args}, _Safe) ->
+ ifes_list(FVar, Args, false);
+ifes_1(FVar, #c_receive{timeout=Timeout,action=Action,clauses=Clauses}, Safe) ->
+ ifes_1(FVar, Timeout, false) andalso
+ ifes_1(FVar, Action, Safe) andalso
+ ifes_list(FVar, Clauses, Safe);
+ifes_1(FVar, #c_seq{arg=Arg,body=Body}, Safe) ->
+ %% Arg of a #c_seq{} has no effect so it's okay to use FVar there even if
+ %% Safe=false.
+ ifes_1(FVar, Arg, true) andalso ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_try{arg=Arg,handler=Handler,body=Body}, Safe) ->
+ ifes_1(FVar, Arg, false) andalso
+ ifes_1(FVar, Handler, Safe) andalso
+ ifes_1(FVar, Body, Safe);
+ifes_1(FVar, #c_tuple{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(FVar, #c_values{es=Elements}, _Safe) ->
+ ifes_list(FVar, Elements, false);
+ifes_1(#c_var{name=Name}, #c_var{name=Name}, Safe) ->
+ %% It's safe to return FVar if it's unused.
+ Safe;
+ifes_1(_FVar, #c_var{}, _Safe) ->
+ true.
+
+ifes_list(FVar, [E|Es], Safe) ->
+ ifes_1(FVar, E, Safe) andalso ifes_list(FVar, Es, Safe);
+ifes_list(_FVar, [], _Safe) ->
+ true.
+
+
expr_list(Es, Ctxt, Sub) ->
[expr(E, Ctxt, Sub) || E <- Es].
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
deleted file mode 100644
index 6cd114abf7..0000000000
--- a/lib/compiler/src/v3_codegen.erl
+++ /dev/null
@@ -1,2930 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-%% Purpose : Code generator for Beam.
-
--module(v3_codegen).
-
-%% The main interface.
--export([module/2]).
-
--import(lists, [member/2,keymember/3,keysort/2,keydelete/3,
- append/1,flatmap/2,filter/2,foldl/3,foldr/3,mapfoldl/3,
- sort/1,reverse/1,reverse/2,map/2]).
--import(ordsets, [add_element/2,intersection/2,union/2]).
-
--include("v3_kernel.hrl").
-
-%% These are not defined in v3_kernel.hrl.
-get_kanno(Kthing) -> element(2, Kthing).
-set_kanno(Kthing, Anno) -> setelement(2, Kthing, Anno).
-
-%% Main codegen structure.
--record(cg, {lcount=1, %Label counter
- bfail, %Fail label for BIFs
- break, %Break label
- recv, %Receive label
- is_top_block, %Boolean: top block or not
- functable=#{}, %Map of local functions: {Name,Arity}=>Label
- in_catch=false, %Inside a catch or not.
- need_frame, %Need a stack frame.
- ultimate_failure, %Label for ultimate match failure.
- ctx %Match context.
- }).
-
-%% Stack/register state record.
--record(sr, {reg=[], %Register table
- stk=[], %Stack table
- res=[]}). %Registers to reserve
-
-%% Internal records.
--record(cg_need_heap, {anno=[] :: term(),
- h=0 :: integer()}).
--record(cg_block, {anno=[] :: term(),
- es=[] :: [term()]}).
-
--type vdb_entry() :: {atom(),non_neg_integer(),non_neg_integer()}.
-
--record(l, {i=0 :: non_neg_integer(), %Op number
- vdb=[] :: [vdb_entry()], %Variable database
- a=[] :: [term()]}). %Core annotation
-
--spec module(#k_mdef{}, [compile:option()]) -> {'ok',beam_asm:module_code()}.
-
-module(#k_mdef{name=Mod,exports=Es,attributes=Attr,body=Forms}, _Opts) ->
- {Asm,St} = functions(Forms, {atom,Mod}),
- {ok,{Mod,Es,Attr,Asm,St#cg.lcount}}.
-
-functions(Forms, AtomMod) ->
- mapfoldl(fun (F, St) -> function(F, AtomMod, St) end, #cg{lcount=1}, Forms).
-
-function(#k_fdef{anno=#k{a=Anno},func=Name,arity=Arity,
- vars=As,body=Kb}, AtomMod, St0) ->
- try
- #k_match{} = Kb, %Assertion.
-
- %% Try to suppress the stack frame unless it is
- %% really needed.
- Body0 = avoid_stack_frame(Kb),
-
- %% Annotate kernel records with variable usage.
- Vdb0 = init_vars(As),
- {Body,_,Vdb} = body(Body0, 1, Vdb0),
-
- %% Generate the BEAM assembly code.
- {Asm,EntryLabel,St} = cg_fun(Body, As, Vdb, AtomMod,
- {Name,Arity}, Anno, St0),
- Func = {function,Name,Arity,EntryLabel,Asm},
- {Func,St}
- catch
- Class:Error:Stack ->
- io:fwrite("Function: ~w/~w\n", [Name,Arity]),
- erlang:raise(Class, Error, Stack)
- end.
-
-
-%% avoid_stack_frame(Kernel) -> Kernel'
-%% If possible, avoid setting up a stack frame. Functions
-%% that only do matching, calls to guard BIFs, and tail-recursive
-%% calls don't need a stack frame.
-
-avoid_stack_frame(#k_match{body=Body}=M) ->
- try
- M#k_match{body=avoid_stack_frame_1(Body)}
- catch
- impossible ->
- M
- end.
-
-avoid_stack_frame_1(#k_alt{first=First0,then=Then0}=Alt) ->
- First = avoid_stack_frame_1(First0),
- Then = avoid_stack_frame_1(Then0),
- Alt#k_alt{first=First,then=Then};
-avoid_stack_frame_1(#k_bif{op=Op}=Bif) ->
- case Op of
- #k_internal{} ->
- %% Most internal BIFs clobber the X registers.
- throw(impossible);
- _ ->
- Bif
- end;
-avoid_stack_frame_1(#k_break{anno=Anno,args=Args}) ->
- #k_guard_break{anno=Anno,args=Args};
-avoid_stack_frame_1(#k_guard_break{}=Break) ->
- Break;
-avoid_stack_frame_1(#k_enter{}=Enter) ->
- %% Tail-recursive calls don't need a stack frame.
- Enter;
-avoid_stack_frame_1(#k_guard{clauses=Cs0}=Guard) ->
- Cs = avoid_stack_frame_list(Cs0),
- Guard#k_guard{clauses=Cs};
-avoid_stack_frame_1(#k_guard_clause{guard=G0,body=B0}=C) ->
- G = avoid_stack_frame_1(G0),
- B = avoid_stack_frame_1(B0),
- C#k_guard_clause{guard=G,body=B};
-avoid_stack_frame_1(#k_match{anno=A,vars=Vs,body=B0,ret=Ret}) ->
- %% Use #k_guard_match{} instead to avoid saving the X registers
- %% to the stack before matching.
- B = avoid_stack_frame_1(B0),
- #k_guard_match{anno=A,vars=Vs,body=B,ret=Ret};
-avoid_stack_frame_1(#k_guard_match{body=B0}=M) ->
- B = avoid_stack_frame_1(B0),
- M#k_guard_match{body=B};
-avoid_stack_frame_1(#k_protected{arg=Arg0}=Prot) ->
- Arg = avoid_stack_frame_1(Arg0),
- Prot#k_protected{arg=Arg};
-avoid_stack_frame_1(#k_put{}=Put) ->
- Put;
-avoid_stack_frame_1(#k_return{}=Ret) ->
- Ret;
-avoid_stack_frame_1(#k_select{var=#k_var{anno=Vanno},types=Types0}=Select) ->
- case member(reuse_for_context, Vanno) of
- false ->
- Types = avoid_stack_frame_list(Types0),
- Select#k_select{types=Types};
- true ->
- %% Including binary patterns that overwrite the register containing
- %% the binary with the match context may not be safe. For example,
- %% bs_match_SUITE:bin_tail_e/1 with inlining will be rejected by
- %% beam_validator.
- %%
- %% Essentially the following code is produced:
- %%
- %% bs_match {x,0} => {x,0}
- %% ...
- %% bs_match {x,0} => {x,1} %% ILLEGAL
- %%
- %% A bs_match instruction will only accept a match context as the
- %% source operand if the source and destination registers are the
- %% the same (as in the first bs_match instruction above).
- %% The second bs_match instruction is therefore illegal.
- %%
- %% This situation is avoided if there is a stack frame:
- %%
- %% move {x,0} => {y,0}
- %% bs_match {x,0} => {x,0}
- %% ...
- %% bs_match {y,0} => {x,1} %% LEGAL
- %%
- throw(impossible)
- end;
-avoid_stack_frame_1(#k_seq{arg=#k_call{anno=Anno,op=Op}=Call,
- body=#k_break{args=BrArgs0}}=Seq) ->
- case Op of
- #k_remote{mod=#k_atom{val=Mod},
- name=#k_atom{val=Name},
- arity=Arity} ->
- case erl_bifs:is_exit_bif(Mod, Name, Arity) of
- false ->
- %% Will clobber X registers. Must have a stack frame.
- throw(impossible);
- true ->
- %% The call to this BIF will never return. It is safe
- %% to suppress the stack frame.
- Bif = #k_bif{anno=Anno,
- op=#k_internal{name=guard_error,arity=1},
- args=[Call],ret=[]},
- BrArgs = lists:duplicate(length(BrArgs0), #k_nil{}),
- GB = #k_guard_break{anno=#k{us=[],ns=[],a=[]},args=BrArgs},
- Seq#k_seq{arg=Bif,body=GB}
- end;
- _ ->
- %% Will clobber X registers. Must have a stack frame.
- throw(impossible)
- end;
-avoid_stack_frame_1(#k_seq{arg=A0,body=B0}=Seq) ->
- A = avoid_stack_frame_1(A0),
- B = avoid_stack_frame_1(B0),
- Seq#k_seq{arg=A,body=B};
-avoid_stack_frame_1(#k_test{}=Test) ->
- Test;
-avoid_stack_frame_1(#k_type_clause{values=Values0}=TC) ->
- Values = avoid_stack_frame_list(Values0),
- TC#k_type_clause{values=Values};
-avoid_stack_frame_1(#k_val_clause{body=B0}=VC) ->
- B = avoid_stack_frame_1(B0),
- VC#k_val_clause{body=B};
-avoid_stack_frame_1(_Body) ->
- throw(impossible).
-
-avoid_stack_frame_list([H|T]) ->
- [avoid_stack_frame_1(H)|avoid_stack_frame_list(T)];
-avoid_stack_frame_list([]) -> [].
-
-
-%% This pass creates beam format annotated with variable lifetime
-%% information. Each thing is given an index and for each variable we
-%% store the first and last index for its occurrence. The variable
-%% database, VDB, attached to each thing is only relevant internally
-%% for that thing.
-%%
-%% For nested things like matches the numbering continues locally and
-%% the VDB for that thing refers to the variable usage within that
-%% thing. Variables which live through a such a thing are internally
-%% given a very large last index. Internally the indexes continue
-%% after the index of that thing. This creates no problems as the
-%% internal variable info never escapes and externally we only see
-%% variable which are alive both before or after.
-%%
-%% This means that variables never "escape" from a thing and the only
-%% way to get values from a thing is to "return" them, with 'break' or
-%% 'return'. Externally these values become the return values of the
-%% thing. This is no real limitation as most nested things have
-%% multiple threads so working out a common best variable usage is
-%% difficult.
-
-%% body(Kbody, I, Vdb) -> {[Expr],MaxI,Vdb}.
-%% Handle a body.
-
-body(#k_seq{arg=Ke,body=Kb}, I, Vdb0) ->
- %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]),
- A = get_kanno(Ke),
- Vdb1 = use_vars(union(A#k.us, A#k.ns), I, Vdb0),
- {Es,MaxI,Vdb2} = body(Kb, I+1, Vdb1),
- E = expr(Ke, I, Vdb2),
- {[E|Es],MaxI,Vdb2};
-body(Ke, I, Vdb0) ->
- %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]),
- A = get_kanno(Ke),
- Vdb1 = use_vars(union(A#k.us, A#k.ns), I, Vdb0),
- E = expr(Ke, I, Vdb1),
- {[E],I,Vdb1}.
-
-%% expr(Kexpr, I, Vdb) -> Expr.
-
-expr(#k_test{anno=A}=Test, I, _Vdb) ->
- Test#k_test{anno=#l{i=I,a=A#k.a}};
-expr(#k_call{anno=A}=Call, I, _Vdb) ->
- Call#k_call{anno=#l{i=I,a=A#k.a}};
-expr(#k_enter{anno=A}=Enter, I, _Vdb) ->
- Enter#k_enter{anno=#l{i=I,a=A#k.a}};
-expr(#k_bif{anno=A}=Bif, I, _Vdb) ->
- Bif#k_bif{anno=#l{i=I,a=A#k.a}};
-expr(#k_match{anno=A,body=Kb,ret=Rs}, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Mdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, A#k.us, I+1, Mdb),
- L = #l{i=I,vdb=use_vars(A#k.us, I+1, Mdb),a=A#k.a},
- #k_match{anno=L,body=M,ret=Rs};
-expr(#k_guard_match{anno=A,body=Kb,ret=Rs}, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Mdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, A#k.us, I+1, Mdb),
- L = #l{i=I,vdb=use_vars(A#k.us, I+1, Mdb),a=A#k.a},
- #k_guard_match{anno=L,body=M,ret=Rs};
-expr(#k_protected{}=Protected, I, Vdb) ->
- protected(Protected, I, Vdb);
-expr(#k_try{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh}=Try, I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the try.
- Tdb0 = vdb_sub(I, I+1, Vdb),
- %% This is the tricky bit. Lock variables in Arg that are used in
- %% the body and handler. Add try tag 'variable'.
- Ab = get_kanno(Kb),
- Ah = get_kanno(Kh),
- Tdb1 = use_vars(union(Ab#k.us, Ah#k.us), I+3, Tdb0),
- Tdb2 = vdb_sub(I, I+2, Tdb1),
- Vnames = fun (Kvar) -> Kvar#k_var.name end, %Get the variable names
- {Aes,_,Adb} = body(Ka, I+2, add_var({catch_tag,I+1}, I+1, locked, Tdb2)),
- {Bes,_,Bdb} = body(Kb, I+4, new_vars(sort(map(Vnames, Vs)), I+3, Tdb2)),
- {Hes,_,Hdb} = body(Kh, I+4, new_vars(sort(map(Vnames, Evs)), I+3, Tdb2)),
- L = #l{i=I,vdb=Tdb1,a=A#k.a},
- Try#k_try{anno=L,
- arg=#cg_block{es=Aes,anno=#l{i=I+1,vdb=Adb,a=[]}},
- vars=Vs,body=#cg_block{es=Bes,anno=#l{i=I+3,vdb=Bdb,a=[]}},
- evars=Evs,handler=#cg_block{es=Hes,anno=#l{i=I+3,vdb=Hdb,a=[]}}};
-expr(#k_try_enter{anno=A,arg=Ka,vars=Vs,body=Kb,evars=Evs,handler=Kh}, I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the try.
- Tdb0 = vdb_sub(I, I+1, Vdb),
- %% This is the tricky bit. Lock variables in Arg that are used in
- %% the body and handler. Add try tag 'variable'.
- Ab = get_kanno(Kb),
- Ah = get_kanno(Kh),
- Tdb1 = use_vars(union(Ab#k.us, Ah#k.us), I+3, Tdb0),
- Tdb2 = vdb_sub(I, I+2, Tdb1),
- Vnames = fun (Kvar) -> Kvar#k_var.name end, %Get the variable names
- {Aes,_,Adb} = body(Ka, I+2, add_var({catch_tag,I+1}, I+1, 1000000, Tdb2)),
- {Bes,_,Bdb} = body(Kb, I+4, new_vars(sort(map(Vnames, Vs)), I+3, Tdb2)),
- {Hes,_,Hdb} = body(Kh, I+4, new_vars(sort(map(Vnames, Evs)), I+3, Tdb2)),
- L = #l{i=I,vdb=Tdb1,a=A#k.a},
- #k_try_enter{anno=L,
- arg=#cg_block{es=Aes,anno=#l{i=I+1,vdb=Adb,a=[]}},
- vars=Vs,body=#cg_block{es=Bes,anno=#l{i=I+3,vdb=Bdb,a=[]}},
- evars=Evs,handler=#cg_block{es=Hes,anno=#l{i=I+3,vdb=Hdb,a=[]}}};
-expr(#k_catch{anno=A,body=Kb}=Catch, I, Vdb) ->
- %% Lock variables that are alive before the catch and used afterwards.
- %% Don't lock variables that are only used inside the catch.
- %% Add catch tag 'variable'.
- Cdb0 = vdb_sub(I, I+1, Vdb),
- {Es,_,Cdb1} = body(Kb, I+1, add_var({catch_tag,I}, I, locked, Cdb0)),
- L = #l{i=I,vdb=Cdb1,a=A#k.a},
- Catch#k_catch{anno=L,body=#cg_block{es=Es}};
-expr(#k_receive{anno=A,var=V,body=Kb,action=Ka}=Recv, I, Vdb) ->
- %% Work out imported variables which need to be locked.
- Rdb = vdb_sub(I, I+1, Vdb),
- M = match(Kb, add_element(V#k_var.name, A#k.us), I+1,
- new_vars([V#k_var.name], I, Rdb)),
- {Tes,_,Adb} = body(Ka, I+1, Rdb),
- Le = #l{i=I,vdb=use_vars(A#k.us, I+1, Vdb),a=A#k.a},
- Recv#k_receive{anno=Le,body=M,
- action=#cg_block{anno=#l{i=I+1,vdb=Adb,a=[]},es=Tes}};
-expr(#k_receive_accept{anno=A}, I, _Vdb) ->
- #k_receive_accept{anno=#l{i=I,a=A#k.a}};
-expr(#k_receive_next{anno=A}, I, _Vdb) ->
- #k_receive_next{anno=#l{i=I,a=A#k.a}};
-expr(#k_put{anno=A}=Put, I, _Vdb) ->
- Put#k_put{anno=#l{i=I,a=A#k.a}};
-expr(#k_break{anno=A}=Break, I, _Vdb) ->
- Break#k_break{anno=#l{i=I,a=A#k.a}};
-expr(#k_guard_break{anno=A}=Break, I, _Vdb) ->
- Break#k_guard_break{anno=#l{i=I,a=A#k.a}};
-expr(#k_return{anno=A}=Ret, I, _Vdb) ->
- Ret#k_return{anno=#l{i=I,a=A#k.a}}.
-
-%% protected(Kprotected, I, Vdb) -> Protected.
-%% Only used in guards.
-
-protected(#k_protected{anno=A,arg=Ts}=Prot, I, Vdb) ->
- %% Lock variables that are alive before try and used afterwards.
- %% Don't lock variables that are only used inside the protected
- %% expression.
- Pdb0 = vdb_sub(I, I+1, Vdb),
- {T,MaxI,Pdb1} = body(Ts, I+1, Pdb0),
- Pdb2 = use_vars(A#k.ns, MaxI+1, Pdb1), %Save "return" values
- Prot#k_protected{arg=T,anno=#l{i=I,a=A#k.a,vdb=Pdb2}}.
-
-%% match(Kexpr, [LockVar], I, Vdb) -> Expr.
-%% Convert match tree to old format.
-
-match(#k_alt{anno=A,first=Kf,then=Kt}, Ls, I, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I, Vdb0),
- F = match(Kf, Ls, I+1, Vdb1),
- T = match(Kt, Ls, I+1, Vdb1),
- #k_alt{anno=[],first=F,then=T};
-match(#k_select{anno=A,types=Kts}=Select, Ls, I, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I, Vdb0),
- Ts = [type_clause(Tc, Ls, I+1, Vdb1) || Tc <- Kts],
- Select#k_select{anno=[],types=Ts};
-match(#k_guard{anno=A,clauses=Kcs}, Ls, I, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I, Vdb0),
- Cs = [guard_clause(G, Ls, I+1, Vdb1) || G <- Kcs],
- #k_guard{anno=[],clauses=Cs};
-match(Other, Ls, I, Vdb0) ->
- Vdb1 = use_vars(Ls, I, Vdb0),
- {B,_,Vdb2} = body(Other, I+1, Vdb1),
- Le = #l{i=I,vdb=Vdb2,a=[]},
- #cg_block{anno=Le,es=B}.
-
-type_clause(#k_type_clause{anno=A,type=T,values=Kvs}, Ls, I, Vdb0) ->
- %%ok = io:format("life ~w: ~p~n", [?LINE,{T,Kvs}]),
- Vdb1 = use_vars(union(A#k.us, Ls), I+1, Vdb0),
- Vs = [val_clause(Vc, Ls, I+1, Vdb1) || Vc <- Kvs],
- #k_type_clause{anno=[],type=T,values=Vs}.
-
-val_clause(#k_val_clause{anno=A,val=V,body=Kb}, Ls0, I, Vdb0) ->
- New = (get_kanno(V))#k.ns,
- Bus = (get_kanno(Kb))#k.us,
- %%ok = io:format("Ls0 = ~p, Used=~p\n New=~p, Bus=~p\n", [Ls0,Used,New,Bus]),
- Ls1 = union(intersection(New, Bus), Ls0), %Lock for safety
- Vdb1 = use_vars(union(A#k.us, Ls1), I+1, new_vars(New, I, Vdb0)),
- B = match(Kb, Ls1, I+1, Vdb1),
- Le = #l{i=I,vdb=use_vars(Bus, I+1, Vdb1),a=A#k.a},
- #k_val_clause{anno=Le,val=V,body=B}.
-
-guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Vdb0) ->
- Vdb1 = use_vars(union(A#k.us, Ls), I+2, Vdb0),
- Gdb = vdb_sub(I+1, I+2, Vdb1),
- G = protected(Kg, I+1, Gdb),
- B = match(Kb, Ls, I+2, Vdb1),
- Le = #l{i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1),a=A#k.a},
- #k_guard_clause{anno=Le,guard=G,body=B}.
-
-
-%% Here follows the code generator pass.
-%%
-%% The following assumptions have been made:
-%%
-%% 1. Matches, i.e. things with {match,M,Ret} wrappers, only return
-%% values; no variables are exported. If the match would have returned
-%% extra variables then these have been transformed to multiple return
-%% values.
-%%
-%% 2. All BIF's called in guards are gc-safe so there is no need to
-%% put thing on the stack in the guard. While this would in principle
-%% work it would be difficult to keep track of the stack depth when
-%% trimming.
-%%
-%% The code generation uses variable lifetime information added by
-%% the previous pass to save variables, allocate registers and
-%% move registers to the stack when necessary.
-%%
-%% We try to use a consistent variable name scheme throughout. The
-%% StackReg record is always called Bef,Int<n>,Aft.
-
-%% cg_fun([Lkexpr], [HeadVar], Vdb, State) -> {[Ainstr],State}
-
-cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
- {Fi,St1} = new_label(St0), %FuncInfo label
- {Fl,St2} = local_func_label(NameArity, St1),
-
- %%
- %% The pattern matching compiler (in v3_kernel) no longer
- %% provides its own catch-all clause, because the
- %% call to erlang:exit/1 caused problem when cases were
- %% used in guards. Therefore, there may be tests that
- %% cannot fail (providing that there is not a bug in a
- %% previous optimzation pass), but still need to provide
- %% a label (there are instructions, such as is_tuple/2,
- %% that do not allow {f,0}).
- %%
- %% We will generate an ultimate failure label and put it
- %% at the end of function, followed by an 'if_end' instruction.
- %% Note that and 'if_end' instruction does not need any
- %% live x registers, so it will always be safe to jump to
- %% it. (We never ever expect the jump to be taken, and in
- %% most functions there will never be any references to
- %% the label in the first place.)
- %%
-
- {UltimateMatchFail,St3} = new_label(St2),
-
- %% Create initial stack/register state, clear unused arguments.
- Bef = clear_dead(#sr{reg=foldl(fun (#k_var{name=V}, Reg) ->
- put_reg(V, Reg)
- end, [], Hvs),
- stk=[]}, 0, Vdb),
- {B,_Aft,St} = cg_list(Les, Vdb, Bef,
- St3#cg{bfail=0,
- ultimate_failure=UltimateMatchFail,
- is_top_block=true}),
- {Name,Arity} = NameArity,
- Asm = [{label,Fi},line(Anno),{func_info,AtomMod,{atom,Name},Arity},
- {label,Fl}|B++[{label,UltimateMatchFail},if_end]],
- {Asm,Fl,St}.
-
-%% cg(Lkexpr, Vdb, StackReg, State) -> {[Ainstr],StackReg,State}.
-%% Generate code for a kexpr.
-
-cg(#cg_block{anno=Le,es=Es}, Vdb, Bef, St) ->
- block_cg(Es, Le, Vdb, Bef, St);
-cg(#k_match{anno=Le,body=M,ret=Rs}, Vdb, Bef, St) ->
- match_cg(M, Rs, Le, Vdb, Bef, St);
-cg(#k_guard_match{anno=Le,body=M,ret=Rs}, Vdb, Bef, St) ->
- guard_match_cg(M, Rs, Le, Vdb, Bef, St);
-cg(#k_call{anno=Le,op=Func,args=As,ret=Rs}, Vdb, Bef, St) ->
- call_cg(Func, As, Rs, Le, Vdb, Bef, St);
-cg(#k_enter{anno=Le,op=Func,args=As}, Vdb, Bef, St) ->
- enter_cg(Func, As, Le, Vdb, Bef, St);
-cg(#k_bif{anno=Le}=Bif, Vdb, Bef, St) ->
- bif_cg(Bif, Le, Vdb, Bef, St);
-cg(#k_receive{anno=Le,timeout=Te,var=Rvar,body=Rm,action=Tes,ret=Rs},
- Vdb, Bef, St) ->
- recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St);
-cg(#k_receive_next{anno=Le}, Vdb, Bef, St) ->
- recv_next_cg(Le, Vdb, Bef, St);
-cg(#k_receive_accept{}, _Vdb, Bef, St) ->
- {[remove_message],Bef,St};
-cg(#k_try{anno=Le,arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th,ret=Rs},
- Vdb, Bef, St) ->
- try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St);
-cg(#k_try_enter{anno=Le,arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th},
- Vdb, Bef, St) ->
- try_enter_cg(Ta, Vs, Tb, Evs, Th, Le, Vdb, Bef, St);
-cg(#k_catch{anno=Le,body=Cb,ret=[R]}, Vdb, Bef, St) ->
- catch_cg(Cb, R, Le, Vdb, Bef, St);
-cg(#k_put{anno=Le,arg=Con,ret=Var}, Vdb, Bef, St) ->
- put_cg(Var, Con, Le, Vdb, Bef, St);
-cg(#k_return{anno=Le,args=Rs}, Vdb, Bef, St) ->
- return_cg(Rs, Le, Vdb, Bef, St);
-cg(#k_break{anno=Le,args=Bs}, Vdb, Bef, St) ->
- break_cg(Bs, Le, Vdb, Bef, St);
-cg(#k_guard_break{anno=Le,args=Bs}, Vdb, Bef, St) ->
- guard_break_cg(Bs, Le, Vdb, Bef, St);
-cg(#cg_need_heap{h=H}, _Vdb, Bef, St) ->
- {[{test_heap,H,max_reg(Bef#sr.reg)}],Bef,St}.
-
-%% cg_list([Kexpr], FirstI, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-cg_list(Kes, Vdb, Bef, St0) ->
- {Keis,{Aft,St1}} =
- flatmapfoldl(fun (Ke, {Inta,Sta}) ->
- {Keis,Intb,Stb} = cg(Ke, Vdb, Inta, Sta),
- {Keis,{Intb,Stb}}
- end, {Bef,St0}, need_heap(Kes)),
- {Keis,Aft,St1}.
-
-%% need_heap([Lkexpr], I, St) -> [Lkexpr].
-%% Insert need_heap instructions in Kexpr list. Try to be smart and
-%% collect them together as much as possible.
-
-need_heap(Kes0) ->
- {Kes,H} = need_heap_0(reverse(Kes0), 0, []),
-
- %% Prepend need_heap if necessary.
- need_heap_need(H) ++ Kes.
-
-need_heap_0([Ke|Kes], H0, Acc) ->
- {Ns,H} = need_heap_1(Ke, H0),
- need_heap_0(Kes, H, [Ke|Ns]++Acc);
-need_heap_0([], H, Acc) ->
- {Acc,H}.
-
-need_heap_1(#k_put{arg=#k_binary{}}, H) ->
- {need_heap_need(H),0};
-need_heap_1(#k_put{arg=#k_map{}}, H) ->
- {need_heap_need(H),0};
-need_heap_1(#k_put{arg=Val}, H) ->
- %% Just pass through adding to needed heap.
- {[],H + case Val of
- #k_cons{} -> 2;
- #k_tuple{es=Es} -> 1 + length(Es);
- _Other -> 0
- end};
-need_heap_1(#k_bif{}=Bif, H) ->
- case is_gc_bif(Bif) of
- false ->
- {[],H};
- true ->
- {need_heap_need(H),0}
- end;
-need_heap_1(_Ke, H) ->
- %% Call or call-like instruction such as set_tuple_element/3.
- {need_heap_need(H),0}.
-
-need_heap_need(0) -> [];
-need_heap_need(H) -> [#cg_need_heap{h=H}].
-
-%% is_gc_bif(#k_bif{}) -> true|false.
-%% is_gc_bif(Name, Arity) -> true|false.
-%% Determines whether the BIF Name/Arity might do a GC.
-
-is_gc_bif(#k_bif{op=#k_remote{name=#k_atom{val=Name}},args=Args}) ->
- is_gc_bif(Name, length(Args));
-is_gc_bif(#k_bif{op=#k_internal{}}) ->
- true.
-
-is_gc_bif(hd, 1) -> false;
-is_gc_bif(tl, 1) -> false;
-is_gc_bif(self, 0) -> false;
-is_gc_bif(node, 0) -> false;
-is_gc_bif(node, 1) -> false;
-is_gc_bif(element, 2) -> false;
-is_gc_bif(get, 1) -> false;
-is_gc_bif(tuple_size, 1) -> false;
-is_gc_bif(map_get, 2) -> false;
-is_gc_bif(is_map_key, 2) -> false;
-is_gc_bif(Bif, Arity) ->
- not (erl_internal:bool_op(Bif, Arity) orelse
- erl_internal:new_type_test(Bif, Arity) orelse
- erl_internal:comp_op(Bif, Arity)).
-
-%% match_cg(Matc, [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% Generate code for a match. First save all variables on the stack
-%% that are to survive after the match. We leave saved variables in
-%% their registers as they might actually be in the right place.
-
-match_cg(M, Rs, Le, Vdb, Bef, St0) ->
- I = Le#l.i,
- {Sis,Int0} = adjust_stack(Bef, I, I+1, Vdb),
- {B,St1} = new_label(St0),
- {Mis,Int1,St2} = match_cg(M, St1#cg.ultimate_failure,
- Int0, St1#cg{break=B}),
- %% Put return values in registers.
- Reg = load_vars(Rs, Int1#sr.reg),
- {Sis ++ Mis ++ [{label,B}],
- clear_dead(Int1#sr{reg=Reg}, I, Vdb),
- St2#cg{break=St1#cg.break}}.
-
-guard_match_cg(M, Rs, Le, Vdb, Bef, St0) ->
- I = Le#l.i,
- {B,St1} = new_label(St0),
- Fail = case St0 of
- #cg{bfail=0,ultimate_failure=Fail0} -> Fail0;
- #cg{bfail=Fail0} -> Fail0
- end,
- {Mis,Aft,St2} = match_cg(M, Fail, Bef, St1#cg{break=B}),
- %% Update the register descriptors for the return registers.
- Reg = guard_match_regs(Aft#sr.reg, Rs),
- {Mis ++ [{label,B}],
- clear_dead(Aft#sr{reg=Reg}, I, Vdb),
- St2#cg{break=St1#cg.break}}.
-
-guard_match_regs([{I,gbreakvar}|Rs], [#k_var{name=V}|Vs]) ->
- [{I,V}|guard_match_regs(Rs, Vs)];
-guard_match_regs([R|Rs], Vs) ->
- [R|guard_match_regs(Rs, Vs)];
-guard_match_regs([], []) -> [].
-
-
-%% match_cg(Match, Fail, StackReg, State) -> {[Ainstr],StackReg,State}.
-%% Generate code for a match tree. N.B. there is no need pass Vdb
-%% down as each level which uses this takes its own internal Vdb not
-%% the outer one.
-
-match_cg(#k_alt{first=F,then=S}, Fail, Bef, St0) ->
- {Tf,St1} = new_label(St0),
- {Fis,Faft,St2} = match_cg(F, Tf, Bef, St1),
- {Sis,Saft,St3} = match_cg(S, Fail, Bef, St2),
- Aft = sr_merge(Faft, Saft),
- {Fis ++ [{label,Tf}] ++ Sis,Aft,St3};
-match_cg(#k_select{var=#k_var{anno=Vanno,name=Vname}=V,types=Scs0}, Fail, Bef, St) ->
- ReuseForContext = member(reuse_for_context, Vanno) andalso
- find_reg(Vname, Bef#sr.reg) =/= error,
- Scs = case ReuseForContext of
- false -> Scs0;
- true -> bsm_rename_ctx(Scs0, Vname)
- end,
- match_fmf(fun (S, F, Sta) ->
- select_cg(S, V, F, Fail, Bef, Sta) end,
- Fail, St, Scs);
-match_cg(#k_guard{clauses=Gcs}, Fail, Bef, St) ->
- match_fmf(fun (G, F, Sta) -> guard_clause_cg(G, F, Bef, Sta) end,
- Fail, St, Gcs);
-match_cg(#cg_block{anno=Le,es=Es}, _Fail, Bef, St) ->
- %% Must clear registers and stack of dead variables.
- Int = clear_dead(Bef, Le#l.i, Le#l.vdb),
- block_cg(Es, Le, Int, St).
-
-%% bsm_rename_ctx([Clause], Var) -> [Clause]
-%% We know from an annotation that the register for a binary can
-%% be reused for the match context because the two are not truly
-%% alive at the same time (even though the life time information
-%% says so).
-%%
-%% The easiest way to have those variables share the same register is
-%% to rename the variable with the shortest life-span (the match
-%% context) to the variable for the binary (which can have a very
-%% long life-time because it is locked during matching). We KNOW that
-%% the match state variable will only be alive during the matching.
-%%
-%% We must also remove all information about the match context
-%% variable from all life-time information databases (Vdb).
-
-bsm_rename_ctx([#k_type_clause{type=k_binary,values=Vcs}=TC|Cs], New) ->
- [#k_val_clause{val=#k_binary{segs=#k_var{name=Old}}=Bin,
- body=Ke0}=VC0] = Vcs,
- Ke = bsm_rename_ctx(Ke0, Old, New, false),
- VC = VC0#k_val_clause{val=Bin#k_binary{segs=#k_var{name=New}},
- body=Ke},
- [TC#k_type_clause{values=[VC]}|bsm_rename_ctx(Cs, New)];
-bsm_rename_ctx([C|Cs], New) ->
- [C|bsm_rename_ctx(Cs, New)];
-bsm_rename_ctx([], _) -> [].
-
-%% bsm_rename_ctx(Ke, OldName, NewName, InProt) -> Ke'
-%% Rename and clear OldName from life-time information. We must
-%% recurse into any block contained in a protected, but it would
-%% only complicatate things to recurse into blocks not in a protected
-%% (the match context variable is not live inside them).
-
-bsm_rename_ctx(#k_select{var=#k_var{name=V},types=Cs0}=Sel,
- Old, New, InProt) ->
- Cs = bsm_rename_ctx_list(Cs0, Old, New, InProt),
- Sel#k_select{var=#k_var{name=bsm_rename_var(V, Old, New)},types=Cs};
-bsm_rename_ctx(#k_type_clause{values=Cs0}=TC, Old, New, InProt) ->
- Cs = bsm_rename_ctx_list(Cs0, Old, New, InProt),
- TC#k_type_clause{values=Cs};
-bsm_rename_ctx(#k_val_clause{body=Ke0}=VC, Old, New, InProt) ->
- Ke = bsm_rename_ctx(Ke0, Old, New, InProt),
- VC#k_val_clause{body=Ke};
-bsm_rename_ctx(#k_alt{first=F0,then=S0}=Alt, Old, New, InProt) ->
- F = bsm_rename_ctx(F0, Old, New, InProt),
- S = bsm_rename_ctx(S0, Old, New, InProt),
- Alt#k_alt{first=F,then=S};
-bsm_rename_ctx(#k_guard{clauses=Gcs0}=Guard, Old, New, InProt) ->
- Gcs = bsm_rename_ctx_list(Gcs0, Old, New, InProt),
- Guard#k_guard{clauses=Gcs};
-bsm_rename_ctx(#k_guard_clause{guard=G0,body=B0}=GC, Old, New, InProt) ->
- G = bsm_rename_ctx(G0, Old, New, InProt),
- B = bsm_rename_ctx(B0, Old, New, InProt),
- %% A guard clause may cause unsaved variables to be saved on the stack.
- %% Since the match state variable Old is an alias for New (uses the
- %% same register), it is neither in the stack nor register descriptor
- %% lists and we would crash when we didn't find it unless we remove
- %% it from the database.
- bsm_forget_var(GC#k_guard_clause{guard=G,body=B}, Old);
-bsm_rename_ctx(#k_protected{arg=Ts0}=Prot, Old, New, _InProt) ->
- InProt = true,
- Ts = bsm_rename_ctx_list(Ts0, Old, New, InProt),
- bsm_forget_var(Prot#k_protected{arg=Ts}, Old);
-bsm_rename_ctx(#k_guard_match{body=Ms0}=Match, Old, New, InProt) ->
- Ms = bsm_rename_ctx(Ms0, Old, New, InProt),
- Match#k_guard_match{body=Ms};
-bsm_rename_ctx(#k_test{}=Test, _, _, _) -> Test;
-bsm_rename_ctx(#k_bif{}=Bif, _, _, _) -> Bif;
-bsm_rename_ctx(#k_put{}=Put, _, _, _) -> Put;
-bsm_rename_ctx(#k_call{}=Call, _, _, _) -> Call;
-bsm_rename_ctx(#cg_block{}=Block, Old, _, false) ->
- %% This block is not inside a protected. The match context variable cannot
- %% possibly be live inside the block.
- bsm_forget_var(Block, Old);
-bsm_rename_ctx(#cg_block{es=Es0}=Block, Old, New, true) ->
- %% A block in a protected. We must recursively rename the variable
- %% inside the block.
- Es = bsm_rename_ctx_list(Es0, Old, New, true),
- bsm_forget_var(Block#cg_block{es=Es}, Old);
-bsm_rename_ctx(#k_guard_break{}=Break, Old, _New, _InProt) ->
- bsm_forget_var(Break, Old).
-
-bsm_rename_ctx_list([C|Cs], Old, New, InProt) ->
- [bsm_rename_ctx(C, Old, New, InProt)|
- bsm_rename_ctx_list(Cs, Old, New, InProt)];
-bsm_rename_ctx_list([], _, _, _) -> [].
-
-bsm_rename_var(Old, Old, New) -> New;
-bsm_rename_var(V, _, _) -> V.
-
-%% bsm_forget_var(#l{}, Variable) -> #l{}
-%% Remove a variable from the variable life-time database.
-
-bsm_forget_var(Ke, V) ->
- #l{vdb=Vdb} = L0 = get_kanno(Ke),
- L = L0#l{vdb=keydelete(V, 1, Vdb)},
- set_kanno(Ke, L).
-
-%% block_cg([Kexpr], Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-%% block_cg([Kexpr], Le, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-block_cg(Es, Le, _Vdb, Bef, St) ->
- block_cg(Es, Le, Bef, St).
-
-block_cg(Es, Le, Bef, #cg{is_top_block=false}=St) ->
- cg_block(Es, Le#l.vdb, Bef, St);
-block_cg(Es, Le, Bef, #cg{is_top_block=true}=St0) ->
- %% No stack frame has been established yet. Do we need one?
- case need_stackframe(Es) of
- true ->
- %% We need a stack frame. Generate the code and add the
- %% code for creating and deallocating the stack frame.
- {Is0,Aft,St} = cg_block(Es, Le#l.vdb, Bef,
- St0#cg{is_top_block=false,need_frame=false}),
- Is = top_level_block(Is0, Aft, max_reg(Bef#sr.reg), St),
- {Is,Aft,St#cg{is_top_block=true}};
- false ->
- %% This sequence of instructions ending in a #k_match{} (a
- %% 'case' or 'if') in the Erlang code does not need a
- %% stack frame yet. Delay the creation (if a stack frame
- %% is needed at all, it will be created inside the
- %% #k_match{}).
- cg_list(Es, Le#l.vdb, Bef, St0)
- end.
-
-%% need_stackframe([Kexpr]) -> true|false.
-%% Does this list of instructions need a stack frame?
-%%
-%% A sequence of instructions that don't clobber the X registers
-%% followed by a single #k_match{} doesn't need a stack frame.
-
-need_stackframe([H|T]) ->
- case H of
- #k_bif{op=#k_internal{}} -> true;
- #k_put{arg=#k_binary{}} -> true;
- #k_bif{} -> need_stackframe(T);
- #k_put{} -> need_stackframe(T);
- #k_guard_match{} -> need_stackframe(T);
- #k_match{} when T =:= [] -> false;
- _ -> true
- end;
-need_stackframe([]) -> false.
-
-cg_block([], _Vdb, Bef, St0) ->
- {[],Bef,St0};
-cg_block(Kes0, Vdb, Bef, St0) ->
- {Kes2,Int1,St1} =
- case basic_block(Kes0) of
- {Kes1,LastI,Args,Rest} ->
- cg_basic_block(Kes1, LastI, Args, Vdb, Bef, St0);
- {Kes1,Rest} ->
- cg_list(Kes1, Vdb, Bef, St0)
- end,
- {Kes3,Int2,St2} = cg_block(Rest, Vdb, Int1, St1),
- {Kes2 ++ Kes3,Int2,St2}.
-
-basic_block(Kes) -> basic_block(Kes, []).
-
-basic_block([Ke|Kes], Acc) ->
- case collect_block(Ke) of
- include -> basic_block(Kes, [Ke|Acc]);
- {block_end,As} ->
- case Acc of
- [] ->
- %% If the basic block does not contain any #k_put{} instructions,
- %% it serves no useful purpose to do basic block optimizations.
- {[Ke],Kes};
- _ ->
- #l{i=I} = get_kanno(Ke),
- {reverse(Acc, [Ke]),I,As,Kes}
- end;
- no_block -> {reverse(Acc, [Ke]),Kes}
- end.
-
-collect_block(#k_put{arg=Arg}) ->
- %% #k_put{} instructions that may garbage collect are not allowed
- %% in basic blocks.
- case Arg of
- #k_binary{} -> no_block;
- #k_map{} -> no_block;
- _ -> include
- end;
-collect_block(#k_call{op=Func,args=As}) ->
- {block_end,As++func_vars(Func)};
-collect_block(#k_enter{op=Func,args=As}) ->
- {block_end,As++func_vars(Func)};
-collect_block(#k_return{args=Rs}) ->
- {block_end,Rs};
-collect_block(#k_break{args=Bs}) ->
- {block_end,Bs};
-collect_block(_) -> no_block.
-
-func_vars(#k_var{}=Var) ->
- [Var];
-func_vars(#k_remote{mod=M,name=F})
- when is_record(M, k_var); is_record(F, k_var) ->
- [M,F];
-func_vars(_) -> [].
-
-%% cg_basic_block([Kexpr], FirstI, LastI, Arguments, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%%
-%% Do a specialized code generation for a basic block of #put{}
-%% instructions (that don't do any garbage collection) followed by a
-%% call, break, or return.
-%%
-%% 'Arguments' is a list of the variables that must be loaded into
-%% consecutive X registers before the last instruction in the block.
-%% The point of this specialized code generation is to try put the
-%% all of the variables in 'Arguments' into the correct X register
-%% to begin with, instead of putting them into the first available
-%% X register and having to move them to the correct X register
-%% later.
-%%
-%% To achieve that, we attempt to reserve the X registers that the
-%% variables in 'Arguments' will need to be in when the block ends.
-%%
-%% To make it more likely that reservations will be successful, we
-%% will try to save variables that need to be saved to the stack as
-%% early as possible (if an X register needed by a variable in
-%% Arguments is occupied by another variable, the value in the
-%% X register can be evicted if it is saved on the stack).
-%%
-%% We will take care not to increase the size of stack frame compared
-%% to what the standard code generator would have done (that is, to
-%% save all X registers at the last possible moment). We will do that
-%% by extending the stack frame to the minimal size needed to save
-%% all that needs to be saved using extend_stack/4, and use
-%% save_carefully/4 during code generation to only save the variables
-%% that can be saved without growing the stack frame.
-
-cg_basic_block(Kes, Lf, As, Vdb, Bef, St0) ->
- Int0 = reserve_arg_regs(As, Bef),
- Int = extend_stack(Int0, Lf, Lf+1, Vdb),
- {Keis,{Aft,St1}} =
- flatmapfoldl(fun(Ke, St) -> cg_basic_block(Ke, St, Lf, Vdb) end,
- {Int,St0}, need_heap(Kes)),
- {Keis,Aft,St1}.
-
-cg_basic_block(#cg_need_heap{}=Ke, {Bef,St0}, _Lf, Vdb) ->
- {Keis,Aft,St1} = cg(Ke, Vdb, Bef, St0),
- {Keis,{Aft,St1}};
-cg_basic_block(Ke, {Bef,St0}, Lf, Vdb) ->
- #l{i=I} = get_kanno(Ke),
-
- %% Save all we can to increase the possibility that reserving
- %% registers will succeed.
- {Sis,Int0} = save_carefully(Bef, I, Lf+1, Vdb),
- Int1 = reserve(Int0),
- {Keis,Aft,St1} = cg(Ke, Vdb, Int1, St0),
- {Sis ++ Keis,{Aft,St1}}.
-
-%% reserve_arg_regs([Argument], Bef) -> Aft.
-%% Try to reserve the X registers for all arguments. All registers
-%% that we wish to reserve will be saved in Bef#sr.res.
-
-reserve_arg_regs(As, Bef) ->
- Res = reserve_arg_regs_1(As, 0),
- reserve(Bef#sr{res=Res}).
-
-reserve_arg_regs_1([#k_var{name=V}|As], I) ->
- [{I,V}|reserve_arg_regs_1(As, I+1)];
-reserve_arg_regs_1([A|As], I) ->
- [{I,A}|reserve_arg_regs_1(As, I+1)];
-reserve_arg_regs_1([], _) -> [].
-
-%% reserve(Bef) -> Aft.
-%% Try to reserve more registers. The registers we wish to reserve
-%% are found in Bef#sr.res.
-
-reserve(#sr{reg=Regs,stk=Stk,res=Res}=Sr) ->
- Sr#sr{reg=reserve_1(Res, Regs, Stk)}.
-
-reserve_1([{I,V}|Rs], [free|Regs], Stk) ->
- [{reserved,I,V}|reserve_1(Rs, Regs, Stk)];
-reserve_1([{I,V}|Rs], [{I,V}|Regs], Stk) ->
- [{I,V}|reserve_1(Rs, Regs, Stk)];
-reserve_1([{I,V}|Rs], [{I,Var}|Regs], Stk) ->
- case on_stack(Var, Stk) of
- true -> [{reserved,I,V}|reserve_1(Rs, Regs, Stk)];
- false -> [{I,Var}|reserve_1(Rs, Regs, Stk)]
- end;
-reserve_1([{I,V}|Rs], [{reserved,I,_}|Regs], Stk) ->
- [{reserved,I,V}|reserve_1(Rs, Regs, Stk)];
-reserve_1([{I,V}|Rs], [], Stk) ->
- [{reserved,I,V}|reserve_1(Rs, [], Stk)];
-reserve_1([], Regs, _) -> Regs.
-
-%% extend_stack(Bef, FirstBefore, LastFrom, Vdb) -> Aft.
-%% Extend the stack enough to fit all variables alive past LastFrom
-%% and not already on the stack.
-
-extend_stack(#sr{stk=Stk0}=Bef, Fb, Lf, Vdb) ->
- Stk1 = clear_dead_stk(Stk0, Fb, Vdb),
- New = new_not_on_stack(Stk1, Fb, Lf, Vdb),
- Stk2 = foldl(fun ({V,_,_}, Stk) -> put_stack(V, Stk) end, Stk1, New),
- Stk = Stk0 ++ lists:duplicate(length(Stk2) - length(Stk0), free),
- Bef#sr{stk=Stk}.
-
-%% save_carefully(Bef, FirstBefore, LastFrom, Vdb) -> {[SaveVar],Aft}.
-%% Save variables which are used past current point and which are not
-%% already on the stack, but only if the variables can be saved without
-%% growing the stack frame.
-
-save_carefully(#sr{stk=Stk}=Bef, Fb, Lf, Vdb) ->
- New0 = new_not_on_stack(Stk, Fb, Lf, Vdb),
- New = keysort(2, New0),
- save_carefully_1(New, Bef, []).
-
-save_carefully_1([{V,_,_}|Vs], #sr{reg=Regs,stk=Stk0}=Bef, Acc) ->
- case put_stack_carefully(V, Stk0) of
- error ->
- {reverse(Acc),Bef};
- Stk1 ->
- SrcReg = fetch_reg(V, Regs),
- Move = {move,SrcReg,fetch_stack(V, Stk1)},
- {x,_} = SrcReg, %Assertion - must be X register.
- save_carefully_1(Vs, Bef#sr{stk=Stk1}, [Move|Acc])
- end;
-save_carefully_1([], Bef, Acc) ->
- {reverse(Acc),Bef}.
-
-%% top_level_block([Instruction], Bef, MaxRegs, St) -> [Instruction].
-%% For the top-level block, allocate a stack frame a necessary,
-%% adjust Y register numbering and instructions that return
-%% from the function.
-
-top_level_block(Keis, #sr{stk=[]}, _MaxRegs, #cg{need_frame=false}) ->
- Keis;
-top_level_block(Keis, Bef, MaxRegs, _St) ->
- %% This top block needs an allocate instruction before it, and a
- %% deallocate instruction before each return.
- FrameSz = length(Bef#sr.stk),
- MaxY = FrameSz-1,
- Keis1 = flatmap(fun ({call_only,Arity,Func}) ->
- [{call_last,Arity,Func,FrameSz}];
- ({call_ext_only,Arity,Func}) ->
- [{call_ext_last,Arity,Func,FrameSz}];
- ({apply_only,Arity}) ->
- [{apply_last,Arity,FrameSz}];
- (return) ->
- [{deallocate,FrameSz},return];
- (Tuple) when is_tuple(Tuple) ->
- [turn_yregs(Tuple, MaxY)];
- (Other) ->
- [Other]
- end, Keis),
- [{allocate_zero,FrameSz,MaxRegs}|Keis1].
-
-%% turn_yregs(Size, Tuple, MaxY) -> Tuple'
-%% Renumber y register so that {y,0} becomes {y,FrameSize-1},
-%% {y,FrameSize-1} becomes {y,0} and so on. This is to make nested
-%% catches work. The code generation algorithm gives a lower register
-%% number to the outer catch, which is wrong.
-
-turn_yregs({call,_,_}=I, _MaxY) -> I;
-turn_yregs({call_ext,_,_}=I, _MaxY) -> I;
-turn_yregs({jump,_}=I, _MaxY) -> I;
-turn_yregs({label,_}=I, _MaxY) -> I;
-turn_yregs({line,_}=I, _MaxY) -> I;
-turn_yregs({test_heap,_,_}=I, _MaxY) -> I;
-turn_yregs({bif,Op,F,A,B}, MaxY) ->
- {bif,Op,F,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({gc_bif,Op,F,Live,A,B}, MaxY) when is_integer(Live) ->
- {gc_bif,Op,F,Live,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({get_tuple_element,S,N,D}, MaxY) ->
- {get_tuple_element,turn_yreg(S, MaxY),N,turn_yreg(D, MaxY)};
-turn_yregs({put_tuple,Arity,D}, MaxY) ->
- {put_tuple,Arity,turn_yreg(D, MaxY)};
-turn_yregs({select_val,R,F,L}, MaxY) ->
- {select_val,turn_yreg(R, MaxY),F,L};
-turn_yregs({test,Op,F,L}, MaxY) ->
- {test,Op,F,turn_yreg(L, MaxY)};
-turn_yregs({test,Op,F,Live,A,B}, MaxY) when is_integer(Live) ->
- {test,Op,F,Live,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({Op,A}, MaxY) ->
- {Op,turn_yreg(A, MaxY)};
-turn_yregs({Op,A,B}, MaxY) ->
- {Op,turn_yreg(A, MaxY),turn_yreg(B, MaxY)};
-turn_yregs({Op,A,B,C}, MaxY) ->
- {Op,turn_yreg(A, MaxY),turn_yreg(B, MaxY),turn_yreg(C, MaxY)};
-turn_yregs(Tuple, MaxY) ->
- turn_yregs(tuple_size(Tuple), Tuple, MaxY).
-
-turn_yregs(1, Tp, _) ->
- Tp;
-turn_yregs(N, Tp, MaxY) ->
- E = turn_yreg(element(N, Tp), MaxY),
- turn_yregs(N-1, setelement(N, Tp, E), MaxY).
-
-turn_yreg({yy,YY}, MaxY) ->
- {y,MaxY-YY};
-turn_yreg({list,Ls},MaxY) ->
- {list,turn_yreg(Ls, MaxY)};
-turn_yreg([_|_]=Ts, MaxY) ->
- [turn_yreg(T, MaxY) || T <- Ts];
-turn_yreg(Other, _MaxY) ->
- Other.
-
-%% select_cg(Sclause, V, TypeFail, ValueFail, StackReg, State) ->
-%% {Is,StackReg,State}.
-%% Selecting type and value needs two failure labels, TypeFail is the
-%% label to jump to of the next type test when this type fails, and
-%% ValueFail is the label when this type is correct but the value is
-%% wrong. These are different as in the second case there is no need
-%% to try the next type, it will always fail.
-
-select_cg(#k_type_clause{type=Type,values=Vs}, Var, Tf, Vf, Bef, St) ->
- #k_var{name=V} = Var,
- select_cg(Type, Vs, V, Tf, Vf, Bef, St).
-
-select_cg(k_cons, [S], V, Tf, Vf, Bef, St) ->
- select_cons(S, V, Tf, Vf, Bef, St);
-select_cg(k_nil, [S], V, Tf, Vf, Bef, St) ->
- select_nil(S, V, Tf, Vf, Bef, St);
-select_cg(k_binary, [S], V, Tf, Vf, Bef, St) ->
- select_binary(S, V, Tf, Vf, Bef, St);
-select_cg(k_bin_seg, S, V, Tf, _Vf, Bef, St) ->
- select_bin_segs(S, V, Tf, Bef, St);
-select_cg(k_bin_int, S, V, Tf, _Vf, Bef, St) ->
- select_bin_segs(S, V, Tf, Bef, St);
-select_cg(k_bin_end, [S], V, Tf, _Vf, Bef, St) ->
- select_bin_end(S, V, Tf, Bef, St);
-select_cg(k_map, S, V, Tf, Vf, Bef, St) ->
- select_map(S, V, Tf, Vf, Bef, St);
-select_cg(k_literal, S, V, Tf, Vf, Bef, St) ->
- select_literal(S, V, Tf, Vf, Bef, St);
-select_cg(Type, Scs, V, Tf, Vf, Bef, St0) ->
- {Vis,{Aft,St1}} =
- mapfoldl(fun (S, {Int,Sta}) ->
- {Val,Is,Inta,Stb} = select_val(S, V, Vf, Bef, Sta),
- {{Is,[Val]},{sr_merge(Int, Inta),Stb}}
- end, {void,St0}, Scs),
- OptVls = combine(lists:sort(combine(Vis))),
- {Vls,Sis,St2} = select_labels(OptVls, St1, [], []),
- {select_val_cg(Type, fetch_var(V, Bef), Vls, Tf, Vf, Sis), Aft, St2}.
-
-select_val_cg(k_tuple, R, [Arity,{f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) ->
- [{test,is_tuple,{f,Tf},[R]},{test,test_arity,{f,Vf},[R,Arity]}|Sis];
-select_val_cg(k_tuple, R, Vls, Tf, Vf, Sis) ->
- [{test,is_tuple,{f,Tf},[R]},{select_tuple_arity,R,{f,Vf},{list,Vls}}|Sis];
-select_val_cg(Type, R, [Val, {f,Lbl}], Fail, Fail, [{label,Lbl}|Sis]) ->
- [{test,is_eq_exact,{f,Fail},[R,{type(Type),Val}]}|Sis];
-select_val_cg(Type, R, [Val, {f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) ->
- [{test,select_type_test(Type),{f,Tf},[R]},
- {test,is_eq_exact,{f,Vf},[R,{type(Type),Val}]}|Sis];
-select_val_cg(Type, R, Vls0, Tf, Vf, Sis) ->
- Vls1 = [case Value of
- {f,_Lbl} -> Value;
- _ -> {type(Type),Value}
- end || Value <- Vls0],
- [{test,select_type_test(Type),{f,Tf},[R]}, {select_val,R,{f,Vf},{list,Vls1}}|Sis].
-
-type(k_atom) -> atom;
-type(k_float) -> float;
-type(k_int) -> integer.
-
-select_type_test(k_int) -> is_integer;
-select_type_test(k_atom) -> is_atom;
-select_type_test(k_float) -> is_float.
-
-combine([{Is,Vs1}, {Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]);
-combine([V|Vis]) -> [V|combine(Vis)];
-combine([]) -> [].
-
-select_labels([{Is,Vs}|Vis], St0, Vls, Sis) ->
- {Lbl,St1} = new_label(St0),
- select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]);
-select_labels([], St, Vls, Sis) ->
- {Vls,append(Sis),St}.
-
-add_vls([V|Vs], Lbl, Acc) ->
- add_vls(Vs, Lbl, [V, {f,Lbl}|Acc]);
-add_vls([], _, Acc) -> Acc.
-
-select_literal(S, V, Tf, Vf, Bef, St) ->
- Reg = fetch_var(V, Bef),
- F = fun(ValClause, Fail, St0) ->
- {Val,Is,Aft,St1} = select_val(ValClause, V, Vf, Bef, St0),
- Test = {test,is_eq_exact,{f,Fail},[Reg,{literal,Val}]},
- {[Test|Is],Aft,St1}
- end,
- match_fmf(F, Tf, St, S).
-
-select_cons(#k_val_clause{val=#k_cons{hd=Hd,tl=Tl},body=B,anno=#l{i=I,vdb=Vdb}},
- V, Tf, Vf, Bef, St0) ->
- Es = [Hd,Tl],
- {Eis,Int,St1} = select_extract_cons(V, Es, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Vf, Int, St1),
- {[{test,is_nonempty_list,{f,Tf},[fetch_var(V, Bef)]}] ++ Eis ++ Bis,Aft,St2}.
-
-select_nil(#k_val_clause{val=#k_nil{},body=B}, V, Tf, Vf, Bef, St0) ->
- {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0),
- {[{test,is_nil,{f,Tf},[fetch_var(V, Bef)]}] ++ Bis,Aft,St1}.
-
-select_binary(#k_val_clause{val=#k_binary{segs=#k_var{name=V}},body=B,
- anno=#l{i=I,vdb=Vdb}}, V, Tf, Vf, Bef, St0) ->
- #cg{ctx=OldCtx} = St0,
- Int0 = clear_dead(Bef#sr{reg=Bef#sr.reg}, I, Vdb),
- {Bis0,Aft,St1} = match_cg(B, Vf, Int0, St0#cg{ctx=V}),
- CtxReg = fetch_var(V, Int0),
- Live = max_reg(Bef#sr.reg),
- Bis1 = [{test,bs_start_match2,{f,Tf},Live,[CtxReg,{context,V}],CtxReg},
- {bs_save2,CtxReg,{V,V}}|Bis0],
- Bis = finish_select_binary(Bis1),
- {Bis,Aft,St1#cg{ctx=OldCtx}};
-select_binary(#k_val_clause{val=#k_binary{segs=#k_var{name=Ivar}},body=B,
- anno=#l{i=I,vdb=Vdb}}, V, Tf, Vf, Bef, St0) ->
- #cg{ctx=OldCtx} = St0,
- Regs = put_reg(Ivar, Bef#sr.reg),
- Int0 = clear_dead(Bef#sr{reg=Regs}, I, Vdb),
- {Bis0,Aft,St1} = match_cg(B, Vf, Int0, St0#cg{ctx=Ivar}),
- CtxReg = fetch_var(Ivar, Int0),
- Live = max_reg(Bef#sr.reg),
- Bis1 = [{test,bs_start_match2,{f,Tf},Live,
- [fetch_var(V, Bef),{context,Ivar}],CtxReg},
- {bs_save2,CtxReg,{Ivar,Ivar}}|Bis0],
- Bis = finish_select_binary(Bis1),
- {Bis,Aft,St1#cg{ctx=OldCtx}}.
-
-finish_select_binary([{bs_save2,R,Point}=I,{bs_restore2,R,Point}|Is]) ->
- [I|finish_select_binary(Is)];
-finish_select_binary([{bs_save2,R,Point}=I,{test,is_eq_exact,_,_}=Test,
- {bs_restore2,R,Point}|Is]) ->
- [I,Test|finish_select_binary(Is)];
-finish_select_binary([{test,bs_match_string,F,[Ctx,BinList]}|Is])
- when is_list(BinList) ->
- I = {test,bs_match_string,F,[Ctx,list_to_bitstring(BinList)]},
- [I|finish_select_binary(Is)];
-finish_select_binary([I|Is]) ->
- [I|finish_select_binary(Is)];
-finish_select_binary([]) -> [].
-
-%% New instructions for selection of binary segments.
-
-select_bin_segs(Scs, Ivar, Tf, Bef, St) ->
- match_fmf(fun(S, Fail, Sta) ->
- select_bin_seg(S, Ivar, Fail, Bef, Sta) end,
- Tf, St, Scs).
-
-select_bin_seg(#k_val_clause{val=#k_bin_seg{size=Size,unit=U,type=T,
- seg=Seg,flags=Fs0,next=Next},
- body=B,
- anno=#l{i=I,vdb=Vdb,a=A}}, Ivar, Fail, Bef, St0) ->
- Ctx = St0#cg.ctx,
- Fs = [{anno,A}|Fs0],
- Es = case Next of
- [] -> [Seg];
- _ -> [Seg,Next]
- end,
- {Mis,Int,St1} = select_extract_bin(Es, Size, U, T, Fs, Fail,
- I, Vdb, Bef, Ctx, B, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- CtxReg = fetch_var(Ctx, Bef),
- Is = if
- Mis =:= [] ->
- %% No bs_restore2 instruction needed if no match instructions.
- Bis;
- true ->
- [{bs_restore2,CtxReg,{Ctx,Ivar}}|Mis++Bis]
- end,
- {Is,Aft,St2};
-select_bin_seg(#k_val_clause{val=#k_bin_int{size=Sz,unit=U,flags=Fs,
- val=Val,next=Next},
- body=B,
- anno=#l{i=I,vdb=Vdb}}, Ivar, Fail, Bef, St0) ->
- Ctx = St0#cg.ctx,
- {Mis,Int,St1} = select_extract_int(Next, Val, Sz, U, Fs, Fail,
- I, Vdb, Bef, Ctx, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- CtxReg = fetch_var(Ctx, Bef),
- Is = case Mis ++ Bis of
- [{test,bs_match_string,F,[OtherCtx,Bin1]},
- {bs_save2,OtherCtx,_},
- {bs_restore2,OtherCtx,_},
- {test,bs_match_string,F,[OtherCtx,Bin2]}|Is0] ->
- %% We used to do this optimization later, but it
- %% turns out that in huge functions with many
- %% bs_match_string instructions, it's a big win
- %% to do the combination now. To avoid copying the
- %% binary data again and again, we'll combine bitstrings
- %% in a list and convert all of it to a bitstring later.
- [{test,bs_match_string,F,[OtherCtx,[Bin1,Bin2]]}|Is0];
- Is0 ->
- Is0
- end,
- {[{bs_restore2,CtxReg,{Ctx,Ivar}}|Is],Aft,St2}.
-
-select_extract_int(#k_var{name=Tl}, Val, #k_int{val=Sz}, U, Fs, Vf,
- I, Vdb, Bef, Ctx, St) ->
- Bits = U*Sz,
- Bin = case member(big, Fs) of
- true ->
- <<Val:Bits>>;
- false ->
- true = member(little, Fs), %Assertion.
- <<Val:Bits/little>>
- end,
- Bits = bit_size(Bin), %Assertion.
- CtxReg = fetch_var(Ctx, Bef),
- Is = if
- Bits =:= 0 ->
- [{bs_save2,CtxReg,{Ctx,Tl}}];
- true ->
- [{test,bs_match_string,{f,Vf},[CtxReg,Bin]},
- {bs_save2,CtxReg,{Ctx,Tl}}]
- end,
- {Is,clear_dead(Bef, I, Vdb),St}.
-
-select_extract_bin([#k_var{name=Hd},#k_var{name=Tl}], Size0, Unit, Type, Flags, Vf,
- I, Vdb, Bef, Ctx, _Body, St) ->
- SizeReg = get_bin_size_reg(Size0, Bef),
- {Es,Aft} =
- case vdb_find(Hd, Vdb) of
- {_,_,Lhd} when Lhd =< I ->
- %% The extracted value will not be used.
- CtxReg = fetch_var(Ctx, Bef),
- Live = max_reg(Bef#sr.reg),
- Skip = build_skip_instr(Type, Vf, CtxReg, Live,
- SizeReg, Unit, Flags),
- {[Skip,{bs_save2,CtxReg,{Ctx,Tl}}],Bef};
- {_,_,_} ->
- Reg = put_reg(Hd, Bef#sr.reg),
- Int1 = Bef#sr{reg=Reg},
- Rhd = fetch_reg(Hd, Reg),
- CtxReg = fetch_reg(Ctx, Reg),
- Live = max_reg(Bef#sr.reg),
- {[build_bs_instr(Type, Vf, CtxReg, Live, SizeReg,
- Unit, Flags, Rhd),
- {bs_save2,CtxReg,{Ctx,Tl}}],Int1}
- end,
- {Es,clear_dead(Aft, I, Vdb),St};
-select_extract_bin([#k_var{name=Hd}], Size, Unit, binary, Flags, Vf,
- I, Vdb, Bef, Ctx, Body, St) ->
- %% Match the last segment of a binary. We KNOW that the size
- %% must be 'all'.
- #k_atom{val=all} = Size, %Assertion.
- {Es,Aft} =
- case vdb_find(Hd, Vdb) of
- {_,_,Lhd} when Lhd =< I ->
- %% The result will not be used. Furthermore, since we
- %% we are at the end of the binary, the position will
- %% not be used again; thus, it is safe to do a cheaper
- %% test of the unit.
- CtxReg = fetch_var(Ctx, Bef),
- {case Unit of
- 1 ->
- [];
- _ ->
- [{test,bs_test_unit,{f,Vf},[CtxReg,Unit]}]
- end,Bef};
- {_,_,_} ->
- case is_context_unused(Body) of
- false ->
- Reg = put_reg(Hd, Bef#sr.reg),
- Int1 = Bef#sr{reg=Reg},
- Rhd = fetch_reg(Hd, Reg),
- CtxReg = fetch_reg(Ctx, Reg),
- Name = bs_get_binary2,
- Live = max_reg(Bef#sr.reg),
- {[{test,Name,{f,Vf},Live,
- [CtxReg,atomic(Size),Unit,{field_flags,Flags}],Rhd}],
- Int1};
- true ->
- %% Since the matching context will not be used again,
- %% we can reuse its register. Reusing the register
- %% opens some interesting optimizations in the
- %% run-time system.
-
- Reg0 = Bef#sr.reg,
- CtxReg = fetch_reg(Ctx, Reg0),
- Reg = replace_reg_contents(Ctx, Hd, Reg0),
- Int1 = Bef#sr{reg=Reg},
- Name = bs_get_binary2,
- Live = max_reg(Int1#sr.reg),
- {[{test,Name,{f,Vf},Live,
- [CtxReg,atomic(Size),Unit,{field_flags,Flags}],CtxReg}],
- Int1}
- end
- end,
- {Es,clear_dead(Aft, I, Vdb),St}.
-
-%% is_context_unused(Ke) -> true | false
-%% Simple heurististic to determine whether the code that follows
-%% will use the current matching context again. (The liveness
-%% information is too conservative to be useful for this purpose.)
-%% 'true' means that the code that follows will definitely not use
-%% the context again (because it is a block, not guard or matching
-%% code); 'false' that we are not sure (there could be more
-%% matching).
-
-is_context_unused(#k_alt{then=Then}) ->
- %% #k_alt{} can be used for different purposes. If the Then part
- %% is a block, it means that matching has finished and is used for a guard
- %% to choose between the matched clauses.
- is_context_unused(Then);
-is_context_unused(#cg_block{}) ->
- true;
-is_context_unused(_) ->
- false.
-
-select_bin_end(#k_val_clause{val=#k_bin_end{},body=B}, Ivar, Tf, Bef, St0) ->
- Ctx = St0#cg.ctx,
- {Bis,Aft,St2} = match_cg(B, Tf, Bef, St0),
- CtxReg = fetch_var(Ctx, Bef),
- {[{bs_restore2,CtxReg,{Ctx,Ivar}},
- {test,bs_test_tail2,{f,Tf},[CtxReg,0]}|Bis],Aft,St2}.
-
-get_bin_size_reg(#k_var{name=V}, Bef) ->
- fetch_var(V, Bef);
-get_bin_size_reg(Literal, _Bef) ->
- atomic(Literal).
-
-build_bs_instr(Type, Vf, CtxReg, Live, SizeReg, Unit, Flags, Rhd) ->
- {Format,Name} = case Type of
- integer -> {plain,bs_get_integer2};
- float -> {plain,bs_get_float2};
- binary -> {plain,bs_get_binary2};
- utf8 -> {utf,bs_get_utf8};
- utf16 -> {utf,bs_get_utf16};
- utf32 -> {utf,bs_get_utf32}
- end,
- case Format of
- plain ->
- {test,Name,{f,Vf},Live,
- [CtxReg,SizeReg,Unit,{field_flags,Flags}],Rhd};
- utf ->
- {test,Name,{f,Vf},Live,
- [CtxReg,{field_flags,Flags}],Rhd}
- end.
-
-build_skip_instr(Type, Vf, CtxReg, Live, SizeReg, Unit, Flags) ->
- {Format,Name} = case Type of
- utf8 -> {utf,bs_skip_utf8};
- utf16 -> {utf,bs_skip_utf16};
- utf32 -> {utf,bs_skip_utf32};
- _ -> {plain,bs_skip_bits2}
- end,
- case Format of
- plain ->
- {test,Name,{f,Vf},[CtxReg,SizeReg,Unit,{field_flags,Flags}]};
- utf ->
- {test,Name,{f,Vf},[CtxReg,Live,{field_flags,Flags}]}
- end.
-
-select_val(#k_val_clause{val=#k_tuple{es=Es},body=B,anno=#l{i=I,vdb=Vdb}},
- V, Vf, Bef, St0) ->
- {Eis,Int,St1} = select_extract_tuple(V, Es, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Vf, Int, St1),
- {length(Es),Eis ++ Bis,Aft,St2};
-select_val(#k_val_clause{val=Val0,body=B}, _V, Vf, Bef, St0) ->
- Val = case Val0 of
- #k_atom{val=Lit} -> Lit;
- #k_float{val=Lit} -> Lit;
- #k_int{val=Lit} -> Lit;
- #k_literal{val=Lit} -> Lit
- end,
- {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0),
- {Val,Bis,Aft,St1}.
-
-%% select_extract_tuple(Src, [V], I, Vdb, StackReg, State) ->
-%% {[E],StackReg,State}.
-%% Extract tuple elements, but only if they do not immediately die.
-
-select_extract_tuple(Src, Vs, I, Vdb, Bef, St) ->
- F = fun (#k_var{name=V}, {Int0,Elem}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I -> {[], {Int0,Elem+1}};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- Rsrc = fetch_var(Src, Int1),
- {[{get_tuple_element,Rsrc,Elem,fetch_reg(V, Reg1)}],
- {Int1,Elem+1}}
- end
- end,
- {Es,{Aft,_}} = flatmapfoldl(F, {Bef,0}, Vs),
- {Es,Aft,St}.
-
-select_map(Scs, V, Tf, Vf, Bef, St0) ->
- Reg = fetch_var(V, Bef),
- {Is,Aft,St1} =
- match_fmf(fun(#k_val_clause{val=#k_map{op=exact,es=Es},
- body=B,anno=#l{i=I,vdb=Vdb}}, Fail, St1) ->
- select_map_val(V, Es, B, Fail, I, Vdb, Bef, St1)
- end, Vf, St0, Scs),
- {[{test,is_map,{f,Tf},[Reg]}|Is],Aft,St1}.
-
-select_map_val(V, Es, B, Fail, I, Vdb, Bef, St0) ->
- {Eis,Int,St1} = select_extract_map(V, Es, Fail, I, Vdb, Bef, St0),
- {Bis,Aft,St2} = match_cg(B, Fail, Int, St1),
- {Eis++Bis,Aft,St2}.
-
-select_extract_map(_, [], _, _, _, Bef, St) -> {[],Bef,St};
-select_extract_map(Src, Vs, Fail, I, Vdb, Bef, St) ->
- %% First split the instruction flow
- %% We want one set of each
- %% 1) has_map_fields (no target registers)
- %% 2) get_map_elements (with target registers)
- %% Assume keys are term-sorted
- Rsrc = fetch_var(Src, Bef),
-
- {{HasKs,GetVs,HasVarKs,GetVarVs},Aft} =
- foldr(fun(#k_map_pair{key=#k_var{name=K},val=#k_var{name=V}},
- {{HasKsi,GetVsi,HasVarVsi,GetVarVsi},Int0}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I ->
- RK = fetch_var(K,Int0),
- {{HasKsi,GetVsi,[RK|HasVarVsi],GetVarVsi},Int0};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- RK = fetch_var(K,Int0),
- RV = fetch_reg(V,Reg1),
- {{HasKsi,GetVsi,HasVarVsi,[[RK,RV]|GetVarVsi]},Int1}
- end;
- (#k_map_pair{key=Key,val=#k_var{name=V}},
- {{HasKsi,GetVsi,HasVarVsi,GetVarVsi},Int0}) ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L =< I ->
- {{[atomic(Key)|HasKsi],GetVsi,HasVarVsi,GetVarVsi},Int0};
- _Other ->
- Reg1 = put_reg(V, Int0#sr.reg),
- Int1 = Int0#sr{reg=Reg1},
- {{HasKsi,[atomic(Key),fetch_reg(V, Reg1)|GetVsi],
- HasVarVsi,GetVarVsi},Int1}
- end
- end, {{[],[],[],[]},Bef}, Vs),
-
- Code = [{test,has_map_fields,{f,Fail},Rsrc,{list,HasKs}} || HasKs =/= []] ++
- [{test,has_map_fields,{f,Fail},Rsrc,{list,[K]}} || K <- HasVarKs] ++
- [{get_map_elements, {f,Fail},Rsrc,{list,GetVs}} || GetVs =/= []] ++
- [{get_map_elements, {f,Fail},Rsrc,{list,[K,V]}} || [K,V] <- GetVarVs],
- {Code, Aft, St}.
-
-
-select_extract_cons(Src, [#k_var{name=Hd},#k_var{name=Tl}], I, Vdb, Bef, St) ->
- Rsrc = fetch_var(Src, Bef),
- Int = clear_dead(Bef, I, Vdb),
- {{_,_,Lhd},{_,_,Ltl}} = {vdb_find(Hd, Vdb),vdb_find(Tl, Vdb)},
- case {Lhd =< I, Ltl =< I} of
- {true,true} ->
- %% Both dead.
- {[],Bef,St};
- {true,false} ->
- %% Head dead.
- Reg0 = put_reg(Tl, Bef#sr.reg),
- Aft = Int#sr{reg=Reg0},
- Rtl = fetch_reg(Tl, Reg0),
- {[{get_tl,Rsrc,Rtl}],Aft,St};
- {false,true} ->
- %% Tail dead.
- Reg0 = put_reg(Hd, Bef#sr.reg),
- Aft = Int#sr{reg=Reg0},
- Rhd = fetch_reg(Hd, Reg0),
- {[{get_hd,Rsrc,Rhd}],Aft,St};
- {false,false} ->
- %% Both used.
- Reg0 = put_reg(Tl, put_reg(Hd, Bef#sr.reg)),
- Aft = Bef#sr{reg=Reg0},
- Rhd = fetch_reg(Hd, Reg0),
- Rtl = fetch_reg(Tl, Reg0),
- {[{get_hd,Rsrc,Rhd},{get_tl,Rsrc,Rtl}],Aft,St}
- end.
-
-guard_clause_cg(#k_guard_clause{anno=#l{vdb=Vdb},guard=G,body=B}, Fail, Bef, St0) ->
- {Gis,Int,St1} = guard_cg(G, Fail, Vdb, Bef, St0),
- {Bis,Aft,St} = match_cg(B, Fail, Int, St1),
- {Gis ++ Bis,Aft,St}.
-
-%% guard_cg(Guard, Fail, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% A guard is a boolean expression of tests. Tests return true or
-%% false. A fault in a test causes the test to return false. Tests
-%% never return the boolean, instead we generate jump code to go to
-%% the correct exit point. Primops and tests all go to the next
-%% instruction on success or jump to a failure label.
-
-guard_cg(#k_protected{arg=Ts,ret=Rs,anno=#l{vdb=Pdb}}, Fail, _Vdb, Bef, St) ->
- protected_cg(Ts, Rs, Fail, Pdb, Bef, St);
-guard_cg(#k_test{anno=#l{i=I},op=Test0,args=As,inverted=Inverted},
- Fail, Vdb, Bef, St0) ->
- #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Test}} = Test0,
- case Inverted of
- false ->
- test_cg(Test, As, Fail, I, Vdb, Bef, St0);
- true ->
- {Psucc,St1} = new_label(St0),
- {Is,Aft,St2} = test_cg(Test, As, Psucc, I, Vdb, Bef, St1),
- {Is++[{jump,{f,Fail}},{label,Psucc}],Aft,St2}
- end;
-guard_cg(G, _Fail, Vdb, Bef, St) ->
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{G,Fail,Vdb,Bef}]),
- {Gis,Aft,St1} = cg(G, Vdb, Bef, St),
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Aft}]),
- {Gis,Aft,St1}.
-
-%% guard_cg_list([Kexpr], Fail, I, Vdb, StackReg, St) ->
-%% {[Ainstr],StackReg,St}.
-
-guard_cg_list(Kes, Fail, Vdb, Bef, St0) ->
- {Keis,{Aft,St1}} =
- flatmapfoldl(fun (Ke, {Inta,Sta}) ->
- {Keis,Intb,Stb} =
- guard_cg(Ke, Fail, Vdb, Inta, Sta),
- {Keis,{Intb,Stb}}
- end, {Bef,St0}, need_heap(Kes)),
- {Keis,Aft,St1}.
-
-%% protected_cg([Kexpr], [Ret], Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Do a protected. Protecteds without return values are just done
-%% for effect, the return value is not checked, success passes on to
-%% the next instruction and failure jumps to Fail. If there are
-%% return values then these must be set to 'false' on failure,
-%% control always passes to the next instruction.
-
-protected_cg(Ts, [], Fail, Vdb, Bef, St0) ->
- %% Protect these calls, revert when done.
- {Tis,Aft,St1} = guard_cg_list(Ts, Fail, Vdb, Bef, St0#cg{bfail=Fail}),
- {Tis,Aft,St1#cg{bfail=St0#cg.bfail}};
-protected_cg(Ts, Rs, _Fail, Vdb, Bef, St0) ->
- {Pfail,St1} = new_label(St0),
- {Psucc,St2} = new_label(St1),
- {Tis,Aft,St3} = guard_cg_list(Ts, Pfail, Vdb, Bef,
- St2#cg{bfail=Pfail}),
- %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Rs,I,Vdb,Aft}]),
- %% Set return values to false.
- Mis = [{move,{atom,false},fetch_var(V,Aft)}||#k_var{name=V} <- Rs],
- {Tis ++ [{jump,{f,Psucc}},
- {label,Pfail}] ++ Mis ++ [{label,Psucc}],
- Aft,St3#cg{bfail=St0#cg.bfail}}.
-
-%% test_cg(TestName, Args, Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Generate test instruction. Use explicit fail label here.
-
-test_cg(is_map, [A], Fail, I, Vdb, Bef, St) ->
- %% We must avoid creating code like this:
- %%
- %% move x(0) y(0)
- %% is_map Fail [x(0)]
- %% make_fun => x(0) %% Overwrite x(0)
- %% put_map_assoc y(0) ...
- %%
- %% The code is safe, but beam_validator does not understand that.
- %% Extending beam_validator to handle such (rare) code as the
- %% above would make it slower for all programs. Instead, change
- %% the code generator to always prefer the Y register for is_map()
- %% and put_map_assoc() instructions, ensuring that they use the
- %% same register.
- Arg = cg_reg_arg_prefer_y(A, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- {[{test,is_map,{f,Fail},[Arg]}],Aft,St};
-test_cg(is_boolean, [#k_atom{val=Val}], Fail, I, Vdb, Bef, St) ->
- Aft = clear_dead(Bef, I, Vdb),
- Is = case is_boolean(Val) of
- true -> [];
- false -> [{jump,{f,Fail}}]
- end,
- {Is,Aft,St};
-test_cg(is_map_key, As, Fail, I, Vdb, Bef, St) ->
- [Key,Map] = cg_reg_args(As, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- F = {f,Fail},
- {[{test,is_map,F,[Map]},{test,has_map_fields,F,Map,{list,[Key]}}],Aft,St};
-test_cg(Test, As, Fail, I, Vdb, Bef, St) ->
- Args = cg_reg_args(As, Bef),
- Aft = clear_dead(Bef, I, Vdb),
- {[beam_utils:bif_to_test(Test, Args, {f,Fail})],Aft,St}.
-
-%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,Aft,State}.
-%% This is a special flatmapfoldl for match code gen where we
-%% generate a "failure" label for each clause. The last clause uses
-%% an externally generated failure label, LastFail. N.B. We do not
-%% know or care how the failure labels are used.
-
-match_fmf(F, LastFail, St, [H]) ->
- F(H, LastFail, St);
-match_fmf(F, LastFail, St0, [H|T]) ->
- {Fail,St1} = new_label(St0),
- {R,Aft1,St2} = F(H, Fail, St1),
- {Rs,Aft2,St3} = match_fmf(F, LastFail, St2, T),
- {R ++ [{label,Fail}] ++ Rs,sr_merge(Aft1, Aft2),St3}.
-
-%% call_cg(Func, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% enter_cg(Func, [Arg], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% Call and enter first put the arguments into registers and save any
-%% other registers, then clean up and compress the stack and set the
-%% frame size. Finally the actual call is made. Call then needs the
-%% return values filled in.
-
-call_cg(#k_var{}=Var, As, Rs, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As++[Var], Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le),{call_fun,Arity}],Aft,
- need_stack_frame(St0)};
-call_cg(#k_remote{mod=Mod,name=Name}, As, Rs, Le, Vdb, Bef, St0)
- when is_record(Mod, k_var); is_record(Name, k_var) ->
- {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- St = need_stack_frame(St0),
- %%{Call,St1} = build_call(Func, Arity, St0),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le),{apply,Arity}],Aft,St};
-call_cg(Func, As, Rs, Le, Vdb, Bef, St0) ->
- case St0 of
- #cg{bfail=Fail} when Fail =/= 0 ->
- %% Inside a guard. The only allowed function call is to
- %% erlang:error/1,2. We will generate the following code:
- %%
- %% move {atom,ok} DestReg
- %% jump FailureLabel
- #k_remote{mod=#k_atom{val=erlang},
- name=#k_atom{val=error}} = Func, %Assertion.
- [#k_var{name=DestVar}] = Rs,
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- Reg = put_reg(DestVar, Int0#sr.reg),
- Int = Int0#sr{reg=Reg},
- Dst = fetch_reg(DestVar, Reg),
- {[{move,{atom,ok},Dst},{jump,{f,Fail}}],
- clear_dead(Int, Le#l.i, Vdb),St0};
- #cg{} ->
- %% Ordinary function call in a function body.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- %% Put return values in registers.
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Call,St1} = build_call(Func, Arity, St0),
- {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [line(Le)|Call],Aft,St1}
- end.
-
-build_call(#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val='!'}}, 2, St0) ->
- {[send],need_stack_frame(St0)};
-build_call(#k_remote{mod=#k_atom{val=Mod},name=#k_atom{val=Name}}, Arity, St0) ->
- {[{call_ext,Arity,{extfunc,Mod,Name,Arity}}],need_stack_frame(St0)};
-build_call(#k_local{name=Name}, Arity, St0) when is_atom(Name) ->
- {Lbl,St1} = local_func_label(Name, Arity, need_stack_frame(St0)),
- {[{call,Arity,{f,Lbl}}],St1}.
-
-free_dead(#sr{stk=Stk0}=Aft) ->
- {Instr,Stk} = free_dead(Stk0, 0, [], []),
- {Instr,Aft#sr{stk=Stk}}.
-
-free_dead([dead|Stk], Y, Instr, StkAcc) ->
- %% Note: kill/1 is equivalent to init/1 (translated by beam_asm).
- %% We use kill/1 to help further optimisation passes.
- free_dead(Stk, Y+1, [{kill,{yy,Y}}|Instr], [free|StkAcc]);
-free_dead([Any|Stk], Y, Instr, StkAcc) ->
- free_dead(Stk, Y+1, Instr, [Any|StkAcc]);
-free_dead([], _, Instr, StkAcc) -> {Instr,reverse(StkAcc)}.
-
-enter_cg(#k_var{} = Var, As, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As++[Var], Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Sis ++ [line(Le),{call_fun,Arity},return],
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- need_stack_frame(St0)};
-enter_cg(#k_remote{mod=Mod,name=Name}, As, Le, Vdb, Bef, St0)
- when is_record(Mod, k_var); is_record(Name, k_var) ->
- {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- St = need_stack_frame(St0),
- {Sis ++ [line(Le),{apply_only,Arity}],
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- St};
-enter_cg(Func, As, Le, Vdb, Bef, St0) ->
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- %% Build complete code and final stack/register state.
- Arity = length(As),
- {Call,St1} = build_enter(Func, Arity, St0),
- Line = enter_line(Func, Arity, Le),
- {Sis ++ Line ++ Call,
- clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
- St1}.
-
-build_enter(#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val='!'}}, 2, St0) ->
- {[send,return],need_stack_frame(St0)};
-build_enter(#k_remote{mod=#k_atom{val=Mod},name=#k_atom{val=Name}}, Arity, St0) ->
- St1 = case trap_bif(Mod, Name, Arity) of
- true -> need_stack_frame(St0);
- false -> St0
- end,
- {[{call_ext_only,Arity,{extfunc,Mod,Name,Arity}}],St1};
-build_enter(#k_local{name=Name}, Arity, St0) when is_atom(Name) ->
- {Lbl,St1} = local_func_label(Name, Arity, St0),
- {[{call_only,Arity,{f,Lbl}}],St1}.
-
-enter_line(#k_remote{mod=#k_atom{val=Mod},name=#k_atom{val=Name}}, Arity, Le) ->
- case erl_bifs:is_safe(Mod, Name, Arity) of
- false ->
- %% Tail-recursive call, possibly to a BIF.
- %% We'll need a line instruction in case the
- %% BIF call fails.
- [line(Le)];
- true ->
- %% Call to a safe BIF. Since it cannot fail,
- %% we don't need any line instruction here.
- []
- end;
-enter_line(_, _, _) ->
- %% Tail-recursive call to a local function. A line
- %% instruction will not be useful.
- [].
-
-%% local_func_label(Name, Arity, State) -> {Label,State'}
-%% local_func_label({Name,Arity}, State) -> {Label,State'}
-%% Get the function entry label for a local function.
-
-local_func_label(Name, Arity, St) ->
- local_func_label({Name,Arity}, St).
-
-local_func_label(Key, #cg{functable=Map}=St0) ->
- case Map of
- #{Key := Label} -> {Label,St0};
- _ ->
- {Label,St} = new_label(St0),
- {Label,St#cg{functable=Map#{Key => Label}}}
- end.
-
-%% need_stack_frame(State) -> State'
-%% Make a note in the state that this function will need a stack frame.
-
-need_stack_frame(#cg{need_frame=true}=St) -> St;
-need_stack_frame(St) -> St#cg{need_frame=true}.
-
-%% trap_bif(Mod, Name, Arity) -> true|false
-%% Trap bifs that need a stack frame.
-
-trap_bif(erlang, link, 1) -> true;
-trap_bif(erlang, unlink, 1) -> true;
-trap_bif(erlang, monitor_node, 2) -> true;
-trap_bif(erlang, group_leader, 2) -> true;
-trap_bif(erlang, exit, 2) -> true;
-trap_bif(_, _, _) -> false.
-
-%% bif_cg(#k_bif{}, Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-%% Generate code a BIF.
-
-bif_cg(#k_bif{op=#k_internal{name=Name},args=As,ret=Rs}, Le, Vdb, Bef, St) ->
- internal_cg(Name, As, Rs, Le, Vdb, Bef, St);
-bif_cg(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}},
- args=As,ret=Rs}, Le, Vdb, Bef, St) ->
- Ar = length(As),
- case is_gc_bif(Name, Ar) of
- false ->
- bif_cg(Name, As, Rs, Le, Vdb, Bef, St);
- true ->
- gc_bif_cg(Name, As, Rs, Le, Vdb, Bef, St)
- end.
-
-%% internal_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-internal_cg(bs_context_to_binary=Instr, [Src0], [], Le, Vdb, Bef, St0) ->
- [Src] = cg_reg_args([Src0], Bef),
- {[{Instr,Src}],clear_dead(Bef, Le#l.i, Vdb), St0};
-internal_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) ->
- [New,Tuple,{integer,Index1}] = cg_reg_args([New0,Tuple0,Index0], Bef),
- Index = Index1-1,
- {[{set_tuple_element,New,Tuple,Index}],
- clear_dead(Bef, Le#l.i, Vdb), St0};
-internal_cg(make_fun, [Func0,Arity0|As], Rs, Le, Vdb, Bef, St0) ->
- %% This behaves more like a function call.
- #k_atom{val=Func} = Func0,
- #k_int{val=Arity} = Arity0,
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {FuncLbl,St1} = local_func_label(Func, Arity, St0),
- MakeFun = {make_fun2,{f,FuncLbl},0,0,length(As)},
- {Sis ++ [MakeFun],
- clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),
- St1};
-internal_cg(bs_init_writable=I, As, Rs, Le, Vdb, Bef, St) ->
- %% This behaves like a function call.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {Sis++[I],clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),St};
-internal_cg(build_stacktrace=I, As, Rs, Le, Vdb, Bef, St) ->
- %% This behaves like a function call.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {Sis++[I],clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),St};
-internal_cg(raise, As, Rs, Le, Vdb, Bef, St) ->
- %% raise can be treated like a guard BIF.
- bif_cg(raise, As, Rs, Le, Vdb, Bef, St);
-internal_cg(guard_error, [ExitCall], _Rs, Le, Vdb, Bef, St) ->
- %% A call an exit BIF from inside a #k_guard_match{}.
- %% Generate a standard call, but leave the register descriptors
- %% alone, effectively pretending that there was no call.
- #k_call{op=#k_remote{mod=#k_atom{val=Mod},name=#k_atom{val=Name}},
- args=As} = ExitCall,
- Arity = length(As),
- {Ms,_} = cg_call_args(As, Bef, Le#l.i, Vdb),
- Call = {call_ext,Arity,{extfunc,Mod,Name,Arity}},
- Is = Ms++[line(Le),Call],
- {Is,Bef,St};
-internal_cg(raw_raise=I, As, Rs, Le, Vdb, Bef, St) ->
- %% This behaves like a function call.
- {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb),
- Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
- {Sis++[I],clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb),St}.
-
-%% bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-bif_cg(Bif, As, [#k_var{name=V}], Le, Vdb, Bef, St0) ->
- Ars = cg_reg_args(As, Bef),
-
- %% If we are inside a catch and in a body (not in guard) and the
- %% BIF may fail, we must save everything that will be alive after
- %% the catch (because the code after the code assumes that all
- %% variables that are live are stored on the stack).
- %%
- %% Currently, we are somewhat pessimistic in
- %% that we save any variable that will be live after this BIF call.
-
- MayFail = not erl_bifs:is_safe(erlang, Bif, length(As)),
- {Sis,Int0} =
- case MayFail of
- true ->
- maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0);
- false ->
- {[],Bef}
- end,
- Int1 = clear_dead(Int0, Le#l.i, Vdb),
- Reg = put_reg(V, Int1#sr.reg),
- Int = Int1#sr{reg=Reg},
- Dst = fetch_reg(V, Reg),
- BifFail = {f,St0#cg.bfail},
- %% We need a line instructions for BIFs that may fail in a body.
- Line = case BifFail of
- {f,0} when MayFail ->
- [line(Le)];
- _ ->
- []
- end,
- {Sis++Line++[{bif,Bif,BifFail,Ars,Dst}],
- clear_dead(Int, Le#l.i, Vdb), St0}.
-
-
-%% gc_bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) ->
-%% {[Ainstr],StackReg,State}.
-
-gc_bif_cg(Bif, As, [#k_var{name=V}], Le, Vdb, Bef, St0) ->
- Ars = cg_reg_args(As, Bef),
-
- %% If we are inside a catch and in a body (not in guard) and the
- %% BIF may fail, we must save everything that will be alive after
- %% the catch (because the code after the code assumes that all
- %% variables that are live are stored on the stack).
- %%
- %% Currently, we are somewhat pessimistic in
- %% that we save any variable that will be live after this BIF call.
-
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
-
- Int1 = clear_dead(Int0, Le#l.i, Vdb),
- Reg = put_reg(V, Int1#sr.reg),
- Int = Int1#sr{reg=Reg},
- Dst = fetch_reg(V, Reg),
- BifFail = {f,St0#cg.bfail},
- Line = case BifFail of
- {f,0} -> [line(Le)];
- {f,_} -> []
- end,
- {Sis++Line++[{gc_bif,Bif,BifFail,max_reg(Bef#sr.reg),Ars,Dst}],
- clear_dead(Int, Le#l.i, Vdb), St0}.
-
-%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs,
-%% [Ret], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-
-recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St0) ->
- {Sis,Int0} = adjust_stack(Bef, Le#l.i, Le#l.i, Vdb),
- Int1 = Int0#sr{reg=clear_regs(Int0#sr.reg)},
- %% Get labels.
- {Rl,St1} = new_label(St0),
- {Tl,St2} = new_label(St1),
- {Bl,St3} = new_label(St2),
- St4 = St3#cg{break=Bl,recv=Rl}, %Set correct receive labels
- {Ris,Raft,St5} = cg_recv_mesg(Rvar, Rm, Tl, Int1, St4),
- {Wis,Taft,St6} = cg_recv_wait(Te, Tes, Le#l.i, Int1, St5),
- Int2 = sr_merge(Raft, Taft), %Merge stack/registers
- Reg = load_vars(Rs, Int2#sr.reg),
- {Sis ++ [line(Le)] ++ Ris ++ [{label,Tl}] ++ Wis ++ [{label,Bl}],
- clear_dead(Int2#sr{reg=Reg}, Le#l.i, Vdb),
- St6#cg{break=St0#cg.break,recv=St0#cg.recv}}.
-
-%% cg_recv_mesg( ) -> {[Ainstr],Aft,St}.
-
-cg_recv_mesg(#k_var{name=R}, Rm, Tl, Bef, St0) ->
- Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Ret = fetch_reg(R, Int0#sr.reg),
- %% Int1 = clear_dead(Int0, I, Rm#l.vdb),
- Int1 = Int0,
- {Mis,Int2,St1} = match_cg(Rm, none, Int1, St0),
- {[{label,St1#cg.recv},{loop_rec,{f,Tl},Ret}|Mis],Int2,St1}.
-
-%% cg_recv_wait(Te, Tes, I, Vdb, Int2, St3) -> {[Ainstr],Aft,St}.
-
-cg_recv_wait(#k_atom{val=infinity}, #cg_block{anno=Le,es=Tes}, I, Bef, St0) ->
- %% We know that the 'after' body will never be executed.
- %% But to keep the stack and register information up to date,
- %% we will generate the code for the 'after' body, and then discard it.
- Int1 = clear_dead(Bef, I, Le#l.vdb),
- {_,Int2,St1} = cg_block(Tes, Le#l.vdb,
- Int1#sr{reg=clear_regs(Int1#sr.reg)}, St0),
- {[{wait,{f,St1#cg.recv}}],Int2,St1};
-cg_recv_wait(#k_int{val=0}, #cg_block{anno=Le,es=Tes}, _I, Bef, St0) ->
- {Tis,Int,St1} = cg_block(Tes, Le#l.vdb, Bef, St0),
- {[timeout|Tis],Int,St1};
-cg_recv_wait(Te, #cg_block{anno=Le,es=Tes}, I, Bef, St0) ->
- Reg = cg_reg_arg(Te, Bef),
- %% Must have empty registers here! Bug if anything in registers.
- Int0 = clear_dead(Bef, I, Le#l.vdb),
- {Tis,Int,St1} = cg_block(Tes, Le#l.vdb,
- Int0#sr{reg=clear_regs(Int0#sr.reg)}, St0),
- {[{wait_timeout,{f,St1#cg.recv},Reg},timeout] ++ Tis,Int,St1}.
-
-%% recv_next_cg(Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-%% Use adjust stack to clear stack, but only need it for Aft.
-
-recv_next_cg(Le, Vdb, Bef, St) ->
- {Sis,Aft} = adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb),
- {[{loop_rec_end,{f,St#cg.recv}}] ++ Sis,Aft,St}. %Joke
-
-%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret],
-%% Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}.
-
-try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0), %Body label
- {H,St2} = new_label(St1), %Handler label
- {E,St3} = new_label(St2), %End label
- #l{i=TryTag} = get_kanno(Ta),
- Int1 = Bef#sr{stk=put_catch(TryTag, Bef#sr.stk)},
- TryReg = fetch_stack({catch_tag,TryTag}, Int1#sr.stk),
- {Ais,Int2,St4} = cg(Ta, Vdb, Int1, St3#cg{break=B,in_catch=true}),
- Int3 = Int2#sr{stk=drop_catch(TryTag, Int2#sr.stk)},
- St5 = St4#cg{break=E,in_catch=St3#cg.in_catch},
- {Bis,Baft,St6} = cg(Tb, Vdb, Int3#sr{reg=load_vars(Vs, Int3#sr.reg)}, St5),
- {His,Haft,St7} = cg(Th, Vdb, Int3#sr{reg=load_vars(Evs, Int3#sr.reg)}, St6),
- Int4 = sr_merge(Baft, Haft), %Merge stack/registers
- Aft = Int4#sr{reg=load_vars(Rs, Int4#sr.reg)},
- {[{'try',TryReg,{f,H}}] ++ Ais ++
- [{label,B},{try_end,TryReg}] ++ Bis ++
- [{label,H},{try_case,TryReg}] ++ His ++
- [{label,E}],
- clear_dead(Aft, Le#l.i, Vdb),
- St7#cg{break=St0#cg.break}}.
-
-try_enter_cg(Ta, Vs, Tb, Evs, Th, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0), %Body label
- {H,St2} = new_label(St1), %Handler label
- #l{i=TryTag} = get_kanno(Ta),
- Int1 = Bef#sr{stk=put_catch(TryTag, Bef#sr.stk)},
- TryReg = fetch_stack({catch_tag,TryTag}, Int1#sr.stk),
- {Ais,Int2,St3} = cg(Ta, Vdb, Int1, St2#cg{break=B,in_catch=true}),
- Int3 = Int2#sr{stk=drop_catch(TryTag, Int2#sr.stk)},
- St4 = St3#cg{in_catch=St2#cg.in_catch},
- {Bis,Baft,St5} = cg(Tb, Vdb, Int3#sr{reg=load_vars(Vs, Int3#sr.reg)}, St4),
- {His,Haft,St6} = cg(Th, Vdb, Int3#sr{reg=load_vars(Evs, Int3#sr.reg)}, St5),
- Int4 = sr_merge(Baft, Haft), %Merge stack/registers
- Aft = Int4,
- {[{'try',TryReg,{f,H}}] ++ Ais ++
- [{label,B},{try_end,TryReg}] ++ Bis ++
- [{label,H},{try_case,TryReg}] ++ His,
- clear_dead(Aft, Le#l.i, Vdb),
- St6#cg{break=St0#cg.break}}.
-
-%% catch_cg(CatchBlock, Ret, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-
-catch_cg(#cg_block{es=C}, #k_var{name=R}, Le, Vdb, Bef, St0) ->
- {B,St1} = new_label(St0),
- CatchTag = Le#l.i,
- Int1 = Bef#sr{stk=put_catch(CatchTag, Bef#sr.stk)},
- CatchReg = fetch_stack({catch_tag,CatchTag}, Int1#sr.stk),
- {Cis,Int2,St2} = cg_block(C, Le#l.vdb, Int1,
- St1#cg{break=B,in_catch=true}),
- [] = Int2#sr.reg, %Assertion.
- Aft = Int2#sr{reg=[{0,R}],stk=drop_catch(CatchTag, Int2#sr.stk)},
- {[{'catch',CatchReg,{f,B}}] ++ Cis ++
- [{label,B},{catch_end,CatchReg}],
- clear_dead(Aft, Le#l.i, Vdb),
- St2#cg{break=St1#cg.break,in_catch=St1#cg.in_catch}}.
-
-%% put_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% We have to be careful how a 'put' works. First the structure is
-%% built, then it is filled and finally things can be cleared. The
-%% annotation must reflect this and make sure that the return
-%% variable is allocated first.
-%%
-%% put_list and put_map are atomic instructions, both of
-%% which can safely resuse one of the source registers as target.
-
-put_cg([#k_var{name=R}], #k_cons{hd=Hd,tl=Tl}, Le, Vdb, Bef, St) ->
- [S1,S2] = cg_reg_args([Hd,Tl], Bef),
- Int0 = clear_dead(Bef, Le#l.i, Vdb),
- Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)},
- Ret = fetch_reg(R, Int1#sr.reg),
- {[{put_list,S1,S2,Ret}], Int1, St};
-put_cg([#k_var{name=R}], #k_binary{segs=Segs}, Le, Vdb, Bef,
- #cg{bfail=Bfail}=St) ->
- %% At run-time, binaries are constructed in three stages:
- %% 1) First the size of the binary is calculated.
- %% 2) Then the binary is allocated.
- %% 3) Then each field in the binary is constructed.
- %% For simplicity, we use the target register to also hold the
- %% size of the binary. Therefore the target register must *not*
- %% be one of the source registers.
-
- %% First allocate the target register.
- Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Target = fetch_reg(R, Int0#sr.reg),
-
- %% Also allocate a scratch register for size calculations.
- Temp = find_scratch_reg(Int0#sr.reg),
-
- %% First generate the code that constructs each field.
- Fail = {f,Bfail},
- PutCode = cg_bin_put(Segs, Fail, Bef),
- {Sis,Int1} = maybe_adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb, St),
- MaxRegs = max_reg(Bef#sr.reg),
- Aft = clear_dead(Int1, Le#l.i, Vdb),
-
- %% Now generate the complete code for constructing the binary.
- Code = cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Le#l.a),
- {Sis++Code,Aft,St};
-
-%% Map: single variable key.
-put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,
- es=[#k_map_pair{key=#k_var{}=K,val=V}]},
- Le, Vdb, Bef, St0) ->
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
-
- SrcReg = cg_reg_arg_prefer_y(Map, Int0),
- Line = line(Le#l.a),
-
- List = [cg_reg_arg(K,Int0),cg_reg_arg(V,Int0)],
-
- Live = max_reg(Bef#sr.reg),
-
- %% The target register can reuse one of the source registers.
- Aft0 = clear_dead(Int0, Le#l.i, Vdb),
- Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
- Target = fetch_reg(R, Aft#sr.reg),
-
- {Is,St1} = put_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
- {Sis++Is,Aft,St1};
-
-%% Map: (possibly) multiple literal keys.
-put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,es=Es}, Le, Vdb, Bef, St0) ->
-
- %% assert key literals
- [] = [Var || #k_map_pair{key=#k_var{}=Var} <- Es],
-
- {Sis,Int0} = maybe_adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb, St0),
- SrcReg = cg_reg_arg_prefer_y(Map, Int0),
- Line = line(Le#l.a),
-
- %% fetch registers for values to be put into the map
- List = flatmap(fun(#k_map_pair{key=K,val=V}) ->
- [atomic(K),cg_reg_arg(V, Int0)]
- end, Es),
-
- Live = max_reg(Bef#sr.reg),
-
- %% The target register can reuse one of the source registers.
- Aft0 = clear_dead(Int0, Le#l.i, Vdb),
- Aft = Aft0#sr{reg=put_reg(R, Aft0#sr.reg)},
- Target = fetch_reg(R, Aft#sr.reg),
-
- {Is,St1} = put_cg_map(Line, Op, SrcReg, Target, Live, List, St0),
- {Sis++Is,Aft,St1};
-
-%% Everything else.
-put_cg([#k_var{name=R}], Con, Le, Vdb, Bef, St) ->
- %% Find a place for the return register first.
- Int = Bef#sr{reg=put_reg(R, Bef#sr.reg)},
- Ret = fetch_reg(R, Int#sr.reg),
- Ais = case Con of
- #k_tuple{es=Es} ->
- [{put_tuple,length(Es),Ret}] ++ cg_build_args(Es, Bef);
- Other ->
- [{move,cg_reg_arg(Other, Int),Ret}]
- end,
- {Ais,clear_dead(Int, Le#l.i, Vdb),St}.
-
-
-put_cg_map(Line, Op0, SrcReg, Target, Live, List, St0) ->
- Bfail = St0#cg.bfail,
- Fail = {f,St0#cg.bfail},
- Op = case Op0 of
- assoc -> put_map_assoc;
- exact -> put_map_exact
- end,
- {OkLbl,St1} = new_label(St0),
- {BadLbl,St2} = new_label(St1),
- Is = if
- Bfail =:= 0 orelse Op =:= put_map_assoc ->
- [Line,{Op,{f,0},SrcReg,Target,Live,{list,List}}];
- true ->
- %% Ensure that Target is always set, even if
- %% the map update operation fails. That is necessary
- %% because Target may be included in a test_heap
- %% instruction.
- [Line,
- {Op,{f,BadLbl},SrcReg,Target,Live,{list,List}},
- {jump,{f,OkLbl}},
- {label,BadLbl},
- {move,{atom,ok},Target},
- {jump,Fail},
- {label,OkLbl}]
- end,
- {Is,St2}.
-
-%%%
-%%% Code generation for constructing binaries.
-%%%
-
-cg_binary([{bs_put_binary,Fail,{atom,all},U,_Flags,Src}|PutCode],
- Target, Temp, Fail, MaxRegs, Anno) ->
- Line = line(Anno),
- Live = cg_live(Target, MaxRegs),
- SzCode = cg_bitstr_size(PutCode, Target, Temp, Fail, Live),
- BinFlags = {field_flags,[]},
- Code = [Line|SzCode] ++
- [case member(single_use, Anno) of
- true ->
- {bs_private_append,Fail,Target,U,Src,BinFlags,Target};
- false ->
- {bs_append,Fail,Target,0,MaxRegs,U,Src,BinFlags,Target}
- end] ++ PutCode,
- cg_bin_opt(Code);
-cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Anno) ->
- Line = line(Anno),
- Live = cg_live(Target, MaxRegs),
- {InitOp,SzCode} = cg_binary_size(PutCode, Target, Temp, Fail, Live),
-
- Code = [Line|SzCode] ++ [{InitOp,Fail,Target,0,MaxRegs,
- {field_flags,[]},Target}|PutCode],
- cg_bin_opt(Code).
-
-cg_live({x,X}, MaxRegs) when X =:= MaxRegs -> MaxRegs+1;
-cg_live({x,X}, MaxRegs) when X < MaxRegs -> MaxRegs.
-
-%% Generate code that calculate the size of the bitstr to be
-%% built in BITS.
-
-cg_bitstr_size(PutCode, Target, Temp, Fail, Live) ->
- {Bits,Es} = cg_bitstr_size_1(PutCode, 0, []),
- reverse(cg_gen_binsize(Es, Target, Temp, Fail, Live,
- [{move,{integer,Bits},Target}])).
-
-cg_bitstr_size_1([{bs_put_utf8,_,_,Src}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits, [{'*',{bs_utf8_size,Src},8}|Acc]);
-cg_bitstr_size_1([{bs_put_utf16,_,_,Src}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits, [{'*',{bs_utf16_size,Src},8}|Acc]);
-cg_bitstr_size_1([{bs_put_utf32,_,_,_}|Next], Bits, Acc) ->
- cg_bitstr_size_1(Next, Bits+32, Acc);
-cg_bitstr_size_1([{_,_,S,U,_,Src}|Next], Bits, Acc) ->
- case S of
- {integer,N} -> cg_bitstr_size_1(Next, Bits+N*U, Acc);
- {atom,all} -> cg_bitstr_size_1(Next, Bits, [{bit_size,Src}|Acc]);
- _ when U =:= 1 -> cg_bitstr_size_1(Next, Bits, [S|Acc]);
- _ -> cg_bitstr_size_1(Next, Bits, [{'*',S,U}|Acc])
- end;
-cg_bitstr_size_1([], Bits, Acc) -> {Bits,Acc}.
-
-%% Generate code that calculate the size of the bitstr to be
-%% built in BYTES or BITS (depending on what is easiest).
-
-cg_binary_size(PutCode, Target, Temp, Fail, Live) ->
- {InitInstruction,Szs} = cg_binary_size_1(PutCode, 0, []),
- SizeExpr = reverse(cg_gen_binsize(Szs, Target, Temp, Fail, Live, [{move,{integer,0},Target}])),
- {InitInstruction,SizeExpr}.
-
-cg_binary_size_1([{bs_put_utf8,_Fail,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits, [{8,{bs_utf8_size,Src}}|Acc]);
-cg_binary_size_1([{bs_put_utf16,_Fail,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits, [{8,{bs_utf16_size,Src}}|Acc]);
-cg_binary_size_1([{bs_put_utf32,_Fail,_Flags,_Src}|T], Bits, Acc) ->
- cg_binary_size_1(T, Bits+32, Acc);
-cg_binary_size_1([{_Put,_Fail,S,U,_Flags,Src}|T], Bits, Acc) ->
- cg_binary_size_2(S, U, Src, T, Bits, Acc);
-cg_binary_size_1([], Bits, Acc) ->
- Bytes = Bits div 8,
- RemBits = Bits rem 8,
- Sizes0 = sort([{1,{integer,RemBits}},{8,{integer,Bytes}}|Acc]),
- Sizes = filter(fun({_,{integer,0}}) -> false;
- (_) -> true end, Sizes0),
- case Sizes of
- [{1,_}|_] ->
- {bs_init_bits,cg_binary_bytes_to_bits(Sizes, [])};
- [{8,_}|_] ->
- {bs_init2,[E || {8,E} <- Sizes]};
- [] ->
- {bs_init_bits,[]}
- end.
-
-cg_binary_size_2({integer,N}, U, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits+N*U, Acc);
-cg_binary_size_2({atom,all}, U, E, Next, Bits, Acc) ->
- if
- U rem 8 =:= 0 ->
- cg_binary_size_1(Next, Bits, [{8,{byte_size,E}}|Acc]);
- true ->
- cg_binary_size_1(Next, Bits, [{1,{bit_size,E}}|Acc])
- end;
-cg_binary_size_2(Reg, 1, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{1,Reg}|Acc]);
-cg_binary_size_2(Reg, 8, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{8,Reg}|Acc]);
-cg_binary_size_2(Reg, U, _, Next, Bits, Acc) ->
- cg_binary_size_1(Next, Bits, [{1,{'*',Reg,U}}|Acc]).
-
-cg_binary_bytes_to_bits([{8,{integer,N}}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{integer,8*N}|Acc]);
-cg_binary_bytes_to_bits([{8,{byte_size,Reg}}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{bit_size,Reg}|Acc]);
-cg_binary_bytes_to_bits([{8,Reg}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [{'*',Reg,8}|Acc]);
-cg_binary_bytes_to_bits([{1,Sz}|T], Acc) ->
- cg_binary_bytes_to_bits(T, [Sz|Acc]);
-cg_binary_bytes_to_bits([], Acc) ->
- cg_binary_bytes_to_bits_1(sort(Acc)).
-
-cg_binary_bytes_to_bits_1([{integer,I},{integer,J}|T]) ->
- cg_binary_bytes_to_bits_1([{integer,I+J}|T]);
-cg_binary_bytes_to_bits_1([H|T]) ->
- [H|cg_binary_bytes_to_bits_1(T)];
-cg_binary_bytes_to_bits_1([]) -> [].
-
-cg_gen_binsize([{'*',{bs_utf8_size,Src},B}|T], Target, Temp, Fail, Live, Acc) ->
- Size = {bs_utf8_size,Fail,Src,Temp},
- Add = {bs_add,Fail,[Target,Temp,B],Target},
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [Add,Size|Acc]);
-cg_gen_binsize([{'*',{bs_utf16_size,Src},B}|T], Target, Temp, Fail, Live, Acc) ->
- Size = {bs_utf16_size,Fail,Src,Temp},
- Add = {bs_add,Fail,[Target,Temp,B],Target},
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [Add,Size|Acc]);
-cg_gen_binsize([{'*',A,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [{bs_add,Fail,[Target,A,B],Target}|Acc]);
-cg_gen_binsize([{bit_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{gc_bif,bit_size,Fail,Live,[B],Temp}|Acc]);
-cg_gen_binsize([{byte_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{gc_bif,byte_size,Fail,Live,[B],Temp}|Acc]);
-cg_gen_binsize([{bs_utf8_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{bs_utf8_size,Fail,B,Temp}|Acc]);
-cg_gen_binsize([{bs_utf16_size,B}|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize([Temp|T], Target, Temp, Fail, Live,
- [{bs_utf16_size,Fail,B,Temp}|Acc]);
-cg_gen_binsize([E0|T], Target, Temp, Fail, Live, Acc) ->
- cg_gen_binsize(T, Target, Temp, Fail, Live,
- [{bs_add,Fail,[Target,E0,1],Target}|Acc]);
-cg_gen_binsize([], _, _, _, _, Acc) -> Acc.
-
-
-%% cg_bin_opt(Code0) -> Code
-%% Optimize the size calculations for binary construction.
-
-cg_bin_opt([{move,S1,{x,X}=D},{gc_bif,Op,Fail,Live0,As,Dst}|Is]) ->
- Live = if
- X + 1 =:= Live0 -> X;
- true -> Live0
- end,
- [{gc_bif,Op,Fail,Live,As,D}|cg_bin_opt([{move,S1,Dst}|Is])];
-cg_bin_opt([{move,_,_}=I1,{Op,_,_,_}=I2|Is])
- when Op =:= bs_utf8_size orelse Op =:= bs_utf16_size ->
- [I2|cg_bin_opt([I1|Is])];
-cg_bin_opt([{bs_add,_,[{integer,0},Src,1],Dst}|Is]) ->
- cg_bin_opt_1([{move,Src,Dst}|Is]);
-cg_bin_opt([{bs_add,_,[Src,{integer,0},_],Dst}|Is]) ->
- cg_bin_opt_1([{move,Src,Dst}|Is]);
-cg_bin_opt(Is) ->
- cg_bin_opt_1(Is).
-
-cg_bin_opt_1([{move,Size,D},{bs_append,Fail,D,Extra,Regs,U,Bin,Flags,D}|Is]) ->
- [{bs_append,Fail,Size,Extra,Regs,U,Bin,Flags,D}|cg_bin_opt(Is)];
-cg_bin_opt_1([{move,Size,D},{bs_private_append,Fail,D,U,Bin,Flags,D}|Is]) ->
- [{bs_private_append,Fail,Size,U,Bin,Flags,D}|cg_bin_opt(Is)];
-cg_bin_opt_1([{move,Size,D},{Op,Fail,D,Extra,Regs,Flags,D}|Is])
- when Op =:= bs_init2; Op =:= bs_init_bits ->
- Bytes = case Size of
- {integer,Int} -> Int;
- _ -> Size
- end,
- [{Op,Fail,Bytes,Extra,Regs,Flags,D}|cg_bin_opt(Is)];
-cg_bin_opt_1([{move,S1,D},{bs_add,Fail,[D,S2,U],Dst}|Is]) ->
- cg_bin_opt([{bs_add,Fail,[S1,S2,U],Dst}|Is]);
-cg_bin_opt_1([{move,S1,D},{bs_add,Fail,[S2,D,U],Dst}|Is]) ->
- cg_bin_opt([{bs_add,Fail,[S2,S1,U],Dst}|Is]);
-cg_bin_opt_1([I|Is]) ->
- [I|cg_bin_opt(Is)];
-cg_bin_opt_1([]) ->
- [].
-
-cg_bin_put(#k_bin_seg{size=S0,unit=U,type=T,flags=Fs,seg=E0,next=Next},
- Fail, Bef) ->
- S1 = cg_reg_arg(S0, Bef),
- E1 = cg_reg_arg(E0, Bef),
- {Format,Op} = case T of
- integer -> {plain,bs_put_integer};
- utf8 -> {utf,bs_put_utf8};
- utf16 -> {utf,bs_put_utf16};
- utf32 -> {utf,bs_put_utf32};
- binary -> {plain,bs_put_binary};
- float -> {plain,bs_put_float}
- end,
- case Format of
- plain ->
- [{Op,Fail,S1,U,{field_flags,Fs},E1}|cg_bin_put(Next, Fail, Bef)];
- utf ->
- [{Op,Fail,{field_flags,Fs},E1}|cg_bin_put(Next, Fail, Bef)]
- end;
-cg_bin_put(#k_bin_end{}, _, _) -> [].
-
-cg_build_args(As, Bef) ->
- [{put,cg_reg_arg(A, Bef)} || A <- As].
-
-%% return_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% break_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}.
-%% These are very simple, just put return/break values in registers
-%% from 0, then return/break. Use the call setup to clean up stack,
-%% but must clear registers to ensure sr_merge works correctly.
-
-return_cg(Rs, Le, Vdb, Bef, St) ->
- {Ms,Int} = cg_setup_call(Rs, Bef, Le#l.i, Vdb),
- {Ms ++ [return],Int#sr{reg=clear_regs(Int#sr.reg)},St}.
-
-break_cg(Bs, Le, Vdb, Bef, St) ->
- {Ms,Int} = cg_setup_call(Bs, Bef, Le#l.i, Vdb),
- {Ms ++ [{jump,{f,St#cg.break}}],
- Int#sr{reg=clear_regs(Int#sr.reg)},St}.
-
-guard_break_cg(Bs, #l{i=I}, Vdb, #sr{reg=Reg0}=Bef, St) ->
- #sr{reg=Reg1} = Int = clear_dead(Bef, I, Vdb),
- Reg2 = trim_free(Reg1),
- NumLocked = length(Reg2),
- Moves0 = gen_moves(Bs, Bef, NumLocked, []),
- Moves = order_moves(Moves0, find_scratch_reg(Reg0)),
- {BreakVars,_} = mapfoldl(fun(_, RegNum) ->
- {{RegNum,gbreakvar},RegNum+1}
- end, length(Reg2), Bs),
- Reg = Reg2 ++ BreakVars,
- Aft = Int#sr{reg=Reg},
- {Moves ++ [{jump,{f,St#cg.break}}],Aft,St}.
-
-%% cg_reg_arg(Arg0, Info) -> Arg
-%% cg_reg_args([Arg0], Info) -> [Arg]
-%% Convert argument[s] into registers. Literal values are returned unchanged.
-
-cg_reg_args(As, Bef) -> [cg_reg_arg(A, Bef) || A <- As].
-
-cg_reg_arg(#k_var{name=V}, Bef) -> fetch_var(V, Bef);
-cg_reg_arg(Literal, _) -> atomic(Literal).
-
-cg_reg_arg_prefer_y(#k_var{name=V}, Bef) -> fetch_var_prefer_y(V, Bef);
-cg_reg_arg_prefer_y(Literal, _) -> atomic(Literal).
-
-%% cg_setup_call([Arg], Bef, Cur, Vdb) -> {[Instr],Aft}.
-%% Do the complete setup for a call/enter.
-
-cg_setup_call(As, Bef, I, Vdb) ->
- {Ms,Int0} = cg_call_args(As, Bef, I, Vdb),
- %% Have set up arguments, can now clean up, compress and save to stack.
- Int1 = Int0#sr{stk=clear_dead_stk(Int0#sr.stk, I, Vdb),res=[]},
- {Sis,Int2} = adjust_stack(Int1, I, I+1, Vdb),
- {Ms ++ Sis,Int2}.
-
-%% cg_call_args([Arg], SrState) -> {[Instr],SrState}.
-%% Setup the arguments to a call/enter/bif. Put the arguments into
-%% consecutive registers starting at {x,0} moving any data which
-%% needs to be saved. Return a modified SrState structure with the
-%% new register contents. N.B. the resultant register info will
-%% contain non-variable values when there are non-variable values.
-%%
-%% This routine is complicated by unsaved values in x registers.
-%% We'll move away any unsaved values that are in the registers
-%% to be overwritten by the arguments.
-
-cg_call_args(As, Bef, I, Vdb) ->
- Regs0 = load_arg_regs(Bef#sr.reg, As),
- Unsaved = unsaved_registers(Regs0, Bef#sr.stk, I, I+1, Vdb),
- {UnsavedMoves,Regs} = move_unsaved(Unsaved, Bef#sr.reg, Regs0),
- Moves0 = gen_moves(As, Bef),
- Moves = order_moves(Moves0, find_scratch_reg(Regs)),
- {UnsavedMoves ++ Moves,Bef#sr{reg=Regs}}.
-
-%% load_arg_regs([Reg], Arguments) -> [Reg]
-%% Update the register descriptor to include the arguments (from {x,0}
-%% and upwards). Values in argument register are overwritten.
-%% Values in x registers above the arguments are preserved.
-
-load_arg_regs(Regs, As) -> load_arg_regs(Regs, As, 0).
-
-load_arg_regs([_|Rs], [#k_var{name=V}|As], I) -> [{I,V}|load_arg_regs(Rs, As, I+1)];
-load_arg_regs([_|Rs], [A|As], I) -> [{I,A}|load_arg_regs(Rs, As, I+1)];
-load_arg_regs([], [#k_var{name=V}|As], I) -> [{I,V}|load_arg_regs([], As, I+1)];
-load_arg_regs([], [A|As], I) -> [{I,A}|load_arg_regs([], As, I+1)];
-load_arg_regs(Rs, [], _) -> Rs.
-
-%% Returns the variables must be saved and are currently in the
-%% x registers that are about to be overwritten by the arguments.
-
-unsaved_registers(Regs, Stk, Fb, Lf, Vdb) ->
- [V || {V,F,L} <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk),
- not in_reg(V, Regs)].
-
-in_reg(V, Regs) -> keymember(V, 2, Regs).
-
-%% Move away unsaved variables from the registers that are to be
-%% overwritten by the arguments.
-move_unsaved(Vs, OrigRegs, NewRegs) ->
- move_unsaved(Vs, OrigRegs, NewRegs, []).
-
-move_unsaved([V|Vs], OrigRegs, NewRegs0, Acc) ->
- NewRegs = put_reg(V, NewRegs0),
- Src = fetch_reg(V, OrigRegs),
- Dst = fetch_reg(V, NewRegs),
- move_unsaved(Vs, OrigRegs, NewRegs, [{move,Src,Dst}|Acc]);
-move_unsaved([], _, Regs, Acc) -> {Acc,Regs}.
-
-%% gen_moves(As, Sr)
-%% Generate the basic move instruction to move the arguments
-%% to their proper registers. The list will be sorted on
-%% destinations. (I.e. the move to {x,0} will be first --
-%% see the comment to order_moves/2.)
-
-gen_moves(As, Sr) -> gen_moves(As, Sr, 0, []).
-
-gen_moves([#k_var{name=V}|As], Sr, I, Acc) ->
- case fetch_var(V, Sr) of
- {x,I} -> gen_moves(As, Sr, I+1, Acc);
- Reg -> gen_moves(As, Sr, I+1, [{move,Reg,{x,I}}|Acc])
- end;
-gen_moves([A0|As], Sr, I, Acc) ->
- A = atomic(A0),
- gen_moves(As, Sr, I+1, [{move,A,{x,I}}|Acc]);
-gen_moves([], _, _, Acc) -> lists:keysort(3, Acc).
-
-%% order_moves([Move], ScratchReg) -> [Move]
-%% Orders move instruction so that source registers are not
-%% destroyed before they are used. If there are cycles
-%% (such as {move,{x,0},{x,1}}, {move,{x,1},{x,1}}),
-%% the scratch register is used to break up the cycle.
-%% If possible, the first move of the input list is placed
-%% last in the result list (to make the move to {x,0} occur
-%% just before the call to allow the Beam loader to coalesce
-%% the instructions).
-
-order_moves(Ms, Scr) -> order_moves(Ms, Scr, []).
-
-order_moves([{move,_,_}=M|Ms0], ScrReg, Acc0) ->
- {Chain,Ms} = collect_chain(Ms0, [M], ScrReg),
- Acc = reverse(Chain, Acc0),
- order_moves(Ms, ScrReg, Acc);
-order_moves([], _, Acc) -> Acc.
-
-collect_chain(Ms, Path, ScrReg) ->
- collect_chain(Ms, Path, [], ScrReg).
-
-collect_chain([{move,Src,Same}=M|Ms0], [{move,Same,_}|_]=Path, Others, ScrReg) ->
- case lists:keyfind(Src, 3, Path) of
- false ->
- collect_chain(reverse(Others, Ms0), [M|Path], [], ScrReg);
- _ -> % We have a cycle.
- {break_up_cycle(M, Path, ScrReg),reverse(Others, Ms0)}
- end;
-collect_chain([M|Ms], Path, Others, ScrReg) ->
- collect_chain(Ms, Path, [M|Others], ScrReg);
-collect_chain([], Path, Others, _) ->
- {Path,Others}.
-
-break_up_cycle({move,Src,_}=M, Path, ScrReg) ->
- [{move,ScrReg,Src},M|break_up_cycle1(Src, Path, ScrReg)].
-
-break_up_cycle1(Dst, [{move,Src,Dst}|Path], ScrReg) ->
- [{move,Src,ScrReg}|Path];
-break_up_cycle1(Dst, [M|Path], LastMove) ->
- [M|break_up_cycle1(Dst, Path, LastMove)].
-
-%% clear_dead(Sr, Until, Vdb) -> Aft.
-%% Remove all variables in Sr which have died AT ALL so far.
-
-clear_dead(#sr{stk=Stk}=Sr0, Until, Vdb) ->
- Sr = Sr0#sr{reg=clear_dead_reg(Sr0, Until, Vdb),
- stk=clear_dead_stk(Stk, Until, Vdb)},
- reserve(Sr).
-
-clear_dead_reg(Sr, Until, Vdb) ->
- [case R of
- {_I,V} = IV ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L > Until -> IV;
- _ -> free %Remove anything else
- end;
- {reserved,_I,_V}=Reserved -> Reserved;
- free -> free
- end || R <- Sr#sr.reg].
-
-clear_dead_stk(Stk, Until, Vdb) ->
- [case S of
- {V} = T ->
- case vdb_find(V, Vdb) of
- {V,_,L} when L > Until -> T;
- _ -> dead %Remove anything else
- end;
- free -> free;
- dead -> dead
- end || S <- Stk].
-
-
-%% sr_merge(Sr1, Sr2) -> Sr.
-%% Merge two stack/register states keeping the longest of both stack
-%% and register. Perform consistency check on both, elements must be
-%% the same. Allow frame size 'void' to make easy creation of
-%% "empty" frame.
-
-sr_merge(#sr{reg=R1,stk=S1,res=[]}, #sr{reg=R2,stk=S2,res=[]}) ->
- #sr{reg=longest(R1, R2),stk=longest(S1, S2),res=[]};
-sr_merge(void, S2) -> S2#sr{res=[]}.
-
-longest([H|T1], [H|T2]) -> [H|longest(T1, T2)];
-longest([dead|T1], [free|T2]) -> [dead|longest(T1, T2)];
-longest([free|T1], [dead|T2]) -> [dead|longest(T1, T2)];
-longest([dead|_] = L, []) -> L;
-longest([], [dead|_] = L) -> L;
-longest([free|_] = L, []) -> L;
-longest([], [free|_] = L) -> L;
-longest([], []) -> [].
-
-trim_free([R|Rs0]) ->
- case {trim_free(Rs0),R} of
- {[],free} -> [];
- {Rs,R} -> [R|Rs]
- end;
-trim_free([]) -> [].
-
-%% maybe_adjust_stack(Bef, FirstBefore, LastFrom, Vdb, St) -> {[Ainstr],Aft}.
-%% Adjust the stack, but only if the code is inside a catch and not
-%% inside a guard. Use this funtion before instructions that may
-%% cause an exception.
-
-maybe_adjust_stack(Bef, Fb, Lf, Vdb, St) ->
- case St of
- #cg{in_catch=true,bfail=0} ->
- adjust_stack(Bef, Fb, Lf, Vdb);
- #cg{} ->
- {[],Bef}
- end.
-
-%% adjust_stack(Bef, FirstBefore, LastFrom, Vdb) -> {[Ainstr],Aft}.
-%% Do complete stack adjustment by compressing stack and adding
-%% variables to be saved. Try to optimise ordering on stack by
-%% having reverse order to their lifetimes.
-%%
-%% In Beam, there is a fixed stack frame and no need to do stack compression.
-
-adjust_stack(Bef, Fb, Lf, Vdb) ->
- Stk0 = Bef#sr.stk,
- {Stk1,Saves} = save_stack(Stk0, Fb, Lf, Vdb),
- {saves(Saves, Bef#sr.reg, Stk1),
- Bef#sr{stk=Stk1}}.
-
-%% save_stack(Stack, FirstBefore, LastFrom, Vdb) -> {[SaveVar],NewStack}.
-%% Save variables which are used past current point and which are not
-%% already on the stack.
-
-save_stack(Stk0, Fb, Lf, Vdb) ->
- %% New variables that are in use but not on stack.
- New = new_not_on_stack(Stk0, Fb, Lf, Vdb),
-
- %% Add new variables that are not just dropped immediately.
- %% N.B. foldr works backwards from the end!!
- Saves = [V || {V,_,_} <- keysort(3, New)],
- Stk1 = foldr(fun (V, Stk) -> put_stack(V, Stk) end, Stk0, Saves),
- {Stk1,Saves}.
-
-%% new_not_on_stack(Stack, FirstBefore, LastFrom, Vdb) ->
-%% [{Variable,First,Last}]
-%% Return information about all variables that are used past current
-%% point and that are not already on the stack.
-
-new_not_on_stack(Stk, Fb, Lf, Vdb) ->
- [VFL || {V,F,L} = VFL <- Vdb,
- F < Fb,
- L >= Lf,
- not on_stack(V, Stk)].
-
-%% saves([SaveVar], Reg, Stk) -> [{move,Reg,Stk}].
-%% Generate move instructions to save variables onto stack. The
-%% stack/reg info used is that after the new stack has been made.
-
-saves(Ss, Reg, Stk) ->
- [{move,fetch_reg(V, Reg),fetch_stack(V, Stk)} || V <- Ss].
-
-%% fetch_var(VarName, StkReg) -> r{R} | sp{Sp}.
-%% find_var(VarName, StkReg) -> ok{r{R} | sp{Sp}} | error.
-%% Fetch/find a variable in either the registers or on the
-%% stack. Fetch KNOWS it's there.
-
-fetch_var(V, Sr) ->
- case find_reg(V, Sr#sr.reg) of
- {ok,R} -> R;
- error -> fetch_stack(V, Sr#sr.stk)
- end.
-
-fetch_var_prefer_y(V, #sr{reg=Reg,stk=Stk}) ->
- case find_stack(V, Stk) of
- {ok,R} -> R;
- error -> fetch_reg(V, Reg)
- end.
-
-load_vars(Vs, Regs) ->
- foldl(fun (#k_var{name=V}, Rs) -> put_reg(V, Rs) end, Regs, Vs).
-
-%% put_reg(Val, Regs) -> Regs.
-%% find_reg(Val, Regs) -> {ok,r{R}} | error.
-%% fetch_reg(Val, Regs) -> r{R}.
-%% Functions to interface the registers.
-
-% put_regs(Vs, Rs) -> foldl(fun put_reg/2, Rs, Vs).
-
-put_reg(V, Rs) -> put_reg_1(V, Rs, 0).
-
-put_reg_1(V, [free|Rs], I) -> [{I,V}|Rs];
-put_reg_1(V, [{reserved,I,V}|Rs], I) -> [{I,V}|Rs];
-put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)];
-put_reg_1(V, [], I) -> [{I,V}].
-
-fetch_reg(V, [{I,V}|_]) -> {x,I};
-fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs).
-
-find_reg(V, [{I,V}|_]) -> {ok,{x,I}};
-find_reg(V, [_|SRs]) -> find_reg(V, SRs);
-find_reg(_, []) -> error.
-
-%% For the bit syntax, we need a scratch register if we are constructing
-%% a binary that will not be used.
-
-find_scratch_reg(Rs) -> find_scratch_reg(Rs, 0).
-
-find_scratch_reg([free|_], I) -> {x,I};
-find_scratch_reg([_|Rs], I) -> find_scratch_reg(Rs, I+1);
-find_scratch_reg([], I) -> {x,I}.
-
-replace_reg_contents(Old, New, [{I,Old}|Rs]) -> [{I,New}|Rs];
-replace_reg_contents(Old, New, [R|Rs]) -> [R|replace_reg_contents(Old, New, Rs)].
-
-%%clear_regs(Regs) -> map(fun (R) -> free end, Regs).
-clear_regs(_) -> [].
-
-max_reg(Regs) ->
- foldl(fun ({I,_}, _) -> I;
- (_, Max) -> Max end,
- -1, Regs) + 1.
-
-%% put_stack(Val, [{Val}]) -> [{Val}].
-%% fetch_stack(Var, Stk) -> sp{S}.
-%% find_stack(Var, Stk) -> ok{sp{S}} | error.
-%% Functions to interface the stack.
-
-put_stack(Val, []) -> [{Val}];
-put_stack(Val, [dead|Stk]) -> [{Val}|Stk];
-put_stack(Val, [free|Stk]) -> [{Val}|Stk];
-put_stack(Val, [NotFree|Stk]) -> [NotFree|put_stack(Val, Stk)].
-
-put_stack_carefully(Val, Stk0) ->
- try
- put_stack_carefully1(Val, Stk0)
- catch
- throw:error ->
- error
- end.
-
-put_stack_carefully1(_, []) -> throw(error);
-put_stack_carefully1(Val, [dead|Stk]) -> [{Val}|Stk];
-put_stack_carefully1(Val, [free|Stk]) -> [{Val}|Stk];
-put_stack_carefully1(Val, [NotFree|Stk]) ->
- [NotFree|put_stack_carefully1(Val, Stk)].
-
-fetch_stack(Var, Stk) -> fetch_stack(Var, Stk, 0).
-
-fetch_stack(V, [{V}|_], I) -> {yy,I};
-fetch_stack(V, [_|Stk], I) -> fetch_stack(V, Stk, I+1).
-
-find_stack(Var, Stk) -> find_stack(Var, Stk, 0).
-
-find_stack(V, [{V}|_], I) -> {ok,{yy,I}};
-find_stack(V, [_|Stk], I) -> find_stack(V, Stk, I+1);
-find_stack(_, [], _) -> error.
-
-on_stack(V, Stk) -> keymember(V, 1, Stk).
-
-%% put_catch(CatchTag, Stack) -> Stack'
-%% drop_catch(CatchTag, Stack) -> Stack'
-%% Special interface for putting and removing catch tags, to ensure that
-%% catches nest properly. Also used for try tags.
-
-put_catch(Tag, Stk0) -> put_catch(Tag, reverse(Stk0), []).
-
-put_catch(Tag, [], Stk) ->
- put_stack({catch_tag,Tag}, Stk);
-put_catch(Tag, [{{catch_tag,_}}|_]=RevStk, Stk) ->
- reverse(RevStk, put_stack({catch_tag,Tag}, Stk));
-put_catch(Tag, [Other|Stk], Acc) ->
- put_catch(Tag, Stk, [Other|Acc]).
-
-drop_catch(Tag, [{{catch_tag,Tag}}|Stk]) -> [free|Stk];
-drop_catch(Tag, [Other|Stk]) -> [Other|drop_catch(Tag, Stk)].
-
-%% atomic(Klit) -> Lit.
-%% atomic_list([Klit]) -> [Lit].
-
-atomic(#k_literal{val=V}) -> {literal,V};
-atomic(#k_int{val=I}) -> {integer,I};
-atomic(#k_float{val=F}) -> {float,F};
-atomic(#k_atom{val=A}) -> {atom,A};
-%%atomic(#k_char{val=C}) -> {char,C};
-atomic(#k_nil{}) -> nil.
-
-%% new_label(St) -> {L,St}.
-
-new_label(#cg{lcount=Next}=St) ->
- {Next,St#cg{lcount=Next+1}}.
-
-%% line(Le) -> {line,[] | {location,File,Line}}
-%% Create a line instruction, containing information about
-%% the current filename and line number. A line information
-%% instruction should be placed before any operation that could
-%% cause an exception.
-
-line(#l{a=Anno}) ->
- line(Anno);
-line([Line,{file,Name}]) when is_integer(Line) ->
- line_1(Name, Line);
-line([_|_]=A) ->
- {Name,Line} = find_loc(A, no_file, 0),
- line_1(Name, Line);
-line([]) ->
- {line,[]}.
-
-line_1(no_file, _) ->
- {line,[]};
-line_1(_, 0) ->
- %% Missing line number or line number 0.
- {line,[]};
-line_1(Name, Line) ->
- {line,[{location,Name,Line}]}.
-
-find_loc([Line|T], File, _) when is_integer(Line) ->
- find_loc(T, File, Line);
-find_loc([{file,File}|T], _, Line) ->
- find_loc(T, File, Line);
-find_loc([_|T], File, Line) ->
- find_loc(T, File, Line);
-find_loc([], File, Line) -> {File,Line}.
-
-flatmapfoldl(F, Accu0, [Hd|Tail]) ->
- {R,Accu1} = F(Hd, Accu0),
- {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
- {R++Rs,Accu2};
-flatmapfoldl(_, Accu, []) -> {[],Accu}.
-
-%% Keep track of life time for variables.
-%%
-%% init_vars([{var,VarName}]) -> Vdb.
-%% new_vars([VarName], I, Vdb) -> Vdb.
-%% use_vars([VarName], I, Vdb) -> Vdb.
-%% add_var(VarName, F, L, Vdb) -> Vdb.
-%%
-%% The list of variable names for new_vars/3 and use_vars/3
-%% must be sorted.
-
-init_vars(Vs) ->
- vdb_new(Vs).
-
-new_vars([], _, Vdb) -> Vdb;
-new_vars([V], I, Vdb) -> vdb_store_new(V, {V,I,I}, Vdb);
-new_vars(Vs, I, Vdb) -> vdb_update_vars(Vs, Vdb, I).
-
-use_vars([], _, Vdb) ->
- Vdb;
-use_vars([V], I, Vdb) ->
- case vdb_find(V, Vdb) of
- {V,F,L} when I > L -> vdb_update(V, {V,F,I}, Vdb);
- {V,_,_} -> Vdb;
- error -> vdb_store_new(V, {V,I,I}, Vdb)
- end;
-use_vars(Vs, I, Vdb) -> vdb_update_vars(Vs, Vdb, I).
-
-add_var(V, F, L, Vdb) ->
- vdb_store_new(V, {V,F,L}, Vdb).
-
-%% vdb
-
-vdb_new(Vs) ->
- ordsets:from_list([{V,0,0} || #k_var{name=V} <- Vs]).
-
--type var() :: atom().
-
--spec vdb_find(var(), [vdb_entry()]) -> 'error' | vdb_entry().
-
-vdb_find(V, Vdb) ->
- case lists:keyfind(V, 1, Vdb) of
- false -> error;
- Vd -> Vd
- end.
-
-vdb_update(V, Update, [{V,_,_}|Vdb]) ->
- [Update|Vdb];
-vdb_update(V, Update, [Vd|Vdb]) ->
- [Vd|vdb_update(V, Update, Vdb)].
-
-vdb_store_new(V, New, [{V1,_,_}=Vd|Vdb]) when V > V1 ->
- [Vd|vdb_store_new(V, New, Vdb)];
-vdb_store_new(V, New, [{V1,_,_}|_]=Vdb) when V < V1 ->
- [New|Vdb];
-vdb_store_new(_, New, []) -> [New].
-
-vdb_update_vars([V|_]=Vs, [{V1,_,_}=Vd|Vdb], I) when V > V1 ->
- [Vd|vdb_update_vars(Vs, Vdb, I)];
-vdb_update_vars([V|Vs], [{V1,_,_}|_]=Vdb, I) when V < V1 ->
- %% New variable.
- [{V,I,I}|vdb_update_vars(Vs, Vdb, I)];
-vdb_update_vars([V|Vs], [{_,F,L}=Vd|Vdb], I) ->
- %% Existing variable.
- if
- I > L -> [{V,F,I}|vdb_update_vars(Vs, Vdb, I)];
- true -> [Vd|vdb_update_vars(Vs, Vdb, I)]
- end;
-vdb_update_vars([V|Vs], [], I) ->
- %% New variable.
- [{V,I,I}|vdb_update_vars(Vs, [], I)];
-vdb_update_vars([], Vdb, _) -> Vdb.
-
-%% vdb_sub(Min, Max, Vdb) -> Vdb.
-%% Extract variables which are used before and after Min. Lock
-%% variables alive after Max.
-
-vdb_sub(Min, Max, Vdb) ->
- [ if L >= Max -> {V,F,locked};
- true -> Vd
- end || {V,F,L}=Vd <- Vdb,
- F < Min,
- L >= Min ].
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 0196e7fdfd..45e0ed5088 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -228,7 +228,8 @@ function({function,_,Name,Arity,Cs0}, Ws0, File, Opts) ->
body(Cs0, Name, Arity, St0) ->
Anno = lineno_anno(element(2, hd(Cs0)), St0),
- {Args,St1} = new_vars(Anno, Arity, St0),
+ {Args0,St1} = new_vars(Anno, Arity, St0),
+ Args = reverse(Args0), %Nicer order
case clauses(Cs0, St1) of
{Cs1,[],St2} ->
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
@@ -328,14 +329,16 @@ gexpr({protect,Line,Arg}, Bools0, St0) ->
Anno = lineno_anno(Line, St),
{#iprotect{anno=#a{anno=Anno},body=Eps++[E]},[],Bools0,St}
end;
-gexpr({op,L,'andalso',E1,E2}, Bools, St0) ->
+gexpr({op,_,'andalso',_,_}=E0, Bools, St0) ->
+ {op,L,'andalso',E1,E2} = right_assoc(E0, 'andalso', St0),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
False = {atom,L,false},
E = make_bool_switch_guard(L, E1, V, E2, False),
gexpr(E, Bools, St);
-gexpr({op,L,'orelse',E1,E2}, Bools, St0) ->
+gexpr({op,_,'orelse',_,_}=E0, Bools, St0) ->
+ {op,L,'orelse',E1,E2} = right_assoc(E0, 'orelse', St0),
Anno = lineno_anno(L, St0),
{#c_var{name=V0},St} = new_var(Anno, St0),
V = {var,L,V0},
@@ -1501,7 +1504,7 @@ bc_initial_size(E0, Q, St0) ->
end.
bc_elem_size({bin,_,El}, St0) ->
- case bc_elem_size_1(El, 0, []) of
+ case bc_elem_size_1(El, ordsets:new(), 0, []) of
{Bits,[]} ->
{#c_literal{val=Bits},[],[],St0};
{Bits,Vars0} ->
@@ -1515,19 +1518,33 @@ bc_elem_size(_, _) ->
throw(impossible).
bc_elem_size_1([{bin_element,_,{string,_,String},{integer,_,N},_}=El|Es],
- Bits, Vars) ->
+ DefVars, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N*length(String), Vars);
-bc_elem_size_1([{bin_element,_,_,{integer,_,N},_}=El|Es], Bits, Vars) ->
+ bc_elem_size_1(Es, DefVars, Bits+U*N*length(String), SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{integer,_,N},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
U = get_unit(El),
- bc_elem_size_1(Es, Bits+U*N, Vars);
-bc_elem_size_1([{bin_element,_,_,{var,_,Var},_}=El|Es], Bits, Vars) ->
- U = get_unit(El),
- bc_elem_size_1(Es, Bits, [{U,#c_var{name=Var}}|Vars]);
-bc_elem_size_1([_|_], _, _) ->
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits+U*N, SizeVars);
+bc_elem_size_1([{bin_element,_,Expr,{var,_,Src},_}=El|Es],
+ DefVars0, Bits, SizeVars) ->
+ case ordsets:is_element(Src, DefVars0) of
+ false ->
+ U = get_unit(El),
+ DefVars = bc_elem_size_def_var(Expr, DefVars0),
+ bc_elem_size_1(Es, DefVars, Bits, [{U,#c_var{name=Src}}|SizeVars]);
+ true ->
+ throw(impossible)
+ end;
+bc_elem_size_1([_|_], _, _, _) ->
throw(impossible);
-bc_elem_size_1([], Bits, Vars) ->
- {Bits,Vars}.
+bc_elem_size_1([], _DefVars, Bits, SizeVars) ->
+ {Bits,SizeVars}.
+
+bc_elem_size_def_var({var,_,Var}, DefVars) ->
+ ordsets:add_element(Var, DefVars);
+bc_elem_size_def_var(_Expr, DefVars) ->
+ DefVars.
bc_elem_size_combine([{U,V}|T], U, UVars, Acc) ->
bc_elem_size_combine(T, U, [V|UVars], Acc);
@@ -2040,6 +2057,19 @@ fail_clause(Pats, Anno, Arg) ->
body=[#iprimop{anno=#a{anno=Anno},name=#c_literal{val=match_fail},
args=[Arg]}]}.
+%% Optimization for Dialyzer.
+right_assoc(E, Op, St) ->
+ case member(dialyzer, St#core.opts) of
+ true ->
+ right_assoc2(E, Op);
+ false ->
+ E
+ end.
+
+right_assoc2({op,L1,Op,{op,L2,Op,E1,E2},E3}, Op) ->
+ right_assoc2({op,L2,Op,E1,{op,L1,Op,E2,E3}}, Op);
+right_assoc2(E, _Op) -> E.
+
annotate_tuple(A, Es, St) ->
case member(dialyzer, St#core.opts) of
true ->
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index aef0b6cc9f..f7ca66b1da 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -82,8 +82,7 @@
-export([module/2,format_error/1]).
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2,
- keymember/3,keyfind/3,partition/2,droplast/1,last/1,sort/1,
- reverse/1]).
+ keyfind/3,partition/2,droplast/1,last/1,sort/1,reverse/1]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
-import(cerl, [c_tuple/1]).
@@ -1416,7 +1415,6 @@ is_remote_bif(_, _, _) -> false.
%% called for effect only.
bif_vals(dsetelement, 3) -> 0;
-bif_vals(bs_context_to_binary, 1) -> 0;
bif_vals(_, _) -> 1.
bif_vals(_, _, _) -> 1.
@@ -2043,9 +2041,6 @@ get_match(#k_cons{}, St0) ->
get_match(#k_binary{}, St0) ->
{[V]=Mes,St1} = new_vars(1, St0),
{#k_binary{segs=V},Mes,St1};
-get_match(#k_bin_seg{size=#k_atom{val=all},next={k_bin_end,[]}}=Seg, St0) ->
- {[S]=Vars,St1} = new_vars(1, St0),
- {Seg#k_bin_seg{seg=S,next=[]},Vars,St1};
get_match(#k_bin_seg{}=Seg, St0) ->
{[S,N0],St1} = new_vars(2, St0),
N = set_kanno(N0, [no_usage]),
@@ -2073,9 +2068,6 @@ new_clauses(Cs0, U, St) ->
#k_cons{hd=H,tl=T} -> [H,T|As];
#k_tuple{es=Es} -> Es ++ As;
#k_binary{segs=E} -> [E|As];
- #k_bin_seg{size=#k_atom{val=all},
- seg=S,next={k_bin_end,[]}} ->
- [S|As];
#k_bin_seg{seg=S,next=N} ->
[S,N|As];
#k_bin_int{next=N} ->
@@ -2343,8 +2335,7 @@ uexpr(#k_bif{anno=A,op=Op,args=As}=Bif, {break,Rs}, St0) ->
{Brs,St1} = bif_returns(Op, Rs, St0),
{Bif#k_bif{anno=#k{us=Used,ns=lit_list_vars(Brs),a=A},ret=Brs},
Used,St1};
-uexpr(#k_match{anno=A,vars=Vs0,body=B0}, Br, St0) ->
- Vs = handle_reuse_annos(Vs0, St0),
+uexpr(#k_match{anno=A,vars=Vs,body=B0}, Br, St0) ->
Rs = break_rets(Br),
{B1,Bu,St1} = umatch(B0, Br, St0),
case is_in_guard(St1) of
@@ -2374,9 +2365,10 @@ uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0},
true ->
{[#k_var{name=X}],#k_var{name=X}} = {Vs,B0}, %Assertion.
#k_atom{val=false} = H0, %Assertion.
- {A1,Bu,St1} = uexpr(A0, Br, St0),
+ {Avs,St1} = new_vars(length(Rs0), St0),
+ {A1,Bu,St} = uexpr(A0, {break,Avs}, St1),
{#k_protected{anno=#k{us=Bu,ns=lit_list_vars(Rs0),a=A},
- arg=A1,ret=Rs0},Bu,St1};
+ arg=A1,ret=Rs0,inner=Avs},Bu,St};
false ->
{Avs,St1} = new_vars(length(Vs), St0),
{A1,Au,St2} = ubody(A0, {break,Avs}, St1),
@@ -2446,33 +2438,6 @@ make_fdef(Anno, Name, Arity, Vs, Body) ->
vars=Vs,body=Body,ret=[]},
#k_fdef{anno=Anno,func=Name,arity=Arity,vars=Vs,body=Match}.
-
-%% handle_reuse_annos([#k_var{}], State) -> State.
-%% In general, it is only safe to reuse a variable for a match context
-%% if the original value of the variable will no longer be needed.
-%%
-%% If a variable has been bound in an outer letrec and is therefore
-%% free in the current function, the variable may still be used.
-%% We don't bother to check whether the variable is actually used,
-%% but simply clears the 'reuse_for_context' annotation for any variable
-%% that is free.
-handle_reuse_annos(Vs, St) ->
- [handle_reuse_anno(V, St) || V <- Vs].
-
-handle_reuse_anno(#k_var{anno=A}=V, St) ->
- case member(reuse_for_context, A) of
- false -> V;
- true -> handle_reuse_anno_1(V, St)
- end.
-
-handle_reuse_anno_1(#k_var{anno=Anno,name=Vname}=V, #kern{ff={F,A}}=St) ->
- FreeVs = get_free(F, A, St),
- case keymember(Vname, #k_var.name, FreeVs) of
- true -> V#k_var{anno=Anno--[reuse_for_context]};
- false -> V
- end;
-handle_reuse_anno_1(V, _St) -> V.
-
%% get_free(Name, Arity, State) -> [Free].
%% store_free(Name, Arity, [Free], State) -> State.
@@ -2516,8 +2481,7 @@ umatch(#k_alt{anno=A,first=F0,then=T0}, Br, St0) ->
Used = union(Fu, Tu),
{#k_alt{anno=#k{us=Used,ns=[],a=A},first=F1,then=T1},
Used,St2};
-umatch(#k_select{anno=A,var=V0,types=Ts0}, Br, St0) ->
- V = handle_reuse_anno(V0, St0),
+umatch(#k_select{anno=A,var=V,types=Ts0}, Br, St0) ->
{Ts1,Tus,St1} = umatch_list(Ts0, Br, St0),
Used = case member(no_usage, get_kanno(V)) of
true -> Tus;
diff --git a/lib/compiler/src/v3_kernel.hrl b/lib/compiler/src/v3_kernel.hrl
index e6f0d3c1f7..e26360a6da 100644
--- a/lib/compiler/src/v3_kernel.hrl
+++ b/lib/compiler/src/v3_kernel.hrl
@@ -66,7 +66,7 @@
-record(k_receive_next, {anno=[]}).
-record(k_try, {anno=[],arg,vars,body,evars,handler,ret=[]}).
-record(k_try_enter, {anno=[],arg,vars,body,evars,handler}).
--record(k_protected, {anno=[],arg,ret=[]}).
+-record(k_protected, {anno=[],arg,ret=[],inner}).
-record(k_catch, {anno=[],body,ret=[]}).
-record(k_guard_match, {anno=[],vars,body,ret=[]}).
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index da5d207db9..40428b7f2d 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -14,6 +14,7 @@ MODULES= \
beam_except_SUITE \
beam_jump_SUITE \
beam_reorder_SUITE \
+ beam_ssa_SUITE \
beam_type_SUITE \
beam_utils_SUITE \
bif_SUITE \
@@ -52,6 +53,7 @@ NO_OPT= \
beam_except \
beam_jump \
beam_reorder \
+ beam_ssa \
beam_type \
beam_utils \
bif \
@@ -75,6 +77,7 @@ INLINE= \
andor \
apply \
beam_block \
+ beam_ssa \
beam_utils \
bif \
bs_bincomp \
@@ -94,6 +97,10 @@ INLINE= \
receive \
record
+R21= \
+ bs_construct \
+ bs_match
+
CORE_MODULES = \
lfe_andor_SUITE \
lfe_guard_SUITE
@@ -104,6 +111,8 @@ POST_OPT_MODULES= $(NO_OPT:%=%_post_opt_SUITE)
POST_OPT_ERL_FILES= $(POST_OPT_MODULES:%=%.erl)
INLINE_MODULES= $(INLINE:%=%_inline_SUITE)
INLINE_ERL_FILES= $(INLINE_MODULES:%=%.erl)
+R21_MODULES= $(R21:%=%_r21_SUITE)
+R21_ERL_FILES= $(R21_MODULES:%=%.erl)
ERL_FILES= $(MODULES:%=%.erl)
CORE_FILES= $(CORE_MODULES:%=%.core)
@@ -124,7 +133,7 @@ RELSYSDIR = $(RELEASE_PATH)/compiler_test
# ----------------------------------------------------
ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += +clint +clint0
+ERL_COMPILE_FLAGS += +clint +clint0 +ssalint
EBIN = .
@@ -132,15 +141,19 @@ EBIN = .
# Targets
# ----------------------------------------------------
-make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) $(INLINE_ERL_FILES)
+make_emakefile: $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
> $(EMAKEFILE)
- $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt $(ERL_COMPILE_FLAGS) \
+ $(ERL_TOP)/make/make_emakefile +no_copt +no_postopt \
+ +no_ssa_opt +no_recv_opt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(NO_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +no_copt $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(POST_OPT_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +inline $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(INLINE_MODULES) >> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile +r21 $(ERL_COMPILE_FLAGS) \
+ -o$(EBIN) $(R21_MODULES) >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile +from_core $(ERL_COMPILE_FLAGS) \
-o$(EBIN) $(CORE_MODULES) >> $(EMAKEFILE)
@@ -167,6 +180,9 @@ docs:
%_inline_SUITE.erl: %_SUITE.erl
sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+%_r21_SUITE.erl: %_SUITE.erl
+ sed -e 's;-module($(basename $<));-module($(basename $@));' $< > $@
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -179,7 +195,7 @@ release_tests_spec: make_emakefile
$(INSTALL_DATA) compiler.spec compiler.cover \
$(EMAKEFILE) $(ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(NO_OPT_ERL_FILES) $(POST_OPT_ERL_FILES) \
- $(INLINE_ERL_FILES) "$(RELSYSDIR)"
+ $(INLINE_ERL_FILES) $(R21_ERL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) $(CORE_FILES) "$(RELSYSDIR)"
for file in $(ERL_DUMMY_FILES); do \
module=`basename $$file .erl`; \
diff --git a/lib/compiler/test/andor_SUITE.erl b/lib/compiler/test/andor_SUITE.erl
index 721f77f0f6..5c463063c1 100644
--- a/lib/compiler/test/andor_SUITE.erl
+++ b/lib/compiler/test/andor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/apply_SUITE.erl b/lib/compiler/test/apply_SUITE.erl
index be49cff9b9..0f82a56fb7 100644
--- a/lib/compiler/test/apply_SUITE.erl
+++ b/lib/compiler/test/apply_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index 1eb07c8c85..2b4a780899 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_jump_SUITE.erl b/lib/compiler/test/beam_jump_SUITE.erl
index 488c30919b..f6cddbf1b1 100644
--- a/lib/compiler/test/beam_jump_SUITE.erl
+++ b/lib/compiler/test/beam_jump_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,8 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- undefined_label/1,ambiguous_catch_try_state/1]).
+ undefined_label/1,ambiguous_catch_try_state/1,
+ unsafe_move_elimination/1]).
suite() ->
[{ct_hooks,[ts_install_cth]}].
@@ -32,7 +33,8 @@ all() ->
groups() ->
[{p,[parallel],
[undefined_label,
- ambiguous_catch_try_state
+ ambiguous_catch_try_state,
+ unsafe_move_elimination
]}].
init_per_suite(Config) ->
@@ -72,3 +74,44 @@ river() -> song.
checks(Wanted) ->
%% Must be one line to cause the unsafe optimization.
{catch case river() of sheet -> begin +Wanted, if "da" -> Wanted end end end, catch case river() of sheet -> begin + Wanted, if "da" -> Wanted end end end}.
+
+unsafe_move_elimination(_Config) ->
+ {{left,right,false},false} = unsafe_move_elimination(left, right, false),
+ {{false,right,false},false} = unsafe_move_elimination(false, right, true),
+ {{true,right,right},right} = unsafe_move_elimination(true, right, true),
+ ok.
+
+unsafe_move_elimination(Left, Right, Simple0) ->
+ id(1),
+
+ %% The move at label 29 would be removed by beam_jump, which is unsafe because
+ %% the two select_val instructions have different source registers.
+ %%
+ %% {select_val,{y,0},{f,25},{list,[{atom,true},{f,27},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,27}.
+ %% {kill,{y,0}}.
+ %% {move,{y,2},{x,0}}.
+ %% {line,...}.
+ %% {call,1,{f,31}}.
+ %% {select_val,{x,0},{f,33},{list,[{atom,true},{f,35},{atom,false},{f,29}]}}.
+ %% ^^^^^ ^^^^^^^^^^^^^^^^^^^
+ %% {label,29}.
+ %% {move,{atom,false},{y,0}}. <=== REMOVED (unsafely).
+ %% {jump,{f,37}}.
+
+ Simple = case case Simple0 of
+ false -> false;
+ true -> id(Left)
+ end
+ of
+ false ->
+ false;
+ true ->
+ id(Right)
+ end,
+ {id({Left,Right,Simple}),Simple}.
+
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/beam_reorder_SUITE.erl b/lib/compiler/test/beam_reorder_SUITE.erl
index 33b27b9f9f..c8a4f9a75f 100644
--- a/lib/compiler/test/beam_reorder_SUITE.erl
+++ b/lib/compiler/test/beam_reorder_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/beam_ssa_SUITE.erl b/lib/compiler/test/beam_ssa_SUITE.erl
new file mode 100644
index 0000000000..5536abbdde
--- /dev/null
+++ b/lib/compiler/test/beam_ssa_SUITE.erl
@@ -0,0 +1,471 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(beam_ssa_SUITE).
+
+-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
+ init_per_group/2,end_per_group/2,
+ calls/1,tuple_matching/1,recv/1,maps/1,
+ cover_ssa_dead/1,combine_sw/1]).
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [{group,p}].
+
+groups() ->
+ [{p,test_lib:parallel(),
+ [tuple_matching,
+ calls,
+ recv,
+ maps,
+ cover_ssa_dead,
+ combine_sw
+ ]}].
+
+init_per_suite(Config) ->
+ test_lib:recompile(?MODULE),
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+calls(Config) ->
+ Ret = {return,value,Config},
+ Ret = fun_call(fun(42) -> ok end, Ret),
+ Ret = apply_fun(fun(a, b) -> ok end, [a,b], Ret),
+ Ret = apply_mfa(test_lib, id, [anything], Ret),
+ {'EXIT',{badarg,_}} = (catch call_error()),
+ {'EXIT',{badarg,_}} = (catch call_error(42)),
+ 5 = start_it([erlang,length,1,2,3,4,5]),
+ ok.
+
+fun_call(Fun, X0) ->
+ X = id(X0),
+ Fun(42),
+ X.
+
+apply_fun(Fun, Args, X0) ->
+ X = id(X0),
+ apply(Fun, Args),
+ X.
+
+apply_mfa(Mod, Name, Args, X0) ->
+ X = id(X0),
+ apply(Mod, Name, Args),
+ X.
+
+call_error() ->
+ error(badarg),
+ ok.
+
+call_error(I) ->
+ <<I:(-8)>>,
+ ok.
+
+start_it([_|_]=MFA) ->
+ case MFA of
+ [M,F|Args] -> M:F(Args)
+ end.
+
+tuple_matching(_Config) ->
+ do_tuple_matching({tag,42}).
+
+do_tuple_matching(Arg) ->
+ Res = do_tuple_matching_1(Arg),
+ Res = do_tuple_matching_2(Arg),
+ Res = do_tuple_matching_3(Arg),
+ Res.
+
+do_tuple_matching_1({tag,V}) ->
+ {ok,V}.
+
+do_tuple_matching_2(Tuple) when is_tuple(Tuple) ->
+ Size = tuple_size(Tuple),
+ if
+ Size =:= 2 ->
+ {ok,element(2, Tuple)}
+ end.
+
+do_tuple_matching_3(Tuple) when is_tuple(Tuple) ->
+ Size = tuple_size(Tuple),
+ if
+ Size =:= 2 ->
+ 2 = id(Size),
+ {ok,element(2, Tuple)}
+ end.
+
+-record(reporter_state, {res,run_config}).
+-record(run_config, {report_interval=0}).
+
+recv(_Config) ->
+ Parent = self(),
+
+ %% Test sync_wait_mon/2.
+ Succ = fun() -> Parent ! {ack,self(),{result,42}} end,
+ {result,42} = sync_wait_mon(spawn_monitor(Succ), infinity),
+
+ Down = fun() -> exit(down) end,
+ {error,down} = sync_wait_mon(spawn_monitor(Down), infinity),
+
+ Exit = fun() ->
+ Self = self(),
+ spawn(fun() -> exit(Self, kill_me) end),
+ receive _ -> ok end
+ end,
+ {error,kill_me} = sync_wait_mon(spawn_monitor(Exit), infinity),
+
+ Timeout = fun() -> receive _ -> ok end end,
+ {error,timeout} = sync_wait_mon(spawn_monitor(Timeout), 0),
+
+ %% Test reporter_loop/1.
+ {a,Parent} = reporter_loop(#reporter_state{res={a,Parent},
+ run_config=#run_config{}}),
+
+ %% Test bad_sink/0.
+ bad_sink(),
+
+ %% Test tricky_recv_1/0.
+ self() ! 1,
+ a = tricky_recv_1(),
+ self() ! 2,
+ b = tricky_recv_1(),
+
+ %% Test tricky_recv_2/0.
+ self() ! 1,
+ {1,yes} = tricky_recv_2(),
+ self() ! 2,
+ {2,maybe} = tricky_recv_2(),
+
+ %% Test 'receive after infinity' in try/catch.
+ Pid = spawn(fun recv_after_inf_in_try/0),
+ exit(Pid, done),
+
+ %% Test tricky_recv_3().
+ self() ! {{self(),r0},{1,42,"name"}},
+ {Parent,r0,[<<1:32,1:8,42:8>>,"name",0]} = tricky_recv_3(),
+ self() ! {{self(),r1},{2,99,<<"data">>}},
+ {Parent,r1,<<1:32,2:8,99:8,"data">>} = tricky_recv_3(),
+
+ %% Test tricky_recv_4().
+ self() ! {[self(),r0],{1,42,"name"}},
+ {Parent,r0,[<<1:32,1:8,42:8>>,"name",0]} = tricky_recv_4(),
+ self() ! {[self(),r1],{2,99,<<"data">>}},
+ {Parent,r1,<<1:32,2:8,99:8,"data">>} = tricky_recv_4(),
+
+ ok.
+
+sync_wait_mon({Pid, Ref}, Timeout) ->
+ receive
+ {ack,Pid,Return} ->
+ erlang:demonitor(Ref, [flush]),
+ Return;
+ {'DOWN',Ref,_Type,Pid,Reason} ->
+ {error,Reason};
+ {'EXIT',Pid,Reason} ->
+ erlang:demonitor(Ref, [flush]),
+ {error,Reason}
+ after Timeout ->
+ erlang:demonitor(Ref, [flush]),
+ exit(Pid, kill),
+ {error,timeout}
+ end.
+
+reporter_loop(State) ->
+ RC = State#reporter_state.run_config,
+ receive after RC#run_config.report_interval ->
+ State#reporter_state.res
+ end.
+
+bad_sink() ->
+ {ok,Pid} = my_spawn(self()),
+ %% The get_tuple_element instruction for the matching
+ %% above was sinked into the receive loop. That will
+ %% not work (and would be bad for performance if it
+ %% would work).
+ receive
+ {ok,Pid} ->
+ ok;
+ error ->
+ exit(failed)
+ end,
+ exit(Pid, kill).
+
+my_spawn(Parent) ->
+ Pid = spawn(fun() ->
+ Parent ! {ok,self()},
+ receive _ -> ok end
+ end),
+ {ok,Pid}.
+
+tricky_recv_1() ->
+ receive
+ X=1 ->
+ id(42),
+ a;
+ X=2 ->
+ b
+ end,
+ case X of
+ 1 -> a;
+ 2 -> b
+ end.
+
+tricky_recv_2() ->
+ receive
+ X=1 ->
+ Y = case id(X) of
+ 1 -> yes;
+ _ -> no
+ end,
+ a;
+ X=2 ->
+ Y = maybe,
+ b
+ end,
+ {X,Y}.
+
+recv_after_inf_in_try() ->
+ try
+ %% Used to crash beam_kernel_to_ssa.
+ receive after infinity -> ok end
+ catch
+ _A:_B ->
+ receive after infinity -> ok end
+ end.
+
+tricky_recv_3() ->
+ {Pid, R, Request} =
+ receive
+ {{Pid0,R0}, {1, Proto0, Name0}} ->
+ {Pid0, R0,
+ [<<1:32, 1:8, Proto0:8>>,Name0,0]};
+ {{Pid1,R1}, {2, Proto1, Data1}} ->
+ {Pid1, R1,
+ <<1:32, 2:8, Proto1:8, Data1/binary>>}
+ end,
+ id({Pid,R,Request}).
+
+tricky_recv_4() ->
+ {Pid, R, Request} =
+ receive
+ {[Pid0,R0], {1, Proto0, Name0}} ->
+ {Pid0, R0,
+ [<<1:32, 1:8, Proto0:8>>,Name0,0]};
+ {[Pid1,R1], {2, Proto1, Data1}} ->
+ {Pid1, R1,
+ <<1:32, 2:8, Proto1:8, Data1/binary>>}
+ end,
+ id({Pid,R,Request}).
+
+maps(_Config) ->
+ {'EXIT',{{badmatch,#{}},_}} = (catch maps_1(any)),
+ ok.
+
+maps_1(K) ->
+ _ = id(42),
+ #{K:=V} = #{},
+ V.
+
+-record(wx_ref, {type=any_type,ref=any_ref}).
+
+cover_ssa_dead(_Config) ->
+ str = format_str(str, escapable, [], true),
+ [iolist,str] = format_str(str, escapable, iolist, true),
+ bad = format_str(str, not_escapable, [], true),
+ bad = format_str(str, not_escapable, iolist, true),
+ bad = format_str(str, escapable, [], false),
+ bad = format_str(str, escapable, [], bad),
+
+ DefWxRef = #wx_ref{},
+ {DefWxRef,77,9999,[]} = contains(#wx_ref{}, 77, 9999),
+ {DefWxRef,77.0,9999,[]} = contains(#wx_ref{}, 77.0, 9999),
+ {DefWxRef,77,9999.0,[]} = contains(#wx_ref{}, 77, 9999.0),
+ {DefWxRef,77.0,9999.0,[]} = contains(#wx_ref{}, 77.0, 9999.0),
+ {any_type,any_ref,42,43,[option]} = contains(#wx_ref{}, {42,43}, [option]),
+ {any_type,any_ref,42,43,[]} = contains(#wx_ref{}, {42,43}, []),
+ {any_type,any_ref,42.0,43,[]} = contains(#wx_ref{}, {42.0,43}, []),
+ {any_type,any_ref,42,43.0,[]} = contains(#wx_ref{}, {42,43.0}, []),
+ {any_type,any_ref,42.0,43.0,[]} = contains(#wx_ref{}, {42.0,43.0}, []),
+
+ nope = conv_alub(false, '=:='),
+ ok = conv_alub(true, '=:='),
+ ok = conv_alub(true, none),
+ error = conv_alub(false, none),
+
+ {false,false} = eval_alu(false, false, false),
+ {true,false} = eval_alu(false, false, true),
+ {false,true} = eval_alu(false, true, false),
+ {false,false} = eval_alu(false, true, true),
+ {false,true} = eval_alu(true, false, false),
+ {false,false} = eval_alu(true, false, true),
+ {true,true} = eval_alu(true, true, false),
+ {false,true} = eval_alu(true, true, true),
+
+ 100.0 = percentage(1.0, 0.0),
+ 100.0 = percentage(1, 0),
+ 0.0 = percentage(0, 0),
+ 0.0 = percentage(0.0, 0.0),
+ 40.0 = percentage(4.0, 10.0),
+ 60.0 = percentage(6, 10),
+
+ %% Cover '=:=', followed by '=/='.
+ false = 'cover__=:=__=/='(41),
+ true = 'cover__=:=__=/='(42),
+ false = 'cover__=:=__=/='(43),
+
+ %% Cover '<', followed by '=/='.
+ true = 'cover__<__=/='(41),
+ false = 'cover__<__=/='(42),
+ false = 'cover__<__=/='(43),
+
+ %% Cover '=<', followed by '=/='.
+ true = 'cover__=<__=/='(41),
+ true = 'cover__=<__=/='(42),
+ false = 'cover__=<__=/='(43),
+
+ %% Cover '>=', followed by '=/='.
+ false = 'cover__>=__=/='(41),
+ true = 'cover__>=__=/='(42),
+ true = 'cover__>=__=/='(43),
+
+ %% Cover '>', followed by '=/='.
+ false = 'cover__>__=/='(41),
+ false = 'cover__>__=/='(42),
+ true = 'cover__>__=/='(43),
+
+ ok.
+
+'cover__=:=__=/='(X) when X =:= 42 -> X =/= 43;
+'cover__=:=__=/='(_) -> false.
+
+'cover__<__=/='(X) when X < 42 -> X =/= 42;
+'cover__<__=/='(_) -> false.
+
+'cover__=<__=/='(X) when X =< 42 -> X =/= 43;
+'cover__=<__=/='(_) -> false.
+
+'cover__>=__=/='(X) when X >= 42 -> X =/= 41;
+'cover__>=__=/='(_) -> false.
+
+'cover__>__=/='(X) when X > 42 -> X =/= 42;
+'cover__>__=/='(_) -> false.
+
+format_str(Str, FormatData, IoList, EscChars) ->
+ Escapable = FormatData =:= escapable,
+ case id(Str) of
+ IoStr when Escapable, EscChars, IoList == [] ->
+ id(IoStr);
+ IoStr when Escapable, EscChars ->
+ [IoList,id(IoStr)];
+ _ ->
+ bad
+ end.
+
+contains(This, X, Y) when is_record(This, wx_ref), is_number(X), is_number(Y) ->
+ {This,X,Y,[]};
+contains(#wx_ref{type=ThisT,ref=ThisRef}, {CX,CY}, Options)
+ when is_number(CX), is_number(CY), is_list(Options) ->
+ {ThisT,ThisRef,CX,CY,Options}.
+
+conv_alub(HasDst, CmpOp) ->
+ case (not HasDst) andalso CmpOp =/= none of
+ true -> nope;
+ false ->
+ case HasDst of
+ false -> error;
+ true -> ok
+ end
+ end.
+
+eval_alu(Sign1, Sign2, N) ->
+ V = (Sign1 andalso Sign2 andalso (not N))
+ or ((not Sign1) andalso (not Sign2) andalso N),
+ C = (Sign1 andalso Sign2)
+ or ((not N) andalso (Sign1 orelse Sign2)),
+ {V,C}.
+
+percentage(Divident, Divisor) ->
+ if Divisor == 0 andalso Divident /= 0 ->
+ 100.0;
+ Divisor == 0 ->
+ 0.0;
+ true ->
+ Divident / Divisor * 100
+ end.
+
+combine_sw(_Config) ->
+ [a] = do_comb_sw_1(a),
+ [b,b] = do_comb_sw_1(b),
+ [c] = do_comb_sw_1(c),
+ [c] = do_comb_sw_1(c),
+ [] = do_comb_sw_1(z),
+
+ [a] = do_comb_sw_2(a),
+ [b2,b1] = do_comb_sw_2(b),
+ [c] = do_comb_sw_2(c),
+ [c] = do_comb_sw_2(c),
+ [] = do_comb_sw_2(z),
+
+ ok.
+
+do_comb_sw_1(X) ->
+ put(?MODULE, []),
+ if
+ X == a; X == b ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ if
+ X == b; X == c ->
+ put(?MODULE, [X|get(?MODULE)]);
+ true ->
+ ok
+ end,
+ erase(?MODULE).
+
+do_comb_sw_2(X) ->
+ put(?MODULE, []),
+ case X of
+ a ->
+ put(?MODULE, [a|get(?MODULE)]);
+ b ->
+ put(?MODULE, [b1|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ case X of
+ b ->
+ put(?MODULE, [b2|get(?MODULE)]);
+ c ->
+ put(?MODULE, [c|get(?MODULE)]);
+ _ ->
+ ok
+ end,
+ erase(?MODULE).
+
+%% The identity function.
+id(I) -> I.
diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl
index 061076b3ff..a4459b95bf 100644
--- a/lib/compiler/test/beam_type_SUITE.erl
+++ b/lib/compiler/test/beam_type_SUITE.erl
@@ -21,9 +21,10 @@
-export([all/0,suite/0,groups/0,init_per_suite/1,end_per_suite/1,
init_per_group/2,end_per_group/2,
- integers/1,coverage/1,booleans/1,setelement/1,cons/1,
- tuple/1,record_float/1,binary_float/1,float_compare/1,
- arity_checks/1,elixir_binaries/1,find_best/1]).
+ integers/1,numbers/1,coverage/1,booleans/1,setelement/1,
+ cons/1,tuple/1,record_float/1,binary_float/1,float_compare/1,
+ arity_checks/1,elixir_binaries/1,find_best/1,
+ test_size/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -33,6 +34,7 @@ all() ->
groups() ->
[{p,[parallel],
[integers,
+ numbers,
coverage,
booleans,
setelement,
@@ -43,7 +45,8 @@ groups() ->
float_compare,
arity_checks,
elixir_binaries,
- find_best
+ find_best,
+ test_size
]}].
init_per_suite(Config) ->
@@ -123,6 +126,59 @@ do_integers_5(X0, Y0) ->
3 -> three
end.
+numbers(_Config) ->
+ Int = id(42),
+ true = is_integer(Int),
+ true = is_number(Int),
+ false = is_float(Int),
+
+ Float = id(42.0),
+ true = is_float(Float),
+ true = is_number(Float),
+ false = is_integer(Float),
+
+ Number = id(1) + id(2),
+ true = is_number(Number),
+ true = is_integer(Number),
+ false = is_float(Number),
+
+ AnotherNumber = id(99.0) + id(1),
+ true = is_float(AnotherNumber),
+ true = is_number(AnotherNumber),
+ false = is_integer(AnotherNumber),
+
+ NotNumber = id(atom),
+ true = is_atom(NotNumber),
+ false = is_number(NotNumber),
+ false = is_integer(NotNumber),
+ false = is_float(NotNumber),
+
+ true = is_number(Int),
+ true = is_number(Float),
+ true = is_number(Number),
+ true = is_number(AnotherNumber),
+
+ %% Cover beam_ssa_type:join/2.
+
+ Join1 = case id(a) of
+ a -> 3 + id(7); %Number.
+ b -> id(5) / id(2) %Float.
+ end,
+ true = is_integer(Join1),
+
+ Join2 = case id(a) of
+ a -> id(5) / 2; %Float.
+ b -> 3 + id(7) %Number.
+ end,
+ true = is_float(Join2),
+
+ %% Cover beam_ssa_type:meet/2.
+
+ Meet1 = id(0) + -10.0, %Float.
+ 10.0 = abs(Meet1), %Number.
+
+ ok.
+
coverage(Config) ->
{'EXIT',{badarith,_}} = (catch id(1) bsl 0.5),
{'EXIT',{badarith,_}} = (catch id(2.0) bsl 2),
@@ -160,10 +216,31 @@ coverage(Config) ->
ok.
booleans(_Config) ->
- {'EXIT',{{case_clause,_},_}} = (catch do_booleans(42)),
+ {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)),
+
+ AnyAtom = id(atom),
+ true = is_atom(AnyAtom),
+ false = is_boolean(AnyAtom),
+
+ MaybeBool = id(maybe),
+ case MaybeBool of
+ true -> ok;
+ maybe -> ok;
+ false -> ok
+ end,
+ false = is_boolean(MaybeBool),
+
+ NotBool = id(a),
+ case NotBool of
+ a -> ok;
+ b -> ok;
+ c -> ok
+ end,
+ false = is_boolean(NotBool),
+
ok.
-do_booleans(B) ->
+do_booleans_1(B) ->
case is_integer(B) of
yes -> yes;
no -> no
@@ -177,13 +254,59 @@ setelement(_Config) ->
cons(_Config) ->
[did] = cons(assigned, did),
+
+ true = cons_is_empty_list([]),
+ false = cons_is_empty_list([a]),
+
+ false = cons_not(true),
+ true = cons_not(false),
+
+ {$a,"bc"} = cons_hdtl(true),
+ {$d,"ef"} = cons_hdtl(false),
ok.
cons(assigned, Instrument) ->
[Instrument] = [did].
+cons_is_empty_list(L) ->
+ Cons = case L of
+ [] -> "true";
+ _ -> "false"
+ end,
+ id(1),
+ case Cons of
+ "true" -> true;
+ "false" -> false
+ end.
+
+cons_not(B) ->
+ Cons = case B of
+ true -> "true";
+ false -> "false"
+ end,
+ id(1),
+ case Cons of
+ "true" -> false;
+ "false" -> true
+ end.
+
+cons_hdtl(B) ->
+ Cons = case B of
+ true -> "abc";
+ false -> "def"
+ end,
+ id(1),
+ {id(hd(Cons)),id(tl(Cons))}.
+
+-record(bird, {a=a,b=id(42)}).
+
tuple(_Config) ->
{'EXIT',{{badmatch,{necessary}},_}} = (catch do_tuple()),
+
+ [] = [X || X <- [], #bird{a = a} == {r,X,foo}],
+ [] = [X || X <- [], #bird{b = b} == {bird,X}],
+ [] = [X || X <- [], 3 == X#bird.a],
+
ok.
do_tuple() ->
@@ -320,6 +443,15 @@ find_best([], <<"a">>) ->
find_best([], nil) ->
{error,<<"should not get here">>}.
+test_size(_Config) ->
+ 2 = do_test_size({a,b}),
+ 4 = do_test_size(<<42:32>>),
+ ok.
+
+do_test_size(Term) when is_tuple(Term) ->
+ size(Term);
+do_test_size(Term) when is_binary(Term) ->
+ size(Term).
id(I) ->
I.
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index d3e544a9cc..661b48a080 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -34,7 +34,7 @@
undef_label/1,illegal_instruction/1,failing_gc_guard_bif/1,
map_field_lists/1,cover_bin_opt/1,
val_dsetel/1,bad_tuples/1,bad_try_catch_nesting/1,
- receive_stacked/1]).
+ receive_stacked/1,aliased_types/1]).
-include_lib("common_test/include/ct.hrl").
@@ -63,7 +63,7 @@ groups() ->
undef_label,illegal_instruction,failing_gc_guard_bif,
map_field_lists,cover_bin_opt,val_dsetel,
bad_tuples,bad_try_catch_nesting,
- receive_stacked]}].
+ receive_stacked,aliased_types]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -579,6 +579,21 @@ receive_stacked(Config) ->
ok.
+%% ERL-735: validator failed to track types on aliased registers, rejecting
+%% legitimate optimizations.
+%%
+%% move x0 y0
+%% bif hd L1 x0
+%% get_hd y0 %% The validator failed to see that y0 was a list
+aliased_types(Config) when is_list(Config) ->
+ Bug = lists:seq(1, 5),
+ if
+ Config =/= [gurka, gaffel] -> %% Pointless branch.
+ _ = hd(Bug),
+ lists:seq(1, 5),
+ hd(Bug)
+ end.
+
%%%-------------------------------------------------------------------------
transform_remove(Remove, Module) ->
diff --git a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
index a60ca1e89a..c7610971f1 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/bad_bin_match.S
@@ -11,5 +11,5 @@
{label,1}.
{func_info,{atom,t},{atom,t},1}.
{label,2}.
- {test,bs_start_match2,{f,1},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,1},1,[{x,0}],{x,0}}.
return.
diff --git a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
index cca052a9c4..5b974119c6 100644
--- a/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
+++ b/lib/compiler/test/beam_validator_SUITE_data/receive_stacked.S
@@ -172,7 +172,7 @@
{allocate_zero,1,0}.
{label,28}.
{loop_rec,{f,30},{x,0}}.
- {test,bs_start_match2,{f,29},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,29},1,[{x,0}],{x,0}}.
{test,bs_get_integer2,
{f,29},
1,
@@ -219,7 +219,7 @@
{allocate_zero,1,0}.
{label,33}.
{loop_rec,{f,35},{x,0}}.
- {test,bs_start_match2,{f,34},1,[{x,0},0],{x,0}}.
+ {test,bs_start_match3,{f,34},1,[{x,0}],{x,0}}.
{test,bs_get_integer2,
{f,34},
1,
@@ -262,7 +262,7 @@
{allocate_zero,1,0}.
{label,38}.
{loop_rec,{f,40},{x,0}}.
- {test,bs_start_match2,{f,39},1,[{x,0},0],{x,1}}.
+ {test,bs_start_match3,{f,39},1,[{x,0}],{x,1}}.
{test,bs_get_integer2,
{f,39},
2,
diff --git a/lib/compiler/test/bif_SUITE.erl b/lib/compiler/test/bif_SUITE.erl
index c4c709eb3a..42ba5d5365 100644
--- a/lib/compiler/test/bif_SUITE.erl
+++ b/lib/compiler/test/bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/bs_bincomp_SUITE.erl b/lib/compiler/test/bs_bincomp_SUITE.erl
index 42361ea546..0419b16eea 100644
--- a/lib/compiler/test/bs_bincomp_SUITE.erl
+++ b/lib/compiler/test/bs_bincomp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
init_per_group/2,end_per_group/2,
byte_aligned/1,bit_aligned/1,extended_byte_aligned/1,
extended_bit_aligned/1,mixed/1,filters/1,trim_coverage/1,
- nomatch/1,sizes/1,general_expressions/1]).
+ nomatch/1,sizes/1,general_expressions/1,matched_out_size/1]).
-include_lib("common_test/include/ct.hrl").
@@ -35,7 +35,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[byte_aligned, bit_aligned, extended_byte_aligned,
extended_bit_aligned, mixed, filters, trim_coverage,
- nomatch, sizes, general_expressions].
+ nomatch, sizes, general_expressions, matched_out_size].
groups() ->
[].
@@ -338,6 +338,13 @@ general_expressions(_) ->
-undef(BAD).
+matched_out_size(Config) when is_list(Config) ->
+ <<1, 2>> = matched_out_size_1(<<4, 1:4, 4, 2:4>>),
+ ok.
+
+matched_out_size_1(Binary) ->
+ << <<X>> || <<S, X:S>> <= Binary>>.
+
cs_init() ->
erts_debug:set_internal_state(available_internal_state, true),
ok.
diff --git a/lib/compiler/test/bs_bit_binaries_SUITE.erl b/lib/compiler/test/bs_bit_binaries_SUITE.erl
index 17faa012bc..526769f3a6 100644
--- a/lib/compiler/test/bs_bit_binaries_SUITE.erl
+++ b/lib/compiler/test/bs_bit_binaries_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index e737839575..0c6db96081 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -40,7 +40,10 @@
map_and_binary/1,unsafe_branch_caching/1,
bad_literals/1,good_literals/1,constant_propagation/1,
parse_xml/1,get_payload/1,escape/1,num_slots_different/1,
- beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1]).
+ beam_bsm/1,guard/1,is_ascii/1,non_opt_eq/1,
+ expression_before_match/1,erl_689/1,restore_on_call/1,
+ restore_after_catch/1,matches_on_parameter/1,big_positions/1,
+ matching_meets_apply/1,bs_start_match2_defs/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -56,7 +59,7 @@ all() ->
[{group,p}].
groups() ->
- [{p,[parallel],
+ [{p,[],
[size_shadow,int_float,otp_5269,null_fields,wiger,
bin_tail,save_restore,
partitioned_bs_match,function_clause,unit,
@@ -72,7 +75,10 @@ groups() ->
map_and_binary,unsafe_branch_caching,
bad_literals,good_literals,constant_propagation,parse_xml,
get_payload,escape,num_slots_different,
- beam_bsm,guard,is_ascii,non_opt_eq]}].
+ beam_bsm,guard,is_ascii,non_opt_eq,
+ expression_before_match,erl_689,restore_on_call,
+ matches_on_parameter,big_positions,
+ matching_meets_apply,bs_start_match2_defs]}].
init_per_suite(Config) ->
@@ -248,6 +254,12 @@ bin_tail(Config) when is_list(Config) ->
ok = bin_tail_e(<<2:2,1:1,1:5,42:64>>),
error = bin_tail_e(<<3:2,1:1,1:5,42:64>>),
error = bin_tail_e(<<>>),
+
+ MD5 = erlang:md5(<<42>>),
+ <<"abc">> = bin_tail_f(<<MD5/binary,"abc">>, MD5, 3),
+ error = bin_tail_f(<<MD5/binary,"abc">>, MD5, 999),
+ {'EXIT',{_,_}} = (catch bin_tail_f(<<0:16/unit:8>>, MD5, 0)),
+
ok.
bin_tail_c(Bin, Offset) ->
@@ -304,6 +316,14 @@ bin_tail_e_var(Bin) ->
<<2:2,_:1,1:5,Tail/binary>> -> Tail;
_ -> error
end.
+
+bin_tail_f(Bin, MD5, Size) ->
+ case Bin of
+ <<MD5:16/binary, Tail:Size/binary>> ->
+ Tail;
+ <<MD5:16/binary, _/binary>> ->
+ error
+ end.
save_restore(Config) when is_list(Config) ->
0 = save_restore_1(<<0:2,42:6>>),
@@ -455,6 +475,15 @@ unit(Config) when is_list(Config) ->
127 = peek7(<<127:7>>),
100 = peek7(<<100:7,19:7>>),
fc(peek7, [<<1,2>>], catch peek7(<<1,2>>)),
+
+ 1 = unit_opt(1, -1),
+ 8 = unit_opt(8, -1),
+
+ <<1:32,"abc">> = unit_opt_2(<<1:32,"abc">>),
+ <<"def">> = unit_opt_2(<<2:32,"def">>),
+ {'EXIT',_} = (catch unit_opt_2(<<1:32,33:7>>)),
+ {'EXIT',_} = (catch unit_opt_2(<<2:32,55:7>>)),
+
ok.
peek1(<<B:8,_/bitstring>>) -> B.
@@ -465,6 +494,27 @@ peek8(<<B:8,_/binary>>) -> B.
peek16(<<B:16,_/binary-unit:16>>) -> B.
+unit_opt(U, X) ->
+ %% Cover type analysis in beam_ssa_type.
+ Bin = case U of
+ 1 -> <<X:7>>;
+ 8 -> <<X>>
+ end,
+ %% The type of Bin will be set to {binary,gcd(1, 8)}.
+ case Bin of
+ <<_/binary-unit:8>> -> 8;
+ <<_/binary-unit:1>> -> 1
+ end.
+
+unit_opt_2(<<St:32,KO/binary>> = Bin0) ->
+ Bin = if
+ St =:= 1 ->
+ Bin0;
+ St =:= 2 ->
+ <<KO/binary>>
+ end,
+ id(Bin).
+
shared_sub_bins(Config) when is_list(Config) ->
{15,[<<>>,<<5>>,<<4,5>>,<<3,4,5>>,<<2,3,4,5>>]} = sum(<<1,2,3,4,5>>, [], 0),
ok.
@@ -1688,7 +1738,190 @@ non_opt_eq([_|_], <<_,_/binary>>) ->
non_opt_eq([], <<>>) ->
true.
+%% ERL-689
+
+erl_689(_Config) ->
+ {{0, 0, 0}, <<>>} = do_erl_689_1(<<0>>, ?MODULE),
+ {{2018, 8, 7}, <<>>} = do_erl_689_1(<<4,2018:16/little,8,7>>, ?MODULE),
+ {{0, 0, 0}, <<>>} = do_erl_689_2(?MODULE, <<0>>),
+ {{2018, 8, 7}, <<>>} = do_erl_689_2(?MODULE, <<4,2018:16/little,8,7>>),
+ ok.
+
+do_erl_689_1(Arg1, Arg2) ->
+ Res = do_erl_689_1a(Arg1, Arg2),
+ Res = do_erl_689_1b(Arg1, Arg2).
+
+do_erl_689_2(Arg1, Arg2) ->
+ Res = do_erl_689_2a(Arg1, Arg2),
+ Res = do_erl_689_2b(Arg1, Arg2).
+
+do_erl_689_1a(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_1b(<<Length, Data/binary>>, _) ->
+ case {Data, Length} of
+ {_, 0} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {<<Y:16/little, M, D, Rest/binary>>, 4} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2a(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ {{Y, M, D}, Rest}
+ end.
+
+do_erl_689_2b(_, <<Length, Data/binary>>) ->
+ case {Length, Data} of
+ {0, _} ->
+ %% bs_context_to_binary would incorrectly set Data to the original
+ %% binary (before matching in the function head).
+ id(0),
+ {{0, 0, 0}, Data};
+ {4, <<Y:16/little, M, D, Rest/binary>>} ->
+ id(1),
+ {{Y, M, D}, Rest}
+ end.
+
+%% ERL-753
+
+bs_start_match2_defs(_Config) ->
+ {<<"http://127.0.0.1:1234/vsaas/hello">>} = api_url(<<"hello">>, dummy),
+ {"https://127.0.0.1:4321/vsaas/hello"} = api_url({https, "hello"}, dummy).
+
+api_url(URL, Auth) ->
+ Header = [],
+ case URL of
+ <<_/binary>> -> {<<"http://127.0.0.1:1234/vsaas/",URL/binary>>};
+ {https, [_|_] = URL1} -> {"https://127.0.0.1:4321/vsaas/"++URL1}
+ end.
+
check(F, R) ->
R = F().
+%% Make sure that an expression that comes between function start and a match
+%% expression passes validation.
+expression_before_match(Config) when is_list(Config) ->
+ <<_,R/binary>> = id(<<0,1,2,3>>),
+ {1, <<2,3>>} = expression_before_match_1(R),
+ ok.
+
+expression_before_match_1(R) ->
+ A = id(1),
+ case R of
+ <<1,Bar/binary>> -> {A, Bar};
+ <<>> -> {A, baz}
+ end.
+
+%% Make sure that context positions are updated on calls.
+restore_on_call(Config) when is_list(Config) ->
+ ok = restore_on_call_1(<<0, 1, 2>>).
+
+restore_on_call_1(<<0, Rest/binary>>) ->
+ <<2>> = restore_on_call_2(Rest),
+ <<2>> = restore_on_call_2(Rest), %% {badmatch, <<>>} on missing restore.
+ ok.
+
+restore_on_call_2(<<1, Rest/binary>>) -> Rest;
+restore_on_call_2(Other) -> Other.
+
+%% 'catch' must invalidate positions.
+restore_after_catch(Config) when is_list(Config) ->
+ <<0, 1>> = restore_after_catch_1(<<0, 1>>),
+ ok.
+
+restore_after_catch_1(<<A/binary>>) ->
+ try throw_after_byte(A) of
+ _ -> impossible
+ catch
+ throw:_Any ->
+ %% Will equal <<1>> if the bug is present.
+ A
+ end.
+
+throw_after_byte(<<_,_/binary>>) ->
+ throw(away).
+
+matches_on_parameter(Config) when is_list(Config) ->
+ %% This improves coverage for matching on "naked" parameters.
+ {<<"urka">>, <<"a">>} = matches_on_parameter_1(<<"gurka">>),
+ ok = (catch matches_on_parameter_2(<<"10001110101">>, 0)).
+
+matches_on_parameter_1(Bin) ->
+ <<"g", A/binary>> = Bin,
+ <<_,_,"rk", B/binary>> = Bin,
+ {A, B}.
+
+matches_on_parameter_2(Bin, Offset) ->
+ <<_:Offset, Bit:1, Rest/bits>> = Bin,
+ case bit_size(Rest) of
+ 0 -> throw(ok);
+ _ -> [Bit | matches_on_parameter_2(Bin, Offset + 1)]
+ end.
+
+big_positions(Config) when is_list(Config) ->
+ %% This provides coverage for when match context positions no longer fit
+ %% into an immediate on 32-bit platforms.
+
+ A = <<0:((1 bsl 27) - 8), $A, 1:1, "gurka", $A>>,
+ B = <<0:((1 bsl 27) - 8), $B, "hello", $B>>,
+
+ {a,$A} = bp_start_match(A),
+ {b,$B} = bp_start_match(B),
+ {a,$A} = bp_getpos(A),
+ {b,$B} = bp_getpos(B),
+
+ ok.
+
+%% After the first iteration the context's position will no longer fit into an
+%% immediate. To improve performance the bs_start_match3 instruction will
+%% return a new context with an updated base position so that we won't have to
+%% resort to using bigints.
+bp_start_match(<<_:(1 bsl 27),T/bits>>) -> bp_start_match(T);
+bp_start_match(<<1:1,"gurka",A>>) -> {a,A};
+bp_start_match(<<"hello",B>>) -> {b,B}.
+
+%% This is a corner case where the above didn't work perfectly; if the position
+%% was _just_ small enough to fit into an immediate when bs_start_match3 was
+%% hit, but too large at bs_get_position, then it must be saved as a bigint.
+bp_getpos(<<_:((1 bsl 27) - 8),T/bits>>) -> bp_getpos(T);
+bp_getpos(<<A,1:1,"gurka",A>>) -> {a,A};
+bp_getpos(<<B,"hello",B>>) -> {b,B}.
+
+matching_meets_apply(_Config) ->
+ <<"abc">> = do_matching_meets_apply(<<"/abc">>, []),
+ 42 = do_matching_meets_apply(<<"">>, {erlang,-42}),
+ 100 = do_matching_meets_apply(no_binary, {erlang,-100}),
+ ok.
+
+do_matching_meets_apply(<<$/, Rest/binary>>, _Handler) ->
+ id(Rest);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_a) ->
+ %% Used to crash the compiler because variables in a remote
+ %% were not handled properly by beam_ssa_bsm.
+ Name:foo(gurka);
+do_matching_meets_apply(<<_/binary>>=Name, never_matches_b) ->
+ %% Another case of the above.
+ foo:Name(gurka);
+do_matching_meets_apply(_Bin, {Handler, State}) ->
+ %% Another case of the above.
+ Handler:abs(State).
+
+
id(I) -> I.
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index 4330677260..8ea4a849ec 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl
index 3ba3ce7cdf..74f9dbd9b4 100644
--- a/lib/compiler/test/compilation_SUITE.erl
+++ b/lib/compiler/test/compilation_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -170,7 +170,7 @@ try_it(Module, Conf) ->
atom_to_list(Module)),
Out = proplists:get_value(priv_dir,Conf),
io:format("Compiling: ~s\n", [Src]),
- CompRc0 = compile:file(Src, [clint0,clint,{outdir,Out},report,
+ CompRc0 = compile:file(Src, [clint0,clint,ssalint,{outdir,Out},report,
bin_opt_info|OtherOpts]),
io:format("Result: ~p\n",[CompRc0]),
{ok,_Mod} = CompRc0,
@@ -189,7 +189,7 @@ try_it(Module, Conf) ->
ct:timetrap(Timetrap),
io:format("Compiling (with old inliner): ~s\n", [Src]),
- CompRc2 = compile:file(Src, [clint,
+ CompRc2 = compile:file(Src, [clint,ssalint,
{outdir,Out},report,bin_opt_info,
{inline,1000}|OtherOpts]),
io:format("Result: ~p\n",[CompRc2]),
@@ -355,7 +355,7 @@ compile_compiler(Files, OutDir, Version, InlineOpts) ->
io:format("~ts", [code:which(compile)]),
io:format("Compiling ~s into ~ts", [Version,OutDir]),
Opts = [report,
- clint0,clint,
+ clint0,clint,ssalint,
bin_opt_info,
{outdir,OutDir},
{d,'COMPILER_VSN',"\""++Version++"\""},
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index 2206927ed1..8d8bbe9543 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -36,7 +36,7 @@
core_roundtrip/1, asm/1, optimized_guards/1,
sys_pre_attributes/1, dialyzer/1,
warnings/1, pre_load_check/1, env_compiler_options/1,
- bc_options/1
+ bc_options/1, deterministic_include/1, deterministic_paths/1
]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -53,7 +53,7 @@ all() ->
cover, env, core_pp, core_roundtrip, asm, optimized_guards,
sys_pre_attributes, dialyzer, warnings, pre_load_check,
env_compiler_options, custom_debug_info, bc_options,
- custom_compile_info].
+ custom_compile_info, deterministic_include, deterministic_paths].
groups() ->
[].
@@ -385,16 +385,18 @@ do_file_listings(DataDir, PrivDir, [File|Files]) ->
do_listing(Simple, TargetDir, dcbsm, ".core_bsm"),
do_listing(Simple, TargetDir, dsetel, ".dsetel"),
do_listing(Simple, TargetDir, dkern, ".kernel"),
+ do_listing(Simple, TargetDir, dssa, ".ssa"),
+ do_listing(Simple, TargetDir, dssaopt, ".ssaopt"),
+ do_listing(Simple, TargetDir, dprecg, ".precodegen"),
do_listing(Simple, TargetDir, dcg, ".codegen"),
do_listing(Simple, TargetDir, dblk, ".block"),
do_listing(Simple, TargetDir, dexcept, ".except"),
do_listing(Simple, TargetDir, dbs, ".bs"),
- do_listing(Simple, TargetDir, dtype, ".type"),
- do_listing(Simple, TargetDir, ddead, ".dead"),
do_listing(Simple, TargetDir, djmp, ".jump"),
do_listing(Simple, TargetDir, dclean, ".clean"),
do_listing(Simple, TargetDir, dpeep, ".peep"),
do_listing(Simple, TargetDir, dopt, ".optimize"),
+ do_listing(Simple, TargetDir, diffable, ".S"),
%% First clean up.
Listings = filename:join(PrivDir, listings),
@@ -424,6 +426,9 @@ listings_big(Config) when is_list(Config) ->
do_listing(Big, TargetDir, 'E'),
do_listing(Big, TargetDir, 'P'),
do_listing(Big, TargetDir, dkern, ".kernel"),
+ do_listing(Big, TargetDir, dssa, ".ssa"),
+ do_listing(Big, TargetDir, dssaopt, ".ssaopt"),
+ do_listing(Big, TargetDir, dprecg, ".precodegen"),
do_listing(Big, TargetDir, to_dis, ".dis"),
TargetNoext = filename:rootname(Target, code:objfile_extension()),
@@ -920,7 +925,7 @@ do_core_pp_1(M, A, Outdir) ->
ok = file:delete(CoreFile),
%% Compile as usual (including optimizations).
- compile_forms(M, Core, [clint,from_core,binary]),
+ compile_forms(M, Core, [clint,ssalint,from_core,binary]),
%% Don't optimize to test that we are not dependent
%% on the Core Erlang optmimization passes.
@@ -929,7 +934,7 @@ do_core_pp_1(M, A, Outdir) ->
%% records; if sys_core_fold was run it would fix
%% that; if sys_core_fold was not run v3_kernel would
%% crash.)
- compile_forms(M, Core, [clint,from_core,no_copt,binary]),
+ compile_forms(M, Core, [clint,ssalint,from_core,no_copt,binary]),
ok.
@@ -1242,21 +1247,11 @@ do_opt_guards_fun([_|Is]) ->
do_opt_guards_fun(Is);
do_opt_guards_fun([]) -> [].
-is_exception(bs_match_SUITE, {matching_and_andalso_2,2}) -> true;
-is_exception(bs_match_SUITE, {matching_and_andalso_3,2}) -> true;
is_exception(guard_SUITE, {'-complex_not/1-fun-4-',1}) -> true;
is_exception(guard_SUITE, {'-complex_not/1-fun-5-',1}) -> true;
-is_exception(guard_SUITE, {basic_andalso_orelse,1}) -> true;
is_exception(guard_SUITE, {bad_guards,1}) -> true;
-is_exception(guard_SUITE, {bad_guards_2,2}) -> true;
is_exception(guard_SUITE, {bad_guards_3,2}) -> true;
-is_exception(guard_SUITE, {cqlc,4}) -> true;
-is_exception(guard_SUITE, {csemi7,3}) -> true;
-is_exception(guard_SUITE, {misc,1}) -> true;
is_exception(guard_SUITE, {nested_not_2b,4}) -> true;
-is_exception(guard_SUITE, {tricky_1,2}) -> true;
-is_exception(map_SUITE, {map_guard_update,2}) -> true;
-is_exception(map_SUITE, {map_guard_update_variables,3}) -> true;
is_exception(_, _) -> false.
sys_pre_attributes(Config) ->
@@ -1478,18 +1473,25 @@ bc_options(Config) ->
101 = highest_opcode(DataDir, small_float, [no_get_hd_tl,no_line_info]),
103 = highest_opcode(DataDir, big,
- [no_get_hd_tl,no_record_opt,
+ [no_put_tuple2,
+ no_get_hd_tl,no_ssa_opt_record,
no_line_info,no_stack_trimming]),
125 = highest_opcode(DataDir, small_float,
- [no_get_hd_tl,no_line_info,no_float_opt]),
+ [no_get_hd_tl,no_line_info,no_ssa_opt_float]),
132 = highest_opcode(DataDir, small,
- [no_get_hd_tl,no_record_opt,no_float_opt,no_line_info]),
+ [no_put_tuple2,no_get_hd_tl,no_ssa_opt_record,
+ no_ssa_opt_float,no_line_info,no_bsm3]),
- 136 = highest_opcode(DataDir, big, [no_get_hd_tl,no_record_opt,no_line_info]),
+ 153 = highest_opcode(DataDir, small, [r20]),
+ 153 = highest_opcode(DataDir, small, [r21]),
- 153 = highest_opcode(DataDir, big, [no_get_hd_tl,no_record_opt]),
+ 136 = highest_opcode(DataDir, big, [no_put_tuple2,no_get_hd_tl,
+ no_ssa_opt_record,no_line_info]),
+
+ 153 = highest_opcode(DataDir, big, [no_put_tuple2,no_get_hd_tl,
+ no_ssa_opt_record]),
153 = highest_opcode(DataDir, big, [r16]),
153 = highest_opcode(DataDir, big, [r17]),
153 = highest_opcode(DataDir, big, [r18]),
@@ -1501,9 +1503,10 @@ bc_options(Config) ->
158 = highest_opcode(DataDir, small_maps, [r18]),
158 = highest_opcode(DataDir, small_maps, [r19]),
158 = highest_opcode(DataDir, small_maps, [r20]),
- 158 = highest_opcode(DataDir, small_maps, []),
+ 158 = highest_opcode(DataDir, small_maps, [r21]),
- 163 = highest_opcode(DataDir, big, []),
+ 164 = highest_opcode(DataDir, small_maps, []),
+ 164 = highest_opcode(DataDir, big, []),
ok.
@@ -1514,6 +1517,47 @@ highest_opcode(DataDir, Mod, Opt) ->
<<16:32,0:32,HighestOpcode:32,_/binary>> = Code,
HighestOpcode.
+deterministic_include(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ Simple = filename:join(DataDir, "simple"),
+
+ %% Files without +deterministic should differ if their include paths do,
+ %% as their debug info will be different.
+ {ok,_,NonDetA} = compile:file(Simple, [binary, {i,"gurka"}]),
+ {ok,_,NonDetB} = compile:file(Simple, [binary, {i,"gaffel"}]),
+ true = NonDetA =/= NonDetB,
+
+ %% ... but files with +deterministic shouldn't.
+ {ok,_,DetC} = compile:file(Simple, [binary, deterministic, {i,"gurka"}]),
+ {ok,_,DetD} = compile:file(Simple, [binary, deterministic, {i,"gaffel"}]),
+ true = DetC =:= DetD,
+
+ ok.
+
+deterministic_paths(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+
+ %% Files without +deterministic should differ if they were compiled from a
+ %% different directory.
+ true = deterministic_paths_1(DataDir, "simple", []),
+
+ %% ... but files with +deterministic shouldn't.
+ false = deterministic_paths_1(DataDir, "simple", [deterministic]),
+
+ ok.
+
+deterministic_paths_1(DataDir, Name, Opts) ->
+ Simple = filename:join(DataDir, "simple"),
+ {ok, Cwd} = file:get_cwd(),
+ try
+ {ok,_,A} = compile:file(Simple, [binary | Opts]),
+ ok = file:set_cwd(DataDir),
+ {ok,_,B} = compile:file(Name, [binary | Opts]),
+ A =/= B
+ after
+ file:set_cwd(Cwd)
+ end.
+
%%%
%%% Utilities.
%%%
diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl
index 23f420f5f2..e5611e99d1 100644
--- a/lib/compiler/test/core_SUITE.erl
+++ b/lib/compiler/test/core_SUITE.erl
@@ -29,7 +29,7 @@
bs_shadowed_size_var/1,
cover_v3_kernel_1/1,cover_v3_kernel_2/1,cover_v3_kernel_3/1,
cover_v3_kernel_4/1,cover_v3_kernel_5/1,
- non_variable_apply/1,name_capture/1]).
+ non_variable_apply/1,name_capture/1,fun_letrec_effect/1]).
-include_lib("common_test/include/ct.hrl").
@@ -57,7 +57,7 @@ groups() ->
bs_shadowed_size_var,
cover_v3_kernel_1,cover_v3_kernel_2,cover_v3_kernel_3,
cover_v3_kernel_4,cover_v3_kernel_5,
- non_variable_apply,name_capture
+ non_variable_apply,name_capture,fun_letrec_effect
]}].
@@ -94,6 +94,7 @@ end_per_group(_GroupName, Config) ->
?comp(cover_v3_kernel_5).
?comp(non_variable_apply).
?comp(name_capture).
+?comp(fun_letrec_effect).
try_it(Mod, Conf) ->
Src = filename:join(proplists:get_value(data_dir, Conf),
diff --git a/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
new file mode 100644
index 0000000000..ab6f5b7940
--- /dev/null
+++ b/lib/compiler/test/core_SUITE_data/fun_letrec_effect.core
@@ -0,0 +1,25 @@
+module 'fun_letrec_effect' ['fun_letrec_effect'/0, 'ok'/0, 'wat'/0]
+attributes []
+
+'fun_letrec_effect'/0 =
+ fun () ->
+ do apply 'wat'/0()
+ receive
+ <'bar'> when 'true' -> 'ok'
+ <_0> when 'true' -> 'failed'
+ after 'infinity' ->
+ 'true'
+
+%% The return value (bar) of the fun was optimized away because the result of
+%% the `letrec ... in` was unused, despite the fun's return value being
+%% relevant for the side-effect of the expression.
+'wat'/0 =
+ fun () ->
+ let <Self> = call 'erlang':'self'() in
+ do letrec 'f'/0 = fun () ->
+ do call 'maps':'put'('foo', 'bar', ~{}~)
+ 'bar'
+ in call 'erlang':'send'(Self, apply 'f'/0())
+ 'undefined'
+
+end
diff --git a/lib/compiler/test/core_alias_SUITE.erl b/lib/compiler/test/core_alias_SUITE.erl
index 4f96576621..737b1567d4 100644
--- a/lib/compiler/test/core_alias_SUITE.erl
+++ b/lib/compiler/test/core_alias_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index aa357dbc9c..3fca1434ae 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -28,7 +28,7 @@
mixed_matching_clauses/1,unnecessary_building/1,
no_no_file/1,configuration/1,supplies/1,
redundant_stack_frame/1,export_from_case/1,
- empty_values/1]).
+ empty_values/1,cover_letrec_effect/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -48,7 +48,7 @@ groups() ->
mixed_matching_clauses,unnecessary_building,
no_no_file,configuration,supplies,
redundant_stack_frame,export_from_case,
- empty_values]}].
+ empty_values,cover_letrec_effect]}].
init_per_suite(Config) ->
@@ -212,9 +212,14 @@ bifs(Config) when is_list(Config) ->
{ok,#{K:=V}} = id(list_to_tuple([ok,#{K=>V}])),
ok.
--define(CMP_SAME(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
--define(CMP_DIFF(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
-
+-define(CMP_SAME0(A0, B), (fun(A) -> true = A == B, false = A /= B end)(id(A0))).
+-define(CMP_SAME1(A0, B), (fun(A) -> false = A /= B, true = A == B end)(id(A0))).
+-define(CMP_SAME(A0, B), (true = ?CMP_SAME0(A0, B) =:= not ?CMP_SAME1(A0, B))).
+
+-define(CMP_DIFF0(A0, B), (fun(A) -> false = A == B, true = A /= B end)(id(A0))).
+-define(CMP_DIFF1(A0, B), (fun(A) -> true = A /= B, false = A == B end)(id(A0))).
+-define(CMP_DIFF(A0, B), (true = ?CMP_DIFF0(A0, B) =:= not ?CMP_DIFF1(A0, B))).
+
eq(Config) when is_list(Config) ->
?CMP_SAME([a,b,c], [a,b,c]),
?CMP_SAME([42.0], [42.0]),
@@ -373,7 +378,7 @@ unused_multiple_values_error(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
Dir = test_lib:get_data_dir(Config),
Core = filename:join(Dir, "unused_multiple_values_error"),
- Opts = [no_copt,clint,return,from_core,{outdir,PrivDir}
+ Opts = [no_copt,clint,ssalint,return,from_core,{outdir,PrivDir}
|test_lib:opt_opts(?MODULE)],
{error,[{unused_multiple_values_error,
[{none,core_lint,{return_mismatch,{hello,1}}}]}],
@@ -615,5 +620,25 @@ empty_values(_Config) ->
do_empty_values() when (#{})#{} ->
c.
+cover_letrec_effect(_Config) ->
+ self() ! {tag,42},
+ _ = try
+ try
+ ignore
+ after
+ receive
+ {tag,Int}=Term ->
+ Res = #{k => {Term,<<Int:16>>}},
+ self() ! Res
+ end
+ end
+ after
+ ok
+ end,
+ receive
+ Any ->
+ #{k := {{tag,42},<<42:16>>}} = Any
+ end,
+ ok.
id(I) -> I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index da291bdc8b..8b9dbe4aa0 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/float_SUITE.erl b/lib/compiler/test/float_SUITE.erl
index 39867021cb..012810aba2 100644
--- a/lib/compiler/test/float_SUITE.erl
+++ b/lib/compiler/test/float_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index e00885fcd6..1df0a05275 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -249,6 +249,13 @@ badfun(_Config) ->
expect_badfun(X, catch X(put(?FUNCTION_NAME, of_course))),
of_course = erase(?FUNCTION_NAME),
+ %% A literal as a Fun used to crash the code generator. This only happened
+ %% when type optimization had reduced `Fun` to a literal, hence the match.
+ Literal = fun(literal = Fun) ->
+ Fun()
+ end,
+ expect_badfun(literal, catch Literal(literal)),
+
ok.
expect_badfun(Term, Exit) ->
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 99dc06b525..1c05129dc4 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,8 +35,7 @@
basic_andalso_orelse/1,traverse_dcd/1,
check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
bad_constants/1,bad_guards/1,
- guard_in_catch/1,beam_bool_SUITE/1,
- cover_beam_dead/1]).
+ guard_in_catch/1,beam_bool_SUITE/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -54,8 +53,7 @@ groups() ->
rel_ops,rel_op_combinations,
literal_type_tests,basic_andalso_orelse,traverse_dcd,
check_qlc_hrl,andalso_semi,t_tuple_size,binary_part,
- bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE,
- cover_beam_dead]}].
+ bad_constants,bad_guards,guard_in_catch,beam_bool_SUITE]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -1779,15 +1777,10 @@ t_tuple_size(Config) when is_list(Config) ->
error = ludicrous_tuple_size({a,b,c}),
error = ludicrous_tuple_size([a,b,c]),
- %% Test the "unsafe case" - the register assigned the tuple size is
- %% not killed.
- DataDir = test_lib:get_data_dir(Config),
- File = filename:join(DataDir, "guard_SUITE_tuple_size"),
- {ok,Mod,Code} = compile:file(File, [from_asm,binary]),
- code:load_binary(Mod, File, Code),
- 14 = Mod:t({1,2,3,4}),
- _ = code:delete(Mod),
- _ = code:purge(Mod),
+ good_ip({1,2,3,4}),
+ good_ip({1,2,3,4,5,6,7,8}),
+ error = validate_ip({42,11}),
+ error = validate_ip(atom),
ok.
@@ -1805,6 +1798,16 @@ ludicrous_tuple_size(T)
when tuple_size(T) =:= 16#FFFFFFFFFFFFFFFF -> ok;
ludicrous_tuple_size(_) -> error.
+good_ip(IP) ->
+ IP = validate_ip(IP).
+
+validate_ip(Value) when is_tuple(Value) andalso
+ ((size(Value) =:= 4) orelse (size(Value) =:= 8)) ->
+ %% size/1 (converted to tuple_size) used more than once.
+ Value;
+validate_ip(_) ->
+ error.
+
%%
%% The binary_part/2,3 guard BIFs
%%
@@ -2206,32 +2209,6 @@ maps() ->
evidence(#{0 := Charge}) when 0; #{[] => Charge} == #{[] => 42} ->
ok.
-cover_beam_dead(_Config) ->
- Mod = ?FUNCTION_NAME,
- Attr = [],
- Fs = [{function,test,1,2,
- [{label,1},
- {line,[]},
- {func_info,{atom,Mod},{atom,test},1},
- {label,2},
- %% Cover beam_dead:turn_op/1 using swapped operand order.
- {test,is_ne_exact,{f,3},[{integer,1},{x,0}]},
- {test,is_eq_exact,{f,1},[{atom,a},{x,0}]},
- {label,3},
- {move,{atom,ok},{x,0}},
- return]}],
- Exp = [{test,1}],
- Asm = {Mod,Exp,Attr,Fs,3},
- {ok,Mod,Beam} = compile:forms(Asm, [from_asm,binary,report]),
- {module,Mod} = code:load_binary(Mod, Mod, Beam),
- ok = Mod:test(1),
- ok = Mod:test(a),
- {'EXIT',_} = (catch Mod:test(other)),
- true = code:delete(Mod),
- _ = code:purge(Mod),
-
- ok.
-
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S b/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
deleted file mode 100644
index cffb792920..0000000000
--- a/lib/compiler/test/guard_SUITE_data/guard_SUITE_tuple_size.S
+++ /dev/null
@@ -1,30 +0,0 @@
-{module, guard_SUITE_tuple_size}. %% version = 0
-
-{exports, [{t,1}]}.
-
-{attributes, []}.
-
-{labels, 5}.
-
-
-{function, t, 1, 2}.
- {label,1}.
- {func_info,{atom,guard_SUITE_tuple_size},{atom,t},1}.
- {label,2}.
- {bif,tuple_size,{f,4},[{x,0}],{x,1}}.
- {test,is_eq_exact,{f,4},[{x,1},{integer,4}]}.
- {test,is_tuple,{f,3},[{x,0}]}.
- {test,test_arity,{f,3},[{x,0},4]}.
- {get_tuple_element,{x,0},0,{x,5}}.
- {get_tuple_element,{x,0},1,{x,2}}.
- {get_tuple_element,{x,0},2,{x,3}}.
- {get_tuple_element,{x,0},3,{x,4}}.
- {gc_bif,'+',{f,0},6,[{x,1},{x,2}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,3}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,4}],{x,0}}.
- {gc_bif,'+',{f,0},6,[{x,0},{x,5}],{x,0}}.
- return.
- {label,3}.
- {badmatch,{x,0}}.
- {label,4}.
- {jump,{f,1}}.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index fdf2fe88b4..69c9dcba69 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -96,7 +96,8 @@ try_inline(Mod, Config) ->
%% Normal compilation.
io:format("Compiling: ~s\n", [Src]),
- {ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,clint]),
+ {ok,Mod} = compile:file(Src, [{outdir,Out},report,
+ bin_opt_info,clint,ssalint]),
ct:timetrap({minutes,10}),
NormalResult = rpc:call(Node, ?MODULE, load_and_call, [Out,Mod]),
@@ -104,7 +105,7 @@ try_inline(Mod, Config) ->
%% Inlining.
io:format("Compiling with old inliner: ~s\n", [Src]),
{ok,Mod} = compile:file(Src, [{outdir,Out},report,bin_opt_info,
- {inline,1000},clint]),
+ {inline,1000},clint,ssalint]),
%% Run inlined code.
ct:timetrap({minutes,10}),
@@ -117,7 +118,7 @@ try_inline(Mod, Config) ->
%% Inlining.
io:format("Compiling with new inliner: ~s\n", [Src]),
{ok,Mod} = compile:file(Src, [{outdir,Out},report,
- bin_opt_info,inline,clint]),
+ bin_opt_info,inline,clint,ssalint]),
%% Run inlined code.
ct:timetrap({minutes,10}),
@@ -351,7 +352,8 @@ otp_7223_2({a}) ->
coverage(Config) when is_list(Config) ->
Mod = bsdecode,
Src = filename:join(proplists:get_value(data_dir, Config), Mod),
- {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},clint]),
+ {ok,Mod,_} = compile:file(Src, [binary,report,{inline,0},
+ clint,ssalint]),
{ok,Mod,_} = compile:file(Src, [binary,report,{inline,20},
- verbose,clint]),
+ verbose,clint,ssalint]),
ok.
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 9182c1b5ed..3e0ab78390 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -1212,10 +1212,25 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_guard_empty_2(),
true = map_guard_head(#{a=>1}),
false = map_guard_head([]),
+
true = map_get_head(#{a=>1}),
+ false = map_get_head(#{}),
+ false = map_get_head([]),
+
+ true = map_get_head_not(#{a=>false}),
+ false = map_get_head_not(#{a=>true}),
+ false = map_get_head(#{}),
false = map_get_head([]),
+
true = map_is_key_head(#{a=>1}),
false = map_is_key_head(#{}),
+ false = map_is_key_head(not_a_map),
+
+ false = map_is_key_head_not(#{a=>1}),
+ true = map_is_key_head_not(#{b=>1}),
+ true = map_is_key_head_not(#{}),
+ false = map_is_key_head_not(not_a_map),
+
true = map_guard_body(#{a=>1}),
false = map_guard_body({}),
true = map_guard_pattern(#{a=>1, <<"hi">> => "hi" }),
@@ -1224,6 +1239,57 @@ t_guard_bifs(Config) when is_list(Config) ->
true = map_guard_ill_map_size(),
true = map_field_check_sequence(#{a=>1}),
false = map_field_check_sequence(#{}),
+
+ %% The guard BIFs used in a body.
+
+ v = map_get(a, id(#{a=>v})),
+ {'EXIT',{{badkey,a},_}} =
+ (catch map_get(a, id(#{}))),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch map_get(a, id(not_a_map))),
+
+ true = is_map_key(a, id(#{a=>1})),
+ false = is_map_key(b, id(#{a=>1})),
+ false = is_map_key(b, id(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} =
+ (catch is_map_key(b, id(not_a_map))),
+
+ {true,v} = erl_699(#{k=>v}),
+ {'EXIT',{{badkey,k},_}} = (catch erl_699(#{})),
+ {'EXIT',{{badmap,not_a_map},_}} = (catch erl_699(not_a_map)),
+
+ %% Cover optimizations in beam_dead.
+
+ ok = beam_dead_1(#{a=>any,k=>true}),
+ error = beam_dead_1(#{a=>any,k=>false}),
+ error = beam_dead_1(#{a=>any}),
+ error = beam_dead_1(#{}),
+
+ ok = beam_dead_2(#{a=>any,k=>true}),
+ error = beam_dead_2(#{a=>any,k=>false}),
+ error = beam_dead_2(#{a=>any}),
+ error = beam_dead_2(#{}),
+
+ ok = beam_dead_3(#{k=>true}),
+ error = beam_dead_3(#{k=>false}),
+ error = beam_dead_3(#{}),
+
+ ok = beam_dead_4(#{k=>true}),
+ error = beam_dead_4(#{k=>false}),
+ error = beam_dead_4(#{}),
+ error = beam_dead_4(not_a_map),
+
+ ok = beam_dead_5(#{k=>true}),
+ error = beam_dead_5(#{k=>false}),
+ error = beam_dead_3(#{}),
+
+ %% Test is_map_key/2 followed by map update.
+
+ Used0 = map_usage(var, #{other=>value}),
+ Used0 = #{other=>value,var=>dead},
+ Used1 = map_usage(var, #{var=>live}),
+ Used1 = #{var=>live},
+
ok.
map_guard_empty() when is_map(#{}); false -> true.
@@ -1236,8 +1302,14 @@ map_guard_head(_) -> false.
map_get_head(M) when map_get(a, M) =:= 1 -> true;
map_get_head(_) -> false.
+map_get_head_not(M) when not map_get(a, M) -> true;
+map_get_head_not(_) -> false.
+
map_is_key_head(M) when is_map_key(a, M) -> true;
-map_is_key_head(M) -> false.
+map_is_key_head(_) -> false.
+
+map_is_key_head_not(M) when not is_map_key(a, M) -> true;
+map_is_key_head_not(_) -> false.
map_guard_body(M) -> is_map(M).
@@ -1254,6 +1326,52 @@ map_field_check_sequence(M)
map_field_check_sequence(_) ->
false.
+erl_699(M) ->
+ %% Used to cause an internal consistency failure.
+ {is_map_key(k, M),maps:get(k, M)}.
+
+beam_dead_1(#{a:=_,k:=_}=M) when map_get(k, M) ->
+ ok;
+beam_dead_1(#{}) ->
+ error.
+
+beam_dead_2(M) ->
+ case M of
+ #{a:=_,k:=_} when map_get(k, M) ->
+ ok;
+ #{} ->
+ error
+ end.
+
+beam_dead_3(M) ->
+ case M of
+ #{k:=_} when map_get(k, M) ->
+ ok;
+ #{} ->
+ error
+ end.
+
+beam_dead_4(M) ->
+ case M of
+ #{} when map_get(k, M) ->
+ ok;
+ _ ->
+ error
+ end.
+
+beam_dead_5(#{}=M) when map_get(k, M) ->
+ ok;
+beam_dead_5(#{}) ->
+ error.
+
+%% Test is_map_key/2, followed by an update of the map.
+map_usage(Def, Used) ->
+ case is_map_key(Def, Used) of
+ true -> Used;
+ false -> Used#{Def=>dead}
+ end.
+
+
t_guard_sequence(Config) when is_list(Config) ->
{1, "a"} = map_guard_sequence_1(#{seq=>1,val=>id("a")}),
{2, "b"} = map_guard_sequence_1(#{seq=>2,val=>id("b")}),
diff --git a/lib/compiler/test/match_SUITE.erl b/lib/compiler/test/match_SUITE.erl
index e3f842b668..229c3093d7 100644
--- a/lib/compiler/test/match_SUITE.erl
+++ b/lib/compiler/test/match_SUITE.erl
@@ -254,6 +254,8 @@ non_matching_aliases(_Config) ->
none = mixed_aliases([d]),
none = mixed_aliases({a,42}),
none = mixed_aliases(42),
+ none = mixed_aliases(<<6789:16>>),
+ none = mixed_aliases(#{key=>value}),
{'EXIT',{{badmatch,42},_}} = (catch nomatch_alias(42)),
{'EXIT',{{badmatch,job},_}} = (catch entirely()),
@@ -279,6 +281,16 @@ mixed_aliases(<<X:8>> = x) -> {a,X};
mixed_aliases([b] = <<X:8>>) -> {b,X};
mixed_aliases(<<X:8>> = {a,X}) -> {c,X};
mixed_aliases([X] = <<X:8>>) -> {d,X};
+mixed_aliases(<<X:16>> = X) -> {e,X};
+mixed_aliases(X = <<X:16>>) -> {f,X};
+mixed_aliases(<<X:16,_/binary>> = X) -> {g,X};
+mixed_aliases(X = <<X:16,_/binary>>) -> {h,X};
+mixed_aliases(X = #{key:=X}) -> {i,X};
+mixed_aliases(#{key:=X} = X) -> {j,X};
+mixed_aliases([X] = #{key:=X}) -> {k,X};
+mixed_aliases(#{key:=X} = [X]) -> {l,X};
+mixed_aliases({a,X} = #{key:=X}) -> {m,X};
+mixed_aliases(#{key:=X} = {a,X}) -> {n,X};
mixed_aliases(_) -> none.
nomatch_alias(I) ->
@@ -434,6 +446,7 @@ letify_guard(A, B) ->
selectify(Config) when is_list(Config) ->
integer = sel_different_types({r,42}),
atom = sel_different_types({r,forty_two}),
+ float = sel_different_types({r,100.0}),
none = sel_different_types({r,18}),
{'EXIT',_} = (catch sel_different_types([a,b,c])),
@@ -444,12 +457,15 @@ selectify(Config) when is_list(Config) ->
integer42 = sel_same_value2(42),
integer43 = sel_same_value2(43),
error = sel_same_value2(44),
+
ok.
sel_different_types({r,_}=T) when element(2, T) =:= forty_two ->
atom;
sel_different_types({r,_}=T) when element(2, T) =:= 42 ->
integer;
+sel_different_types({r,_}=T) when element(2, T) =:= 100.0 ->
+ float;
sel_different_types({r,_}) ->
none.
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index a1d931b994..c9acda2b6d 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -171,7 +171,7 @@ silly_coverage(Config) when is_list(Config) ->
expect_error(fun() -> sys_core_dsetel:module(BadCoreErlang, []) end),
expect_error(fun() -> v3_kernel:module(BadCoreErlang, []) end),
- %% v3_codegen
+ %% beam_kernel_to_ssa
BadKernel = {k_mdef,[],?MODULE,
[{foo,0}],
[],
@@ -179,7 +179,31 @@ silly_coverage(Config) when is_list(Config) ->
{k,[],[],[]},
f,0,[],
seriously_bad_body}]},
- expect_error(fun() -> v3_codegen:module(BadKernel, []) end),
+ expect_error(fun() -> beam_kernel_to_ssa:module(BadKernel, []) end),
+
+ %% beam_ssa_lint
+ %% beam_ssa_recv
+ %% beam_ssa_pre_codegen
+ %% beam_ssa_opt
+ %% beam_ssa_codegen
+ BadSSA = {b_module,#{},a,b,c,
+ [{b_function,#{func_info=>{mod,foo,0}},args,bad_blocks,0}]},
+ expect_error(fun() -> beam_ssa_lint:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_recv:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_pre_codegen:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_opt:module(BadSSA, []) end),
+ expect_error(fun() -> beam_ssa_codegen:module(BadSSA, []) end),
+
+ %% beam_ssa_lint, beam_ssa_pp
+ {error,[{_,Errors}]} = beam_ssa_lint:module(bad_ssa_lint_input(), []),
+ _ = [io:put_chars(Mod:format_error(Reason)) ||
+ {Mod,Reason} <- Errors],
+
+ %% Cover printing of annotations in beam_ssa_pp
+ PPAnno = #{func_info=>{mod,foo,0},other_anno=>value,map_anno=>#{k=>v}},
+ PPBlocks = #{0=>{b_blk,#{},[],{b_ret,#{},{b_literal,42}}}},
+ PP = {b_function,PPAnno,[],PPBlocks,0},
+ io:put_chars(beam_ssa_pp:format_function(PP)),
%% beam_a
BeamAInput = {?MODULE,[{foo,0}],[],
@@ -189,14 +213,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_a:module(BeamAInput, []) end),
- %% beam_reorder
- BlockInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- expect_error(fun() -> beam_reorder:module(BlockInput, []) end),
-
%% beam_block
BlockInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -209,15 +225,6 @@ silly_coverage(Config) when is_list(Config) ->
BsInput = BlockInput,
expect_error(fun() -> beam_bs:module(BsInput, []) end),
- %% beam_type
- TypeInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {line,loc},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list]}],99},
- expect_error(fun() -> beam_type:module(TypeInput, []) end),
-
%% beam_except
ExceptInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -227,16 +234,6 @@ silly_coverage(Config) when is_list(Config) ->
{label,2}|non_proper_list]}],99},
expect_error(fun() -> beam_except:module(ExceptInput, []) end),
- %% beam_dead. This is tricky. Our function must look OK to
- %% beam_utils:clean_labels/1, but must crash beam_dead.
- DeadInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,is_eq_exact,{f,1},[bad,operands]}]}],99},
- expect_error(fun() -> beam_dead:module(DeadInput, []) end),
-
%% beam_clean
CleanInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
@@ -257,44 +254,6 @@ silly_coverage(Config) when is_list(Config) ->
2},
expect_error(fun() -> beam_peep:module(PeepInput, []) end),
- %% beam_bsm. This is tricky. Our function must be sane enough to not crash
- %% btb_index/1, but must crash the main optimization pass.
- BsmInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {test,bs_get_binary2,{f,99},0,[{x,0},{atom,all},1,[]],{x,0}},
- {block,[a|b]}]}],0},
- expect_error(fun() -> beam_bsm:module(BsmInput, []) end),
-
- %% beam_receive.
- ReceiveInput = {?MODULE,[{foo,0}],[],
- [{function,foo,0,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},0},
- {label,2},
- {call_ext,0,{extfunc,erlang,make_ref,0}},
- {block,[a|b]}]}],0},
- expect_error(fun() -> beam_receive:module(ReceiveInput, []) end),
-
- %% beam_record.
- RecordInput = {?MODULE,[{foo,0}],[],
- [{function,foo,1,2,
- [{label,1},
- {func_info,{atom,?MODULE},{atom,foo},1},
- {label,2},
- {test,is_tuple,{f,1},[{x,0}]},
- {test,test_arity,{f,1},[{x,0},3]},
- {block,[{set,[{x,1}],[{x,0}],{get_tuple_element,0}}]},
- {test,is_eq_exact,{f,1},[{x,1},{atom,bar}]},
- {block,[{set,[{x,2}],[{x,0}],{get_tuple_element,1}}|a]},
- {test,is_eq_exact,{f,1},[{x,2},{integer,1}]},
- {block,[{set,[{x,0}],[{atom,ok}],move}]},
- return]}],0},
-
- expect_error(fun() -> beam_record:module(RecordInput, []) end),
-
BeamZInput = {?MODULE,[{foo,0}],[],
[{function,foo,0,2,
[{label,1},
@@ -312,6 +271,31 @@ silly_coverage(Config) when is_list(Config) ->
ok.
+bad_ssa_lint_input() ->
+ {b_module,#{},t,
+ [{foobar,1},{module_info,0},{module_info,1}],
+ [],
+ [{b_function,
+ #{func_info => {t,foobar,1},location => {"t.erl",4}},
+ [{b_var,0}],
+ #{0 => {b_blk,#{},[],{b_ret,#{},{b_var,'@undefined_var'}}}},
+ 3},
+ {b_function,
+ #{func_info => {t,module_info,0}},
+ [],
+ #{0 =>
+ {b_blk,#{},
+ [{b_set,#{},
+ {b_var,{'@ssa_ret',3}},
+ call,
+ [{b_remote,
+ {b_literal,erlang},
+ {b_literal,get_module_info},
+ 1},
+ {b_var,'@unknown_variable'}]}],
+ {b_ret,#{},{b_var,{'@ssa_ret',3}}}}},
+ 4}]}.
+
expect_error(Fun) ->
try Fun() of
Any ->
diff --git a/lib/compiler/test/overridden_bif_SUITE.erl b/lib/compiler/test/overridden_bif_SUITE.erl
index a46abe8dcf..6b8a9591c9 100644
--- a/lib/compiler/test/overridden_bif_SUITE.erl
+++ b/lib/compiler/test/overridden_bif_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/receive_SUITE.erl b/lib/compiler/test/receive_SUITE.erl
index 81ef0d33f2..4219768d6f 100644
--- a/lib/compiler/test/receive_SUITE.erl
+++ b/lib/compiler/test/receive_SUITE.erl
@@ -25,7 +25,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1,
- wait/1]).
+ wait/1,recv_in_try/1,double_recv/1]).
-include_lib("common_test/include/ct.hrl").
@@ -44,7 +44,8 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
- [recv,coverage,otp_7980,ref_opt,export,wait]}].
+ [recv,coverage,otp_7980,ref_opt,export,wait,
+ recv_in_try,double_recv]}].
init_per_suite(Config) ->
@@ -305,4 +306,76 @@ wait_1(r, _, _) ->
wait_1(A, B, C) ->
{A,B,C}.
+recv_in_try(_Config) ->
+ self() ! {ok,fh}, {ok,fh} = recv_in_try(infinity, native),
+ self() ! {ok,ignored}, {ok,42} = recv_in_try(infinity, plain),
+ self() ! {error,ignored}, nok = recv_in_try(infinity, plain),
+ timeout = recv_in_try(1, plain),
+ ok.
+
+recv_in_try(Timeout, Format) ->
+ try
+ receive
+ {Status,History} ->
+ %% {test,is_tuple,{f,148},[{x,0}]}.
+ %% {test,test_arity,{f,148},[{x,0},2]}.
+ %% {get_tuple_element,{x,0},0,{y,1}}. %y1 is fragile.
+ %%
+ %% %% Here the fragility of y1 would be be progated to
+ %% %% the 'catch' below. Incorrect, since get_tuple_element
+ %% %% can't fail.
+ %% {get_tuple_element,{x,0},1,{x,2}}.
+ %%
+ %% remove_message. %y1 fragility cleared.
+ FH = case Format of
+ native ->
+ id(History);
+ plain ->
+ id(42)
+ end,
+ case Status of
+ ok ->
+ {ok,FH};
+ error ->
+ nok
+ end
+ after Timeout ->
+ timeout
+ end
+ catch
+ %% The fragility of y1 incorrectly propagated to here.
+ %% beam_validator would complain.
+ throw:{error,Reason} ->
+ {nok,Reason}
+ end.
+
+%% ERL-703. The compiler would crash because beam_utils:anno_defs/1
+%% failed to take into account that code after loop_rec_end is
+%% unreachable.
+
+double_recv(_Config) ->
+ self() ! {more,{a,term}},
+ ok = do_double_recv({more,{a,term}}, any),
+ self() ! message,
+ ok = do_double_recv(whatever, message),
+
+ error = do_double_recv({more,42}, whatever),
+ error = do_double_recv(whatever, whatever),
+ ok.
+
+do_double_recv({more, Rest}, _Msg) ->
+ receive
+ {more, Rest} ->
+ ok
+ after 0 ->
+ error
+ end;
+do_double_recv(_, Msg) ->
+ receive
+ Msg ->
+ ok
+ after 0 ->
+ error
+ end.
+
id(I) -> I.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl
new file mode 100644
index 0000000000..4fbde3a83d
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/no_5.erl
@@ -0,0 +1,38 @@
+-module(no_5).
+-compile([export_all,nowarn_export_all]).
+
+?MODULE() ->
+ ok.
+
+%% Nested receives were not handled properly.
+
+confusing_recv_mark(Pid) ->
+ Ref = make_ref(),
+ %% There would be a recv_mark here.
+ MRef = erlang:monitor(process, Pid),
+ receive
+ Ref ->
+ %% And a recv_set here.
+ receive
+ MRef -> gurka
+ end;
+ MRef ->
+ gaffel
+ end.
+
+%% The optimization could potentially be improved to
+%% handle matching of multiple refs, like this:
+
+proper_recv_mark(Pid) ->
+ %% Place the recv_mark before the creation of both refs.
+ Ref = make_ref(),
+ MRef = erlang:monitor(process, Pid),
+ %% Place the recv_set here.
+ receive
+ Ref ->
+ receive
+ MRef -> gurka
+ end;
+ MRef ->
+ gaffel
+ end.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
deleted file mode 100644
index fd14228135..0000000000
--- a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.S
+++ /dev/null
@@ -1,71 +0,0 @@
-{module, yes_14}. %% version = 0
-
-{exports, [{f,2},{module_info,0},{module_info,1},{yes_14,0}]}.
-
-{attributes, []}.
-
-{labels, 12}.
-
-
-{function, yes_14, 0, 2}.
- {label,1}.
- {func_info,{atom,yes_14},{atom,yes_14},0}.
- {label,2}.
- {move,{atom,ok},{x,0}}.
- return.
-
-
-{function, f, 2, 4}.
- {label,3}.
- {func_info,{atom,yes_14},{atom,f},2}.
- {label,4}.
- {allocate_heap,2,3,2}.
- {move,{x,0},{y,1}}.
- {put_tuple,2,{y,0}}.
- {put,{atom,data}}.
- {put,{x,1}}.
- {call_ext,0,{extfunc,erlang,make_ref,0}}. % Ref in [x0]
- {test_heap,4,1}.
- {put_tuple,3,{x,1}}.
- {put,{atom,request}}.
- {put,{x,0}}.
- {put,{y,0}}.
- {move,{x,0},{y,0}}. % Ref in [x0,y0]
- {move,{y,1},{x,0}}. % Ref in [y0]
- {kill,{y,1}}.
- send.
- {move,{y,0},{x,0}}. % Ref in [x0,y0]
- {move,{x,0},{y,1}}. % Ref in [x0,y0,y1]
- {label,5}.
- {loop_rec,{f,7},{x,0}}. % Ref in [y0,y1]
- {test,is_tuple,{f,6},[{x,0}]}.
- {test,test_arity,{f,6},[{x,0},2]}.
- {get_tuple_element,{x,0},0,{x,1}}.
- {get_tuple_element,{x,0},1,{x,2}}.
- {test,is_eq_exact,{f,6},[{x,1},{atom,reply}]}.
- {test,is_eq_exact,{f,6},[{x,2},{y,1}]}.
- remove_message.
- {move,{atom,ok},{x,0}}.
- {deallocate,2}.
- return.
- {label,6}.
- {loop_rec_end,{f,5}}.
- {label,7}.
- {wait,{f,5}}.
-
-
-{function, module_info, 0, 9}.
- {label,8}.
- {func_info,{atom,yes_14},{atom,module_info},0}.
- {label,9}.
- {move,{atom,yes_14},{x,0}}.
- {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
-
-
-{function, module_info, 1, 11}.
- {label,10}.
- {func_info,{atom,yes_14},{atom,module_info},1}.
- {label,11}.
- {move,{x,0},{x,1}}.
- {move,{atom,yes_14},{x,0}}.
- {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl
new file mode 100644
index 0000000000..aa47c02af9
--- /dev/null
+++ b/lib/compiler/test/receive_SUITE_data/ref_opt/yes_14.erl
@@ -0,0 +1,27 @@
+-module(yes_14).
+-compile(export_all).
+
+?MODULE() ->
+ ok.
+
+do_call(Process, Request) ->
+ Mref = erlang:monitor(process, Process),
+ Process ! Request,
+ Local = case node(Process) of
+ Node when Node =:= node() -> true;
+ _Node -> false
+ end,
+ id(Local),
+ receive
+ {X,Y,Z} when Mref =/= X, Z =:= 42, Mref =:= Y ->
+ error;
+ {X,Y,_} when Mref =/= X, Mref =:= Y ->
+ error;
+ {Mref, Reply} ->
+ erlang:demonitor(Mref, [flush]),
+ {ok, Reply};
+ {'DOWN', Mref, _, _, _} ->
+ error
+ end.
+
+id(I) -> I.
diff --git a/lib/compiler/test/record_SUITE.erl b/lib/compiler/test/record_SUITE.erl
index 118e0a241c..4ed7f39780 100644
--- a/lib/compiler/test/record_SUITE.erl
+++ b/lib/compiler/test/record_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
index f448d54933..9b0b9b0c38 100644
--- a/lib/compiler/test/regressions_SUITE.erl
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl
index 8954a9f5fb..4502f5b68a 100644
--- a/lib/compiler/test/test_lib.erl
+++ b/lib/compiler/test/test_lib.erl
@@ -72,14 +72,15 @@ opt_opts(Mod) ->
{options,Opts} = lists:keyfind(options, 1, Comp),
lists:filter(fun(no_copt) -> true;
(no_postopt) -> true;
- (no_float_opt) -> true;
- (no_new_funs) -> true;
- (no_new_binaries) -> true;
- (no_new_apply) -> true;
- (no_gc_bifs) -> true;
+ (no_ssa_opt) -> true;
+ (no_recv_opt) -> true;
+ (no_ssa_float) -> true;
(no_stack_trimming) -> true;
(debug_info) -> true;
(inline) -> true;
+ (no_put_tuple2) -> true;
+ (no_bsm3) -> true;
+ (no_bsm_opt) -> true;
(_) -> false
end, Opts).
@@ -91,8 +92,9 @@ get_data_dir(Config) ->
Data0 = proplists:get_value(data_dir, Config),
Opts = [{return,list}],
Data1 = re:replace(Data0, "_no_opt_SUITE", "_SUITE", Opts),
- Data = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
- re:replace(Data, "_inline_SUITE", "_SUITE", Opts).
+ Data2 = re:replace(Data1, "_post_opt_SUITE", "_SUITE", Opts),
+ Data = re:replace(Data2, "_inline_SUITE", "_SUITE", Opts),
+ re:replace(Data, "_r21_SUITE", "_SUITE", Opts).
is_cloned_mod(Mod) ->
is_cloned_mod_1(atom_to_list(Mod)).
@@ -102,6 +104,7 @@ is_cloned_mod(Mod) ->
is_cloned_mod_1("no_opt_SUITE") -> true;
is_cloned_mod_1("post_opt_SUITE") -> true;
is_cloned_mod_1("inline_SUITE") -> true;
+is_cloned_mod_1("21_SUITE") -> true;
is_cloned_mod_1([_|T]) -> is_cloned_mod_1(T);
is_cloned_mod_1([]) -> false.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index 42ff4f6133..1f39348998 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -522,25 +522,43 @@ bin_opt_info(Config) when is_list(Config) ->
<<>> -> ok
end.
+ %% We use a tail in a BIF instruction, remote call, function
+ %% return, and an optimizable tail call for better coverage.
+ t2(<<A,B,T/bytes>>) ->
+ if
+ A > B -> t2(T);
+ A =< B -> T
+ end;
+ t2(<<_,T/bytes>>) when byte_size(T) < 4 ->
+ foo;
t2(<<_,T/bytes>>) ->
- split_binary(T, 4).
+ split_binary(T, 4).
">>,
- Ts1 = [{bsm1,
- Code,
- [bin_opt_info],
- {warnings,
- [{4,sys_core_bsm,orig_bin_var_used_in_guard},
- {5,beam_bsm,{no_bin_opt,{{t1,1},no_suitable_bs_start_match}}},
- {9,beam_bsm,{no_bin_opt,
- {binary_used_in,{extfunc,erlang,split_binary,2}}}} ]}}],
- [] = run(Config, Ts1),
+
+ Ws = (catch run_test(Config, Code, [bin_opt_info])),
+
+ %% This is an inexact match since the pass reports exact instructions as
+ %% part of the warnings, which may include annotations that vary from run
+ %% to run.
+ {warnings,
+ [{5,beam_ssa_bsm,{unsuitable_call,
+ {{b_local,{b_literal,t1},1},
+ {used_before_match,
+ {b_set,_,_,{bif,byte_size},[_]}}}}},
+ {5,beam_ssa_bsm,{binary_created,_,_}},
+ {11,beam_ssa_bsm,{binary_created,_,_}}, %% A =< B -> T
+ {13,beam_ssa_bsm,context_reused}, %% A > B -> t2(T);
+ {16,beam_ssa_bsm,{binary_created,_,_}}, %% when byte_size(T) < 4 ->
+ {19,beam_ssa_bsm,{remote_call,
+ {b_remote,
+ {b_literal,erlang},
+ {b_literal,split_binary},2}}},
+ {19,beam_ssa_bsm,{binary_created,_,_}} %% split_binary(T, 4)
+ ]} = Ws,
%% For coverage: don't give the bin_opt_info option.
- Ts2 = [{bsm2,
- Code,
- [],
- []}],
- [] = run(Config, Ts2),
+ [] = (catch run_test(Config, Code, [])),
+
ok.
bin_construction(Config) when is_list(Config) ->
@@ -746,7 +764,7 @@ maps_bin_opt_info(Config) when is_list(Config) ->
M.
">>,
[bin_opt_info],
- {warnings,[{2,beam_bsm,bin_opt}]}}],
+ {warnings,[{3,beam_ssa_bsm,context_reused}]}}],
[] = run(Config, Ts),
ok.
@@ -969,7 +987,6 @@ run(Config, Tests) ->
end,
lists:foldl(F, [], Tests).
-
%% Compiles a test module and returns the list of errors and warnings.
run_test(Conf, Test0, Warnings) ->
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index f99b6721e2..ab707885f4 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.2.2
+COMPILER_VSN = 7.2.6
diff --git a/lib/configure.in.src b/lib/configure.in.src
deleted file mode 100644
index d507a5c0dd..0000000000
--- a/lib/configure.in.src
+++ /dev/null
@@ -1,62 +0,0 @@
-dnl
-dnl %CopyrightBegin%
-dnl
-dnl Copyright Ericsson AB 1999-2016. All Rights Reserved.
-dnl
-dnl Licensed under the Apache License, Version 2.0 (the "License");
-dnl you may not use this file except in compliance with the License.
-dnl You may obtain a copy of the License at
-dnl
-dnl http://www.apache.org/licenses/LICENSE-2.0
-dnl
-dnl Unless required by applicable law or agreed to in writing, software
-dnl distributed under the License is distributed on an "AS IS" BASIS,
-dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-dnl See the License for the specific language governing permissions and
-dnl limitations under the License.
-dnl
-dnl %CopyrightEnd%
-dnl
-
-dnl Turn off caching
-define([AC_CACHE_LOAD], )dnl
-define([AC_CACHE_SAVE], )dnl
-
-dnl Process this file with autoconf to produce a configure script.
-AC_INIT
-
-dnl
-dnl This is just to run configure in all applications that need it.
-dnl
-
-if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then
- AC_MSG_ERROR(You need to set the environment variable ERL_TOP!)
-fi
-erl_top=${ERL_TOP}
-AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
-
-AC_ARG_ENABLE(bootstrap-only,
-[ --enable-bootstrap-only enable bootstrap only configuration],
-[ if test "X$enableval" = "Xyes"; then
- bootstrap_only=yes
- else
- bootstrap_only=no
- fi
-],
-bootstrap_only=no)
-
-# Multiple versions of autoconf generates code that
-# don't work on all platforms (e.g. SunOS 5.8) if
-# sub directories are soft links. Internally at Ericsson
-# some OTP application directories are soft links.
-# An added "/." solves this problem.
-
-@BOOTSTRAP_CONFIGURE_APPS@
-
-if test $bootstrap_only = no; then
-
-@NON_BOOTSTRAP_CONFIGURE_APPS@
-
-fi
-
-AC_OUTPUT
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index 31124ba477..cd0e5442e9 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -19,7 +19,6 @@
#
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
-include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk
# ----------------------------------------------------
# Application version
@@ -31,23 +30,20 @@ VSN=$(CRYPTO_VSN)
# The following variables differ between systems.
# Set by configure.
# ----------------------------------------------------
-CC = $(DED_CC)
-LD = $(DED_LD)
+CC = @DED_CC@
+LD = @DED_LD@
SHELL = /bin/sh
-LIBS = $(DED_LIBS)
-LDFLAGS += $(DED_LDFLAGS)
-CFLAGS = $(DED_CFLAGS)
+LIBS = @DED_LIBS@
+LDFLAGS += @DED_LDFLAGS@
+CFLAGS = @DED_CFLAGS@ @SSL_FLAGS@
# From erts/configure
SSL_LIBDIR = @SSL_LIBDIR@
SSL_INCLUDE = @SSL_INCLUDE@
SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@
SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@
-SSL_FLAGS = @SSL_FLAGS@
-
-INCLUDES = $(SSL_INCLUDE) $(DED_INCLUDES)
-CFLAGS += $(SSL_FLAGS)
+INCLUDES = $(SSL_INCLUDE) @DED_INCLUDE@
ifeq ($(TYPE),debug)
TYPEMARKER = .debug
@@ -70,6 +66,11 @@ RELSYSDIR = $(RELEASE_PATH)/lib/crypto-$(VSN)
# ----------------------------------------------------
# Misc Macros
# ----------------------------------------------------
+
+PRIVDIR = ../priv
+OBJDIR = $(PRIVDIR)/obj/$(TARGET)
+LIBDIR = $(PRIVDIR)/lib/$(TARGET)
+
CRYPTO_OBJS = $(OBJDIR)/crypto$(TYPEMARKER).o
CALLBACK_OBJS = $(OBJDIR)/crypto_callback$(TYPEMARKER).o
NIF_MAKEFILE = $(PRIVDIR)/Makefile
@@ -80,19 +81,10 @@ NIF_ARCHIVE = $(LIBDIR)/crypto$(TYPEMARKER).a
TEST_ENGINE_OBJS = $(OBJDIR)/otp_test_engine$(TYPEMARKER).o
-ifeq ($(findstring win32,$(TARGET)), win32)
-NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).dll
-CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).dll
-TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).dll
-else
-NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).so
-CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).so
-TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).so
-endif
+NIF_LIB = $(LIBDIR)/crypto$(TYPEMARKER).@DED_EXT@
+CALLBACK_LIB = $(LIBDIR)/crypto_callback$(TYPEMARKER).@DED_EXT@
+TEST_ENGINE_LIB = $(LIBDIR)/otp_test_engine$(TYPEMARKER).@DED_EXT@
-ifeq ($(HOST_OS),)
-HOST_OS := $(shell $(ERL_TOP)/erts/autoconf/config.guess)
-endif
DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
@@ -125,7 +117,7 @@ RANLIB=true
endif
ALL_CFLAGS = $(TYPE_FLAGS) $(EXTRA_FLAGS) $(INCLUDES)
-ALL_STATIC_CFLAGS = $(DED_STATIC_CFLAGS) $(INCLUDES)
+ALL_STATIC_CFLAGS = @DED_STATIC_CFLAGS@ $(INCLUDES)
# ----------------------------------------------------
# Targets
@@ -181,21 +173,13 @@ endif
clean:
-ifeq ($(findstring win32,$(TARGET)), win32)
- rm -f $(LIBDIR)/crypto.dll
- rm -f $(LIBDIR)/crypto.debug.dll
- rm -f $(LIBDIR)/crypto_callback.dll
- rm -f $(LIBDIR)/crypto_callback.debug.dll
- rm -f $(LIBDIR)/otp_test_engine.dll
-else
- rm -f $(LIBDIR)/crypto.so
- rm -f $(LIBDIR)/crypto.debug.so
- rm -f $(LIBDIR)/crypto.valgrind.so
- rm -f $(LIBDIR)/crypto_callback.so
- rm -f $(LIBDIR)/crypto_callback.debug.so
- rm -f $(LIBDIR)/crypto_callback.valgrind.so
- rm -f $(LIBDIR)/otp_test_engine.so
-endif
+ rm -f $(LIBDIR)/crypto.@DED_EXT@
+ rm -f $(LIBDIR)/crypto.debug.@DED_EXT@
+ rm -f $(LIBDIR)/crypto.valgrind.@DED_EXT@
+ rm -f $(LIBDIR)/crypto_callback.@DED_EXT@
+ rm -f $(LIBDIR)/crypto_callback.debug.@DED_EXT@
+ rm -f $(LIBDIR)/crypto_callback.valgrind.@DED_EXT@
+ rm -f $(LIBDIR)/otp_test_engine.@DED_EXT@
rm -f $(OBJDIR)/crypto.o
rm -f $(OBJDIR)/crypto_static.o
rm -f $(OBJDIR)/crypto.debug.o
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 6eeebb67a2..b2d8123f00 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -148,6 +148,23 @@
# define HAVE_DES_ede3_cfb_encrypt
#endif
+// SHA3:
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,1)
+// An error in beta releases of 1.1.1 fixed in production release
+# ifdef NID_sha3_224
+# define HAVE_SHA3_224
+# endif
+# ifdef NID_sha3_256
+# define HAVE_SHA3_256
+# endif
+#endif
+# ifdef NID_sha3_384
+# define HAVE_SHA3_384
+# endif
+# ifdef NID_sha3_512
+# define HAVE_SHA3_512
+# endif
+
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'o') \
&& !defined(OPENSSL_NO_EC) \
&& !defined(OPENSSL_NO_ECDH) \
@@ -155,12 +172,11 @@
# define HAVE_EC
#endif
-// (test for == 1.1.1pre8)
-#if OPENSSL_VERSION_NUMBER == (PACKED_OPENSSL_VERSION_PLAIN(1,1,1) - 7) \
+// (test for >= 1.1.1pre8)
+#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1) - 7) \
&& !defined(HAS_LIBRESSL) \
&& defined(HAVE_EC)
-// EXPERIMENTAL:
-# define HAVE_EDDH
+# define HAVE_ED_CURVE_DH
#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'c')
@@ -169,8 +185,14 @@
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
# define HAVE_EVP_AES_CTR
+# define HAVE_AEAD
# define HAVE_GCM
+# define HAVE_CCM
# define HAVE_CMAC
+# if defined(RSA_PKCS1_OAEP_PADDING)
+# define HAVE_RSA_OAEP_PADDING
+# endif
+# define HAVE_RSA_MGF1_MD
# if OPENSSL_VERSION_NUMBER < PACKED_OPENSSL_VERSION(1,0,1,'d')
# define HAVE_GCM_EVP_DECRYPT_BUG
# endif
@@ -178,7 +200,16 @@
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,1,0)
# ifndef HAS_LIBRESSL
+# define HAVE_CHACHA20
# define HAVE_CHACHA20_POLY1305
+# define HAVE_RSA_OAEP_MD
+# endif
+#endif
+
+// OPENSSL_VERSION_NUMBER >= 1.1.1-pre8
+#if OPENSSL_VERSION_NUMBER >= (PACKED_OPENSSL_VERSION_PLAIN(1,1,1)-7)
+# ifndef HAS_LIBRESSL
+# define HAVE_POLY1305
# endif
#endif
@@ -186,10 +217,16 @@
# define HAVE_ECB_IVEC_BUG
#endif
-#define HAVE_RSA_SSLV23_PADDING
-#if defined(HAS_LIBRESSL) \
- && LIBRESSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(2,6,1)
-# undef HAVE_RSA_SSLV23_PADDING
+#ifndef HAS_LIBRESSL
+# ifdef RSA_SSLV23_PADDING
+# define HAVE_RSA_SSLV23_PADDING
+# endif
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+# ifdef RSA_PKCS1_PSS_PADDING
+# define HAVE_RSA_PKCS1_PSS_PADDING
+# endif
#endif
#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION(0,9,8,'h') \
@@ -514,14 +551,16 @@ static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF
static ERL_NIF_TERM rand_seed_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#ifdef HAVE_GCM_EVP_DECRYPT_BUG
static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
#endif
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+
+static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -536,6 +575,7 @@ static ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
static ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
/* helpers */
@@ -606,11 +646,14 @@ static ErlNifFunc nif_funcs[] = {
{"rand_seed_nif", 1, rand_seed_nif},
- {"aes_gcm_encrypt", 5, aes_gcm_encrypt},
- {"aes_gcm_decrypt", 5, aes_gcm_decrypt},
+ {"aead_encrypt", 6, aead_encrypt},
+ {"aead_decrypt", 6, aead_decrypt},
+
+ {"chacha20_stream_init", 2, chacha20_stream_init},
+ {"chacha20_stream_encrypt", 2, chacha20_stream_crypt},
+ {"chacha20_stream_decrypt", 2, chacha20_stream_crypt},
- {"chacha20_poly1305_encrypt", 4, chacha20_poly1305_encrypt},
- {"chacha20_poly1305_decrypt", 5, chacha20_poly1305_decrypt},
+ {"poly1305_nif", 2, poly1305_nif},
{"engine_by_id_nif", 1, engine_by_id_nif},
{"engine_init_nif", 1, engine_init_nif},
@@ -625,6 +668,7 @@ static ErlNifFunc nif_funcs[] = {
{"engine_get_first_nif", 0, engine_get_first_nif},
{"engine_get_next_nif", 1, engine_get_next_nif},
{"engine_get_id_nif", 1, engine_get_id_nif},
+ {"engine_get_name_nif", 1, engine_get_name_nif},
{"engine_get_all_methods_nif", 0, engine_get_all_methods_nif}
};
@@ -674,6 +718,15 @@ static ERL_NIF_TERM atom_onbasis;
static ERL_NIF_TERM atom_aes_cfb8;
static ERL_NIF_TERM atom_aes_cfb128;
+#ifdef HAVE_GCM
+static ERL_NIF_TERM atom_aes_gcm;
+#endif
+#ifdef HAVE_CCM
+static ERL_NIF_TERM atom_aes_ccm;
+#endif
+#ifdef HAVE_CHACHA20_POLY1305
+static ERL_NIF_TERM atom_chacha20_poly1305;
+#endif
#ifdef HAVE_ECB_IVEC_BUG
static ERL_NIF_TERM atom_aes_ecb;
static ERL_NIF_TERM atom_des_ecb;
@@ -684,8 +737,7 @@ static ERL_NIF_TERM atom_rsa;
static ERL_NIF_TERM atom_dss;
static ERL_NIF_TERM atom_ecdsa;
-#ifdef HAVE_EDDH
-static ERL_NIF_TERM atom_eddh;
+#ifdef HAVE_ED_CURVE_DH
static ERL_NIF_TERM atom_x25519;
static ERL_NIF_TERM atom_x448;
#endif
@@ -705,6 +757,10 @@ static ERL_NIF_TERM atom_sha224;
static ERL_NIF_TERM atom_sha256;
static ERL_NIF_TERM atom_sha384;
static ERL_NIF_TERM atom_sha512;
+static ERL_NIF_TERM atom_sha3_224;
+static ERL_NIF_TERM atom_sha3_256;
+static ERL_NIF_TERM atom_sha3_384;
+static ERL_NIF_TERM atom_sha3_512;
static ERL_NIF_TERM atom_md5;
static ERL_NIF_TERM atom_ripemd160;
@@ -790,6 +846,35 @@ static struct digest_type_t digest_types[] =
{NULL}
#endif
},
+ {{"sha3_224"},
+#ifdef HAVE_SHA3_224
+ {&EVP_sha3_224}
+#else
+ {NULL}
+#endif
+ },
+ {{"sha3_256"},
+#ifdef HAVE_SHA3_256
+ {&EVP_sha3_256}
+#else
+ {NULL}
+#endif
+ },
+ {{"sha3_384"},
+#ifdef HAVE_SHA3_384
+ {&EVP_sha3_384}
+#else
+ {NULL}
+#endif
+ },
+ {{"sha3_512"},
+#ifdef HAVE_SHA3_512
+ {&EVP_sha3_512}
+#else
+ {NULL}
+#endif
+ },
+
{{NULL}}
};
@@ -1082,6 +1167,15 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
#endif
atom_aes_cfb8 = enif_make_atom(env, "aes_cfb8");
atom_aes_cfb128 = enif_make_atom(env, "aes_cfb128");
+#ifdef HAVE_GCM
+ atom_aes_gcm = enif_make_atom(env, "aes_gcm");
+#endif
+#ifdef HAVE_CCM
+ atom_aes_ccm = enif_make_atom(env, "aes_ccm");
+#endif
+#ifdef HAVE_CHACHA20_POLY1305
+ atom_chacha20_poly1305 = enif_make_atom(env,"chacha20_poly1305");
+#endif
#ifdef HAVE_ECB_IVEC_BUG
atom_aes_ecb = enif_make_atom(env, "aes_ecb");
atom_des_ecb = enif_make_atom(env, "des_ecb");
@@ -1097,8 +1191,7 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_rsa = enif_make_atom(env,"rsa");
atom_dss = enif_make_atom(env,"dss");
atom_ecdsa = enif_make_atom(env,"ecdsa");
-#ifdef HAVE_EDDH
- atom_eddh = enif_make_atom(env,"eddh");
+#ifdef HAVE_ED_CURVE_DH
atom_x25519 = enif_make_atom(env,"x25519");
atom_x448 = enif_make_atom(env,"x448");
#endif
@@ -1117,6 +1210,10 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_sha256 = enif_make_atom(env,"sha256");
atom_sha384 = enif_make_atom(env,"sha384");
atom_sha512 = enif_make_atom(env,"sha512");
+ atom_sha3_224 = enif_make_atom(env,"sha3_224");
+ atom_sha3_256 = enif_make_atom(env,"sha3_256");
+ atom_sha3_384 = enif_make_atom(env,"sha3_384");
+ atom_sha3_512 = enif_make_atom(env,"sha3_512");
atom_md5 = enif_make_atom(env,"md5");
atom_ripemd160 = enif_make_atom(env,"ripemd160");
@@ -1237,15 +1334,17 @@ static void unload(ErlNifEnv* env, void* priv_data)
}
static int algo_hash_cnt, algo_hash_fips_cnt;
-static ERL_NIF_TERM algo_hash[8]; /* increase when extending the list */
+static ERL_NIF_TERM algo_hash[12]; /* increase when extending the list */
static int algo_pubkey_cnt, algo_pubkey_fips_cnt;
static ERL_NIF_TERM algo_pubkey[11]; /* increase when extending the list */
static int algo_cipher_cnt, algo_cipher_fips_cnt;
-static ERL_NIF_TERM algo_cipher[24]; /* increase when extending the list */
+static ERL_NIF_TERM algo_cipher[25]; /* increase when extending the list */
static int algo_mac_cnt, algo_mac_fips_cnt;
-static ERL_NIF_TERM algo_mac[2]; /* increase when extending the list */
+static ERL_NIF_TERM algo_mac[3]; /* increase when extending the list */
static int algo_curve_cnt, algo_curve_fips_cnt;
static ERL_NIF_TERM algo_curve[87]; /* increase when extending the list */
+static int algo_rsa_opts_cnt, algo_rsa_opts_fips_cnt;
+static ERL_NIF_TERM algo_rsa_opts[11]; /* increase when extending the list */
static void init_algorithms_types(ErlNifEnv* env)
{
@@ -1264,6 +1363,18 @@ static void init_algorithms_types(ErlNifEnv* env)
#ifdef HAVE_SHA512
algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha512");
#endif
+#ifdef HAVE_SHA3_224
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_224");
+#endif
+#ifdef HAVE_SHA3_256
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_256");
+#endif
+#ifdef HAVE_SHA3_384
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_384");
+#endif
+#ifdef HAVE_SHA3_512
+ algo_hash[algo_hash_cnt++] = enif_make_atom(env, "sha3_512");
+#endif
// Non-validated algorithms follow
algo_hash_fips_cnt = algo_hash_cnt;
algo_hash[algo_hash_cnt++] = enif_make_atom(env, "md4");
@@ -1283,9 +1394,6 @@ static void init_algorithms_types(ErlNifEnv* env)
#endif
// Non-validated algorithms follow
algo_pubkey_fips_cnt = algo_pubkey_cnt;
-#ifdef HAVE_EDDH
- algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "eddh");
-#endif
algo_pubkey[algo_pubkey_cnt++] = enif_make_atom(env, "srp");
// Validated algorithms first
@@ -1308,6 +1416,9 @@ static void init_algorithms_types(ErlNifEnv* env)
#if defined(HAVE_GCM)
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_gcm");
#endif
+#if defined(HAVE_CCM)
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"aes_ccm");
+#endif
// Non-validated algorithms follow
algo_cipher_fips_cnt = algo_cipher_cnt;
#ifdef HAVE_AES_IGE
@@ -1331,33 +1442,158 @@ static void init_algorithms_types(ErlNifEnv* env)
#if defined(HAVE_CHACHA20_POLY1305)
algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20_poly1305");
#endif
-
+#if defined(HAVE_CHACHA20)
+ algo_cipher[algo_cipher_cnt++] = enif_make_atom(env,"chacha20");
+#endif
+
// Validated algorithms first
algo_mac_cnt = 0;
algo_mac[algo_mac_cnt++] = enif_make_atom(env,"hmac");
#ifdef HAVE_CMAC
algo_mac[algo_mac_cnt++] = enif_make_atom(env,"cmac");
#endif
+#ifdef HAVE_POLY1305
+ algo_mac[algo_mac_cnt++] = enif_make_atom(env,"poly1305");
+#endif
// Non-validated algorithms follow
algo_mac_fips_cnt = algo_mac_cnt;
-
// Validated algorithms first
algo_curve_cnt = 0;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp160r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp192k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp521r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime192v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"prime256v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls7");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls9");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls12");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP160t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP192t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP224t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP256t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP320t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP384t1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"brainpoolP512t1");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect163r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect193r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect233r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect239k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect283r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect409r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571k1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect571r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb163v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb176v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb191v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb208w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb239v3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb272w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb304w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb359v1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2pnb368w1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"c2tnb431r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls5");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls10");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls11");
+#endif
+#endif
// Non-validated algorithms follow
algo_curve_fips_cnt = algo_curve_cnt;
+#if defined(HAVE_EC)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp112r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"secp128r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls6");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls8");
+#if !defined(OPENSSL_NO_EC2M)
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect113r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"sect131r2");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls1");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"wtls4");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec3");
+ algo_curve[algo_curve_cnt++] = enif_make_atom(env,"ipsec4");
+#endif
+#endif
//--
-#ifdef HAVE_EDDH
+#ifdef HAVE_ED_CURVE_DH
algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x25519");
algo_curve[algo_curve_cnt++] = enif_make_atom(env,"x448");
#endif
+ // Validated algorithms first
+ algo_rsa_opts_cnt = 0;
+#ifdef HAS_EVP_PKEY_CTX
+# ifdef HAVE_RSA_PKCS1_PSS_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_pss_padding");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pss_saltlen");
+# endif
+# ifdef HAVE_RSA_MGF1_MD
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_mgf1_md");
+# endif
+# ifdef HAVE_RSA_OAEP_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_oaep_padding");
+# endif
+# ifdef HAVE_RSA_OAEP_MD
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_label");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_oaep_md");
+# endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"signature_md");
+#endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_pkcs1_padding");
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_x931_padding");
+#ifdef HAVE_RSA_SSLV23_PADDING
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_sslv23_padding");
+#endif
+ algo_rsa_opts[algo_rsa_opts_cnt++] = enif_make_atom(env,"rsa_no_padding");
+ algo_rsa_opts_fips_cnt = algo_rsa_opts_cnt;
+
+
// Check that the max number of algos is updated
ASSERT(algo_hash_cnt <= sizeof(algo_hash)/sizeof(ERL_NIF_TERM));
ASSERT(algo_pubkey_cnt <= sizeof(algo_pubkey)/sizeof(ERL_NIF_TERM));
ASSERT(algo_cipher_cnt <= sizeof(algo_cipher)/sizeof(ERL_NIF_TERM));
ASSERT(algo_mac_cnt <= sizeof(algo_mac)/sizeof(ERL_NIF_TERM));
ASSERT(algo_curve_cnt <= sizeof(algo_curve)/sizeof(ERL_NIF_TERM));
+ ASSERT(algo_rsa_opts_cnt <= sizeof(algo_rsa_opts)/sizeof(ERL_NIF_TERM));
}
static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
@@ -1369,19 +1605,22 @@ static ERL_NIF_TERM algorithms(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv
int cipher_cnt = fips_mode ? algo_cipher_fips_cnt : algo_cipher_cnt;
int mac_cnt = fips_mode ? algo_mac_fips_cnt : algo_mac_cnt;
int curve_cnt = fips_mode ? algo_curve_fips_cnt : algo_curve_cnt;
+ int rsa_opts_cnt = fips_mode ? algo_rsa_opts_fips_cnt : algo_rsa_opts_cnt;
#else
int hash_cnt = algo_hash_cnt;
int pubkey_cnt = algo_pubkey_cnt;
int cipher_cnt = algo_cipher_cnt;
int mac_cnt = algo_mac_cnt;
int curve_cnt = algo_curve_cnt;
+ int rsa_opts_cnt = algo_rsa_opts_cnt;
#endif
- return enif_make_tuple5(env,
+ return enif_make_tuple6(env,
enif_make_list_from_array(env, algo_hash, hash_cnt),
enif_make_list_from_array(env, algo_pubkey, pubkey_cnt),
enif_make_list_from_array(env, algo_cipher, cipher_cnt),
enif_make_list_from_array(env, algo_mac, mac_cnt),
- enif_make_list_from_array(env, algo_curve, curve_cnt)
+ enif_make_list_from_array(env, algo_curve, curve_cnt),
+ enif_make_list_from_array(env, algo_rsa_opts, rsa_opts_cnt)
);
}
@@ -1989,6 +2228,62 @@ static ERL_NIF_TERM cmac_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]
#endif
}
+/* For OpenSSL >= 1.1.1 the hmac_nif and cmac_nif could be integrated into poly1305 (with 'type' as parameter) */
+static ERL_NIF_TERM poly1305_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Text) */
+#ifdef HAVE_POLY1305
+ ErlNifBinary key_bin, text, ret_bin;
+ ERL_NIF_TERM ret = atom_error;
+ EVP_PKEY *key = NULL;
+ EVP_MD_CTX *mctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
+ const EVP_MD *md = NULL;
+ size_t size;
+ int type;
+
+ type = EVP_PKEY_POLY1305;
+
+ if (!enif_inspect_binary(env, argv[0], &key_bin) ||
+ !(key_bin.size == 32) ) {
+ return enif_make_badarg(env);
+ }
+
+ if (!enif_inspect_binary(env, argv[1], &text) ) {
+ return enif_make_badarg(env);
+ }
+
+ key = EVP_PKEY_new_raw_private_key(type, /*engine*/ NULL, key_bin.data, key_bin.size);
+
+ if (!key ||
+ !(mctx = EVP_MD_CTX_new()) ||
+ !EVP_DigestSignInit(mctx, &pctx, md, /*engine*/ NULL, key) ||
+ !EVP_DigestSignUpdate(mctx, text.data, text.size)) {
+ goto err;
+ }
+
+ if (!EVP_DigestSignFinal(mctx, NULL, &size) ||
+ !enif_alloc_binary(size, &ret_bin) ||
+ !EVP_DigestSignFinal(mctx, ret_bin.data, &size)) {
+ goto err;
+ }
+
+ if ((size != ret_bin.size) &&
+ !enif_realloc_binary(&ret_bin, size)) {
+ goto err;
+ }
+
+ ret = enif_make_binary(env, &ret_bin);
+
+ err:
+ EVP_MD_CTX_free(mctx);
+ EVP_PKEY_free(key);
+ return ret;
+
+#else
+ return atom_notsup;
+#endif
+}
+
static ERL_NIF_TERM block_crypt_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type, Key, Ivec, Text, IsEncrypt) or (Type, Key, Text, IsEncrypt) */
struct cipher_type_t *cipherp = NULL;
@@ -2282,66 +2577,102 @@ static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_N
}
#endif /* !HAVE_EVP_AES_CTR */
-static ERL_NIF_TERM aes_gcm_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_GCM)
+static ERL_NIF_TERM aead_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type,Key,Iv,AAD,In) */
+#if defined(HAVE_AEAD)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = NULL;
ErlNifBinary key, iv, aad, in;
unsigned int tag_len;
unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
+ ERL_NIF_TERM type, out, out_tag;
+ int len, ctx_ctrl_set_ivlen, ctx_ctrl_get_tag;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || (key.size != 16 && key.size != 24 && key.size != 32)
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_get_uint(env, argv[4], &tag_len) || tag_len < 1 || tag_len > 16) {
+ type = argv[0];
+
+ if (!enif_is_atom(env, type)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &key)
+ || !enif_inspect_binary(env, argv[2], &iv)
+ || !enif_inspect_iolist_as_binary(env, argv[3], &aad)
+ || !enif_inspect_iolist_as_binary(env, argv[4], &in)
+ || !enif_get_uint(env, argv[5], &tag_len)) {
return enif_make_badarg(env);
}
- if (key.size == 16)
- cipher = EVP_aes_128_gcm();
- else if (key.size == 24)
- cipher = EVP_aes_192_gcm();
- else if (key.size == 32)
- cipher = EVP_aes_256_gcm();
-
+ /* Use cipher_type some day. Must check block_encrypt|decrypt first */
+#if defined(HAVE_GCM)
+ if (type == atom_aes_gcm) {
+ if ((iv.size > 0)
+ && (1 <= tag_len && tag_len <= 16)) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_GCM_GET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_gcm();
+ else if (key.size == 24) cipher = EVP_aes_192_gcm();
+ else if (key.size == 32) cipher = EVP_aes_256_gcm();
+ else enif_make_badarg(env);
+ } else
+ enif_make_badarg(env);
+ } else
+#endif
+#if defined(HAVE_CCM)
+ if (type == atom_aes_ccm) {
+ if ((7 <= iv.size && iv.size <= 13)
+ && (4 <= tag_len && tag_len <= 16)
+ && ((tag_len & 1) == 0)
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_CCM_GET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_ccm();
+ else if (key.size == 24) cipher = EVP_aes_192_ccm();
+ else if (key.size == 32) cipher = EVP_aes_256_ccm();
+ else enif_make_badarg(env);
+ } else
+ enif_make_badarg(env);
+ } else
+#endif
+#if defined(HAVE_CHACHA20_POLY1305)
+ if (type == atom_chacha20_poly1305) {
+ if ((key.size == 32)
+ && (1 <= iv.size && iv.size <= 16)
+ && (tag_len == 16)
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_get_tag = EVP_CTRL_AEAD_GET_TAG,
+ cipher = EVP_chacha20_poly1305();
+ } else enif_make_badarg(env);
+ } else
+#endif
+ return enif_raise_exception(env, atom_notsup);
+
ctx = EVP_CIPHER_CTX_new();
+ if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err;
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err;
+
+#if defined(HAVE_CCM)
+ if (type == atom_aes_ccm) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) goto out_err;
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
+ if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in.size) != 1) goto out_err;
+ } else
+#endif
+ if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
+ if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
outp = enif_make_new_binary(env, in.size, &out);
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
+ if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
+ if (EVP_EncryptFinal_ex(ctx, outp/*+len*/, &len) != 1) goto out_err;
tagp = enif_make_new_binary(env, tag_len, &out_tag);
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_len, tagp) != 1)
- goto out_err;
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_get_tag, tag_len, tagp) != 1) goto out_err;
EVP_CIPHER_CTX_free(ctx);
-
CONSUME_REDS(env, in);
-
return enif_make_tuple2(env, out, out_tag);
-out_err:
+out_err:
EVP_CIPHER_CTX_free(ctx);
return atom_error;
@@ -2350,58 +2681,103 @@ out_err:
#endif
}
-static ERL_NIF_TERM aes_gcm_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
- return aes_gcm_decrypt_NO_EVP(env, argc, argv);
-#elif defined(HAVE_GCM)
+static ERL_NIF_TERM aead_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Type,Key,Iv,AAD,In,Tag) */
+#if defined(HAVE_AEAD)
EVP_CIPHER_CTX *ctx;
const EVP_CIPHER *cipher = NULL;
ErlNifBinary key, iv, aad, in, tag;
unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
+ ERL_NIF_TERM type, out;
+ int len, ctx_ctrl_set_ivlen, ctx_ctrl_set_tag;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
- || (key.size != 16 && key.size != 24 && key.size != 32)
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag)) {
+ type = argv[0];
+#if defined(HAVE_GCM_EVP_DECRYPT_BUG)
+ if (type == atom_aes_gcm)
+ return aes_gcm_decrypt_NO_EVP(env, argc, argv);
+#endif
+
+ if (!enif_is_atom(env, type)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &key)
+ || !enif_inspect_binary(env, argv[2], &iv)
+ || !enif_inspect_iolist_as_binary(env, argv[3], &aad)
+ || !enif_inspect_iolist_as_binary(env, argv[4], &in)
+ || !enif_inspect_iolist_as_binary(env, argv[5], &tag)) {
return enif_make_badarg(env);
}
- if (key.size == 16)
- cipher = EVP_aes_128_gcm();
- else if (key.size == 24)
- cipher = EVP_aes_192_gcm();
- else if (key.size == 32)
- cipher = EVP_aes_256_gcm();
+ /* Use cipher_type some day. Must check block_encrypt|decrypt first */
+#if defined(HAVE_GCM)
+ if (type == atom_aes_gcm) {
+ if (iv.size > 0) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_GCM_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_GCM_SET_TAG;
+ if (key.size == 16) cipher = EVP_aes_128_gcm();
+ else if (key.size == 24) cipher = EVP_aes_192_gcm();
+ else if (key.size == 32) cipher = EVP_aes_256_gcm();
+ else enif_make_badarg(env);
+ } else
+ enif_make_badarg(env);
+ } else
+#endif
+#if defined(HAVE_CCM)
+ if (type == atom_aes_ccm) {
+ if (iv.size > 0) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_CCM_SET_IVLEN;
+ if (key.size == 16) cipher = EVP_aes_128_ccm();
+ else if (key.size == 24) cipher = EVP_aes_192_ccm();
+ else if (key.size == 32) cipher = EVP_aes_256_ccm();
+ else enif_make_badarg(env);
+ } else
+ enif_make_badarg(env);
+ } else
+#endif
+#if defined(HAVE_CHACHA20_POLY1305)
+ if (type == atom_chacha20_poly1305) {
+ if ((key.size == 32)
+ && (1 <= iv.size && iv.size <= 16)
+ && tag.size == 16
+ ) {
+ ctx_ctrl_set_ivlen = EVP_CTRL_AEAD_SET_IVLEN;
+ ctx_ctrl_set_tag = EVP_CTRL_AEAD_SET_TAG;
+ cipher = EVP_chacha20_poly1305();
+ } else enif_make_badarg(env);
+ } else
+#endif
+ return enif_raise_exception(env, atom_notsup);
+
+ outp = enif_make_new_binary(env, in.size, &out);
ctx = EVP_CIPHER_CTX_new();
+ if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) goto out_err;
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_ivlen, iv.size, NULL) != 1) goto out_err;
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
+#if defined(HAVE_CCM)
+ if (type == atom_aes_ccm) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag.size, tag.data) != 1) goto out_err;
+ }
+#endif
- outp = enif_make_new_binary(env, in.size, &out);
+ if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1) goto out_err;
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
+#if defined(HAVE_CCM)
+ if (type == atom_aes_ccm) {
+ if (1 != EVP_DecryptUpdate(ctx, NULL, &len, NULL, in.size)) goto out_err;
+ }
+#endif
+ if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1) goto out_err;
+ if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1) goto out_err;
+
+#if defined(HAVE_GCM) || defined(HAVE_CHACHA20_POLY1305)
+ if (type == atom_aes_gcm) {
+ if (EVP_CIPHER_CTX_ctrl(ctx, ctx_ctrl_set_tag, tag.size, tag.data) != 1) goto out_err;
+ if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1) goto out_err;
+ }
+#endif
EVP_CIPHER_CTX_free(ctx);
CONSUME_REDS(env, in);
-
return out;
out_err:
@@ -2414,19 +2790,19 @@ out_err:
#ifdef HAVE_GCM_EVP_DECRYPT_BUG
static ERL_NIF_TERM aes_gcm_decrypt_NO_EVP(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{
+{/* (Type,Key,Iv,AAD,In,Tag) */
GCM128_CONTEXT *ctx;
ErlNifBinary key, iv, aad, in, tag;
AES_KEY aes_key;
unsigned char *outp;
ERL_NIF_TERM out;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key)
+ if (!enif_inspect_iolist_as_binary(env, argv[1], &key)
|| AES_set_encrypt_key(key.data, key.size*8, &aes_key) != 0
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag)) {
+ || !enif_inspect_binary(env, argv[2], &iv) || iv.size == 0
+ || !enif_inspect_iolist_as_binary(env, argv[3], &aad)
+ || !enif_inspect_iolist_as_binary(env, argv[4], &in)
+ || !enif_inspect_iolist_as_binary(env, argv[5], &tag)) {
return enif_make_badarg(env);
}
@@ -2460,118 +2836,67 @@ out_err:
#endif /* HAVE_GCM_EVP_DECRYPT_BUG */
-static ERL_NIF_TERM chacha20_poly1305_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in;
- unsigned char *outp, *tagp;
- ERL_NIF_TERM out, out_tag;
- int len;
+static ERL_NIF_TERM chacha20_stream_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, IV) */
+#if defined(HAVE_CHACHA20)
+ ErlNifBinary key_bin, ivec_bin;
+ struct evp_cipher_ctx *ctx;
+ const EVP_CIPHER *cipher;
+ ERL_NIF_TERM ret;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)) {
- return enif_make_badarg(env);
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
+ || !enif_inspect_binary(env, argv[1], &ivec_bin)
+ || key_bin.size != 32
+ || ivec_bin.size != 16) {
+ return enif_make_badarg(env);
}
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_set_padding(ctx, 0);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_EncryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_EncryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_EncryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_EncryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- tagp = enif_make_new_binary(env, 16, &out_tag);
-
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, 16, tagp) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
+ cipher = EVP_chacha20();
- CONSUME_REDS(env, in);
+ ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
+ ctx->ctx = EVP_CIPHER_CTX_new();
- return enif_make_tuple2(env, out, out_tag);
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
+ EVP_CipherInit_ex(ctx->ctx, cipher, NULL,
+ key_bin.data, ivec_bin.data, 1);
+ EVP_CIPHER_CTX_set_padding(ctx->ctx, 0);
+ ret = enif_make_resource(env, ctx);
+ enif_release_resource(ctx);
+ return ret;
#else
return enif_raise_exception(env, atom_notsup);
#endif
-}
+};
-static ERL_NIF_TERM chacha20_poly1305_decrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
-{/* (Key,Iv,AAD,In,Tag) */
-#if defined(HAVE_CHACHA20_POLY1305)
- EVP_CIPHER_CTX *ctx;
- const EVP_CIPHER *cipher = NULL;
- ErlNifBinary key, iv, aad, in, tag;
- unsigned char *outp;
- ERL_NIF_TERM out;
- int len;
+static ERL_NIF_TERM chacha20_stream_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (State, Data) */
+#if defined(HAVE_CHACHA20)
+ struct evp_cipher_ctx *ctx, *new_ctx;
+ ErlNifBinary data_bin;
+ ERL_NIF_TERM ret, cipher_term;
+ unsigned char *out;
+ int outl = 0;
- if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 32
- || !enif_inspect_binary(env, argv[1], &iv) || iv.size == 0 || iv.size > 16
- || !enif_inspect_iolist_as_binary(env, argv[2], &aad)
- || !enif_inspect_iolist_as_binary(env, argv[3], &in)
- || !enif_inspect_iolist_as_binary(env, argv[4], &tag) || tag.size != 16) {
- return enif_make_badarg(env);
+ if (!enif_get_resource(env, argv[0], evp_cipher_ctx_rtype, (void**)&ctx)
+ || !enif_inspect_iolist_as_binary(env, argv[1], &data_bin)) {
+ return enif_make_badarg(env);
}
+ new_ctx = enif_alloc_resource(evp_cipher_ctx_rtype, sizeof(struct evp_cipher_ctx));
+ new_ctx->ctx = EVP_CIPHER_CTX_new();
+ EVP_CIPHER_CTX_copy(new_ctx->ctx, ctx->ctx);
+ out = enif_make_new_binary(env, data_bin.size, &cipher_term);
+ EVP_CipherUpdate(new_ctx->ctx, out, &outl, data_bin.data, data_bin.size);
+ ASSERT(outl == data_bin.size);
- cipher = EVP_chacha20_poly1305();
-
- ctx = EVP_CIPHER_CTX_new();
-
- if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, iv.size, NULL) != 1)
- goto out_err;
- if (EVP_DecryptInit_ex(ctx, NULL, NULL, key.data, iv.data) != 1)
- goto out_err;
- if (EVP_DecryptUpdate(ctx, NULL, &len, aad.data, aad.size) != 1)
- goto out_err;
-
- outp = enif_make_new_binary(env, in.size, &out);
-
- if (EVP_DecryptUpdate(ctx, outp, &len, in.data, in.size) != 1)
- goto out_err;
- if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, tag.size, tag.data) != 1)
- goto out_err;
- if (EVP_DecryptFinal_ex(ctx, outp+len, &len) != 1)
- goto out_err;
-
- EVP_CIPHER_CTX_free(ctx);
-
- CONSUME_REDS(env, in);
-
- return out;
-
-out_err:
- EVP_CIPHER_CTX_free(ctx);
- return atom_error;
+ ret = enif_make_tuple2(env, enif_make_resource(env, new_ctx), cipher_term);
+ enif_release_resource(new_ctx);
+ CONSUME_REDS(env,data_bin);
+ return ret;
#else
return enif_raise_exception(env, atom_notsup);
#endif
-}
+};
+
static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Bytes) */
@@ -3810,7 +4135,7 @@ static ERL_NIF_TERM ecdh_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF
int i;
EC_GROUP *group;
const BIGNUM *priv_key;
- EC_POINT *my_ecpoint;
+ EC_POINT *my_ecpoint = NULL;
EC_KEY *other_ecdh = NULL;
if (!get_ec_key(env, argv[1], argv[2], atom_undefined, &key))
@@ -3853,11 +4178,10 @@ out_err:
#endif
}
-// EXPERIMENTAL!
static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
/* (Curve, PeerBin, MyBin) */
{
-#ifdef HAVE_EDDH
+#ifdef HAVE_ED_CURVE_DH
int type;
EVP_PKEY_CTX *ctx;
ErlNifBinary peer_bin, my_bin, key_bin;
@@ -3909,11 +4233,10 @@ static ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_
#endif
}
-// EXPERIMENTAL!
static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
/* (Curve) */
{
-#ifdef HAVE_EDDH
+#ifdef HAVE_ED_CURVE_DH
int type;
EVP_PKEY_CTX *ctx;
EVP_PKEY *pkey = NULL;
@@ -3926,22 +4249,20 @@ static ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF
if (!(ctx = EVP_PKEY_CTX_new_id(type, NULL))) return enif_make_badarg(env);
- if (!EVP_PKEY_keygen_init(ctx)) return enif_make_atom(env,"EVP_PKEY_keygen_init failed");
- if (!EVP_PKEY_keygen(ctx, &pkey)) return enif_make_atom(env,"EVP_PKEY_keygen failed");
+ if (!EVP_PKEY_keygen_init(ctx)) return atom_error;
+ if (!EVP_PKEY_keygen(ctx, &pkey)) return atom_error;
- if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len))
- return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 1 failed");
+ if (!EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len)) return atom_error;
if (!EVP_PKEY_get_raw_public_key(pkey,
enif_make_new_binary(env, key_len, &ret_pub),
&key_len))
- return enif_make_atom(env,"EVP_PKEY_get_raw_public_key 2 failed");
+ return atom_error;
- if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len))
- return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 1 failed");
+ if (!EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len)) return atom_error;
if (!EVP_PKEY_get_raw_private_key(pkey,
enif_make_new_binary(env, key_len, &ret_prv),
&key_len))
- return enif_make_atom(env,"EVP_PKEY_get_raw_private_key 2 failed");
+ return atom_error;
return enif_make_tuple2(env, ret_pub, ret_prv);
#else
@@ -4092,7 +4413,7 @@ static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF
if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
opt->rsa_padding = RSA_PKCS1_PADDING;
} else if (tpl_terms[1] == atom_rsa_pkcs1_pss_padding) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,0)
+#ifdef HAVE_RSA_PKCS1_PSS_PADDING
opt->rsa_padding = RSA_PKCS1_PSS_PADDING;
if (opt->rsa_mgf1_md == NULL) {
opt->rsa_mgf1_md = md;
@@ -4381,20 +4702,22 @@ printf("\r\n");
if (argv[0] == atom_rsa) {
if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg;
+# ifdef HAVE_RSA_PKCS1_PSS_PADDING
if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
if (sig_opt.rsa_mgf1_md != NULL) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
+# ifdef HAVE_RSA_MGF1_MD
if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg;
-#else
+# else
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return atom_notsup;
-#endif
+# endif
}
if (sig_opt.rsa_pss_saltlen > -2
&& EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0)
goto badarg;
}
+#endif
}
if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) <= 0) goto badarg;
@@ -4519,13 +4842,13 @@ static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) <= 0) goto badarg;
if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) {
if (sig_opt.rsa_mgf1_md != NULL) {
-#if OPENSSL_VERSION_NUMBER >= PACKED_OPENSSL_VERSION_PLAIN(1,0,1)
+# ifdef HAVE_RSA_MGF1_MD
if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) <= 0) goto badarg;
-#else
+# else
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return atom_notsup;
-#endif
+# endif
}
if (sig_opt.rsa_pss_saltlen > -2
&& EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) <= 0)
@@ -4618,8 +4941,10 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI
) {
if (tpl_terms[1] == atom_rsa_pkcs1_padding) {
opt->rsa_padding = RSA_PKCS1_PADDING;
+#ifdef HAVE_RSA_OAEP_PADDING
} else if (tpl_terms[1] == atom_rsa_pkcs1_oaep_padding) {
opt->rsa_padding = RSA_PKCS1_OAEP_PADDING;
+#endif
#ifdef HAVE_RSA_SSLV23_PADDING
} else if (tpl_terms[1] == atom_rsa_sslv23_padding) {
opt->rsa_padding = RSA_SSLV23_PADDING;
@@ -4638,7 +4963,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI
}
opt->signature_md = opt_md;
} else if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) {
-#ifndef HAVE_RSA_OAEP_MD
+#ifndef HAVE_RSA_MGF1_MD
if (tpl_terms[1] != atom_sha)
return PKEY_NOTSUP;
#endif
@@ -4876,7 +5201,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
} else {
/* non-evp rsa private decrypt */
i = RSA_private_decrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
+ out_bin.data, rsa, crypt_opt.rsa_padding);
if (i > 0) {
ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
enif_realloc_binary(&out_bin, i);
@@ -4894,7 +5219,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
} else {
/* non-evp rsa public decrypt */
i = RSA_public_decrypt(in_bin.size, in_bin.data,
- out_bin.data, rsa, crypt_opt.rsa_padding);
+ out_bin.data, rsa, crypt_opt.rsa_padding);
if (i > 0) {
ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, i);
enif_realloc_binary(&out_bin, i);
@@ -4913,7 +5238,10 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
unsigned char *p;
if (rsa == NULL) goto badarg;
tmplen = RSA_size(rsa);
- if (!enif_alloc_binary(tmplen, &tmp_bin)) goto badarg;
+ if (!enif_alloc_binary(tmplen, &tmp_bin)) {
+ RSA_free(rsa);
+ goto badarg;
+ }
p = out_bin.data;
p++;
i = RSA_padding_check_SSLv23(tmp_bin.data, tmplen, p, out_bin.size - 1, tmplen);
@@ -4924,6 +5252,7 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
tmp_bin = in_bin;
i = 1;
}
+ RSA_free(rsa);
}
#endif
}
@@ -5012,7 +5341,7 @@ static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NI
/ * Example of result:
{
Curve = {Field, Prime, Point, Order, CoFactor} =
- {
+ {
Field = {prime_field,<<255,...,255>>},
Prime = {<<255,...,252>>,
<<90,...,75>>,
@@ -5025,9 +5354,9 @@ static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NI
Key = <<151,...,62>>
}
or
- {
+ {
Curve =
- {characteristic_two_field,
+ {characteristic_two_field,
M,
Basis = {tpbasis, _}
| {ppbasis, k1, k2, k3}
@@ -5040,7 +5369,7 @@ static ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NI
*/
#endif
}
-
+
if (pkey) EVP_PKEY_free(pkey);
return enif_make_badarg(env);
}
@@ -5221,7 +5550,7 @@ static ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const
error:
for(i = 0; cmds != NULL && cmds[i] != NULL; i++)
- enif_free(cmds[i]);
+ enif_free(cmds[i]);
enif_free(cmds);
return ret;
#else
@@ -5539,7 +5868,7 @@ static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
if (!engine_id) {
enif_alloc_binary(0, &engine_id_bin);
engine_id_bin.size = 0;
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_id_bin));
+ return enif_make_binary(env, &engine_id_bin);
}
size = strlen(engine_id);
@@ -5547,7 +5876,39 @@ static ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TE
engine_id_bin.size = size;
memcpy(engine_id_bin.data, engine_id, size);
- return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_id_bin));
+ return enif_make_binary(env, &engine_id_bin);
+#else
+ return atom_notsup;
+#endif
+}
+
+static ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Engine) */
+#ifdef HAS_ENGINE_SUPPORT
+ ErlNifBinary engine_name_bin;
+ const char *engine_name;
+ int size;
+ struct engine_ctx *ctx;
+
+ // Get Engine
+ if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) {
+ PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object");
+ return enif_make_badarg(env);
+ }
+
+ engine_name = ENGINE_get_name(ctx->engine);
+ if (!engine_name) {
+ enif_alloc_binary(0, &engine_name_bin);
+ engine_name_bin.size = 0;
+ return enif_make_binary(env, &engine_name_bin);
+ }
+
+ size = strlen(engine_name);
+ enif_alloc_binary(size, &engine_name_bin);
+ engine_name_bin.size = size;
+ memcpy(engine_name_bin.data, engine_name, size);
+
+ return enif_make_binary(env, &engine_name_bin);
#else
return atom_notsup;
#endif
diff --git a/lib/crypto/c_src/otp_test_engine.c b/lib/crypto/c_src/otp_test_engine.c
index b6c9067964..34c825059f 100644
--- a/lib/crypto/c_src/otp_test_engine.c
+++ b/lib/crypto/c_src/otp_test_engine.c
@@ -64,7 +64,8 @@ static int test_init(ENGINE *e) {
printf("OTP Test Engine Initializatzion!\r\n");
/* Load all digest and cipher algorithms. Needed for password protected private keys */
- OpenSSL_add_all_algorithms();
+ OpenSSL_add_all_ciphers();
+ OpenSSL_add_all_digests();
return 111;
}
diff --git a/lib/crypto/configure.in b/lib/crypto/configure.in
new file mode 100644
index 0000000000..a3b6673f29
--- /dev/null
+++ b/lib/crypto/configure.in
@@ -0,0 +1,775 @@
+dnl Process this file with autoconf to produce a configure script. -*-m4-*-
+dnl
+dnl %CopyrightBegin%
+dnl
+dnl Copyright Ericsson AB 2018. All Rights Reserved.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+dnl
+dnl %CopyrightEnd%
+dnl
+
+dnl define([AC_CACHE_LOAD], )dnl
+dnl define([AC_CACHE_SAVE], )dnl
+
+
+AC_INIT(vsn.mk)
+
+if test -z "$ERL_TOP" || test ! -d "$ERL_TOP" ; then
+ AC_CONFIG_AUX_DIRS(autoconf)
+else
+ erl_top=${ERL_TOP}
+ AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
+fi
+
+if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
+ AC_CANONICAL_HOST
+else
+ host_os=win32
+fi
+
+LM_PRECIOUS_VARS
+
+if test "$cross_compiling" = "yes"; then
+ CROSS_COMPILING=yes
+else
+ CROSS_COMPILING=no
+fi
+AC_SUBST(CROSS_COMPILING)
+
+ERL_XCOMP_SYSROOT_INIT
+
+AC_PROG_CC
+LM_WINDOWS_ENVIRONMENT
+
+ERL_DED
+
+dnl
+dnl SSL, SSH and CRYPTO need the OpenSSL libraries
+dnl
+dnl Check flags --with-ssl, --without-ssl --with-ssl=PATH.
+dnl If no option is given or --with-ssl is set without a path then we
+dnl search for OpenSSL libraries and header files in the standard locations.
+dnl If set to --without-ssl we disable the use of SSL, SSH and CRYPTO.
+dnl If set to --with-ssl=PATH we use that path as the prefix, i.e. we
+dnl use "PATH/include" and "PATH/lib".
+
+AC_CHECK_SIZEOF(void *)
+
+std_ssl_locations="/usr/local /usr/sfw /usr /opt/local /usr/pkg /usr/local/openssl /usr/lib/openssl /usr/openssl /usr/local/ssl /usr/lib/ssl /usr/ssl /"
+
+AC_ARG_WITH(ssl-zlib,
+AS_HELP_STRING([--with-ssl-zlib=PATH],
+ [specify location of ZLib to be used by OpenSSL])
+AS_HELP_STRING([--with-ssl-zlib],
+ [link SSL with Zlib (default if found)])
+AS_HELP_STRING([--without-ssl-zlib],
+ [don't link SSL with ZLib]))
+
+if test "x$with_ssl_zlib" = "xno"; then
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+elif test "x$with_ssl_zlib" = "xyes" || test "x$with_ssl_zlib" = "x"; then
+ if test $erl_xcomp_without_sysroot = yes; then
+ AC_MSG_WARN([Cannot search for zlib; missing cross system root (erl_xcomp_sysroot).])
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ elif test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ else
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ AC_MSG_CHECKING(for static ZLib to be used by SSL in standard locations)
+ for rdir in $std_ssl_locations; do
+ dir="$erl_xcomp_sysroot$rdir"
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$dir/lib64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib64/libz.a"
+ break
+ elif test -f "$dir/lib/64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib/64/libz.a"
+ break
+ fi
+ fi
+ if test -f "$dir/lib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS="$dir/lib/libz.a"
+ break
+ fi
+ done
+ if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
+ AC_MSG_RESULT([no])
+ else
+ AC_MSG_RESULT([$STATIC_ZLIB_LIBS])
+ fi
+ fi
+else
+ SSL_LINK_WITH_ZLIB=no
+ STATIC_ZLIB_LIBS=
+ if test -f "$with_ssl_zlib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/libz.a
+ elif test -f "$with_ssl_zlib/lib/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/libz.a
+ fi
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$with_ssl_zlib/lib64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib64/libz.a
+ elif test -f "$with_ssl_zlib/lib/64/libz.a"; then
+ SSL_LINK_WITH_ZLIB=yes
+ STATIC_ZLIB_LIBS=$with_ssl_zlib/lib/64/libz.a
+ fi
+ fi
+ if test "x$SSL_LINK_WITH_ZLIB" = "xno"; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl-zlib=PATH)
+ fi
+fi
+
+
+AC_ARG_WITH(ssl,
+AS_HELP_STRING([--with-ssl=PATH], [specify location of OpenSSL include and lib])
+AS_HELP_STRING([--with-ssl], [use SSL (default)])
+AS_HELP_STRING([--without-ssl], [don't use SSL]))
+
+AC_ARG_WITH(ssl-incl,
+AS_HELP_STRING([--with-ssl-incl=PATH], [location of OpenSSL include dir, if different than specified by --with-ssl=PATH]),
+[
+case X$with_ssl in
+ X | Xyes | Xno) AC_MSG_ERROR([--with-ssl-incl=PATH set without --with-ssl=PATH]);;
+esac
+],
+[with_ssl_incl=$with_ssl]) #default
+
+AC_ARG_WITH(ssl-rpath,
+AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS],
+ [runtime library path for OpenSSL. Default is "yes", which equates to a
+ number of standard locations. If "no", then no runtime
+ library paths will be used. Anything else should be a
+ comma separated list of paths.]),
+[
+case X$with_ssl in
+ Xno) AC_MSG_ERROR([--with-ssl-rpath set without --with-ssl]);;
+esac
+],
+[with_ssl_rpath=yes]) #default
+
+
+AC_ARG_ENABLE(dynamic-ssl-lib,
+AS_HELP_STRING([--disable-dynamic-ssl-lib],
+ [disable using dynamic openssl libraries]),
+[ case "$enableval" in
+ no) enable_dynamic_ssl=no ;;
+ *) enable_dynamic_ssl=yes ;;
+ esac ], enable_dynamic_ssl=yes)
+
+#----------------------------------------------------------------------
+# We actually might do the SSL tests twice due to late discovery of
+# kerberos problems with static linking, in case we redo it all trying
+# dynamic SSL libraries instead.
+#----------------------------------------------------------------------
+
+ssl_done=no
+
+while test "x$ssl_done" != "xyes"; do
+
+ssl_done=yes # Default only one run
+
+# Remove all SKIP files from previous runs
+for a in ssl crypto ssh; do
+ rm -f "$ERL_TOP/lib/$a/SKIP"
+done
+
+SSL_DYNAMIC_ONLY=$enable_dynamic_ssl
+SSL_STATIC_ONLY=no
+
+case "$erl_xcomp_without_sysroot-$with_ssl" in
+ yes-* | no-no)
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ if test "$with_ssl" = "no"; then
+ skip="User gave --without-ssl option"
+ else
+ skip="Cannot search for ssl; missing cross system root (erl_xcomp_sysroot)."
+ fi
+ for a in ssl crypto ssh; do
+ echo "$skip" > $ERL_TOP/lib/$a/SKIP
+ done
+ ;;
+ no-yes | no- )
+ # On windows, we could try to find the installation
+ # of Shining Light OpenSSL, which can be found by poking in
+ # the uninstall section in the registry, it's worth a try...
+ extra_dir=""
+ if test "x$MIXED_CYGWIN" = "xyes"; then
+ AC_CHECK_PROG(REGTOOL, regtool, regtool, false)
+ if test "$ac_cv_prog_REGTOOL" != false; then
+ wrp="/machine/software/microsoft/windows/currentversion/"
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ urp="uninstall/openssl (64-bit)_is1/inno setup: app path"
+ regtool_subsystem=-w
+ else
+ urp="uninstall/openssl (32-bit)_is1/inno setup: app path"
+ regtool_subsystem=-W
+ fi
+ rp="$wrp$urp"
+ if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
+ true
+ else
+ # Fallback to unspecified wordlength
+ urp="uninstall/openssl_is1/inno setup: app path"
+ rp="$wrp$urp"
+ fi
+ if regtool -q $regtool_subsystem get "$rp" > /dev/null; then
+ ssl_install_dir=`regtool -q $regtool_subsystem get "$rp"`
+ # Try hard to get rid of spaces...
+ if cygpath -d "$ssl_install_dir" > /dev/null 2>&1; then
+ ssl_install_dir=`cygpath -d "$ssl_install_dir"`
+ fi
+ extra_dir=`cygpath $ssl_install_dir`
+ fi
+ fi
+ elif test "x$MIXED_MSYS" = "xyes"; then
+ AC_CHECK_PROG(REGTOOL, reg_query.sh, reg_query.sh, false)
+ if test "$ac_cv_prog_REGTOOL" != false; then
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL (64-bit)_is1"
+ else
+ rp="HKLM/SOFTWARE/Microsoft/Windows/CurrentVersion/Uninstall/OpenSSL_is1"
+ fi
+ key="Inno Setup: App Path"
+ if "$ac_cv_prog_REGTOOL" "$rp" "$key" > /dev/null; then
+ ssl_install_dir=`"$ac_cv_prog_REGTOOL" "$rp" "$key"`
+ extra_dir=`win2msys_path.sh "$ssl_install_dir"`
+ fi
+ fi
+ fi
+ # We search for OpenSSL in the common OS standard locations.
+ SSL_APP=ssl
+ CRYPTO_APP=crypto
+ SSH_APP=ssh
+
+ SSL_CRYPTO_LIBNAME=crypto
+ SSL_SSL_LIBNAME=ssl
+
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ std_win_ssl_locations="/cygdrive/c/OpenSSL-Win64 /c/OpenSSL-Win64 /opt/local64/pgm/OpenSSL"
+ else
+ std_win_ssl_locations="/cygdrive/c/OpenSSL-Win32 /c/OpenSSL-Win32 /cygdrive/c/OpenSSL /c/OpenSSL /opt/local/pgm/OpenSSL"
+ fi
+ else
+ std_win_ssl_locations=""
+ fi
+
+
+ AC_MSG_CHECKING(for OpenSSL >= 0.9.8c in standard locations)
+ for rdir in $extra_dir $std_win_ssl_locations $std_ssl_locations; do
+ dir="$erl_xcomp_sysroot$rdir"
+ if test -f "$erl_xcomp_isysroot$rdir/include/openssl/opensslv.h"; then
+ is_real_ssl=yes
+ SSL_INCDIR="$dir"
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ if test -f "$dir/lib/VC/libeay32.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$dir/lib/VC/openssl.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ elif test -f $dir/lib/VC/libeay32MD.lib; then
+ SSL_CRYPTO_LIBNAME=libeay32MD
+ SSL_SSL_LIBNAME=ssleay32MD
+ if test "x$enable_dynamic_ssl" = "xno" && \
+ test -f $dir/lib/VC/static/libeay32MD.lib; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC/static"
+ SSL_LIBDIR="$dir/lib/VC/static"
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib/VC"
+ SSL_LIBDIR="$dir/lib/VC"
+ fi
+ elif test -f "$dir/lib/libeay32.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$dir/lib/openssl.lib"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ else
+ is_real_ssl=no
+ fi
+ elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
+ SSL_CRYPTO_LIBNAME=sslcrypto
+ SSL_LIBDIR="$dir/lib/powerpc/"
+ SSL_RUNTIME_LIBDIR="$rdir/lib/powerpc/"
+ else
+ if test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$dir/lib64/libcrypto.a"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib64"
+ SSL_LIBDIR="$dir/lib64"
+ elif test -f "$dir/lib/64/libcrypto.a"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/64"
+ SSL_LIBDIR="$dir/lib/64"
+ elif test -f "$dir/lib64/libcrypto.so"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib64"
+ SSL_LIBDIR="$dir/lib64"
+ elif test -f "$dir/lib/64/libcrypto.so"; then
+ SSL_RUNTIME_LIBDIR="$rdir/lib/64"
+ SSL_LIBDIR="$dir/lib/64"
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ fi
+ else
+ SSL_RUNTIME_LIBDIR="$rdir/lib"
+ SSL_LIBDIR="$dir/lib"
+ fi
+ fi
+ if test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.a"; then
+ SSL_DYNAMIC_ONLY=yes
+ elif test '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.so" -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
+ SSL_STATIC_ONLY=yes
+ fi
+ SSL_BINDIR="$rdir/bin"
+ if test "x$is_real_ssl" = "xyes" ; then
+ SSL_INCLUDE="-I$dir/include"
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS=$SSL_INCLUDE
+ AC_EGREP_CPP(^yes$,[
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER >= 0x0090803fL
+yes
+#endif
+ ],[
+ ssl_found=yes
+ ],[
+ SSL_APP=
+ ssl_found=no
+ ])
+ CPPFLAGS=$old_CPPFLAGS
+ if test "x$ssl_found" = "xyes"; then
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes"; then
+ ssl_linkable=yes
+ elif test "x${SSL_CRYPTO_LIBNAME}" = "xsslcrypto"; then
+ # This should only be triggered seen OSE
+ ssl_linkable=yes
+ else
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ if test "x$SSL_STATIC_ONLY" = "xyes"; then
+ LIBS="${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"
+ else
+ LDFLAGS="$LDFLAGS -L$SSL_LIBDIR"
+ LIBS="$LIBS -l${SSL_CRYPTO_LIBNAME}"
+ fi
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [ssl_linkable=yes],
+ [ssl_linkable=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+ fi
+ fi
+ if test "x$ssl_found" = "xyes" && test "x$ssl_linkable" = "xyes"; then
+ AC_MSG_RESULT([$dir])
+ break;
+ fi
+ fi
+ fi
+ done
+
+ if test "x$ssl_found" != "xyes" ; then
+ dnl
+ dnl If no SSL found above, check whether we are running on OpenBSD.
+ dnl
+ case $host_os in
+ openbsd*)
+ if test -f "$erl_xcomp_isysroot/usr/include/openssl/opensslv.h"; then
+ # Trust OpenBSD to have everything the in the correct locations.
+ ssl_found=yes
+ ssl_linkable=yes
+ SSL_INCDIR="$erl_xcomp_sysroot/usr"
+ AC_MSG_RESULT([$SSL_INCDIR])
+ SSL_RUNTIME_LIB="/usr/lib"
+ SSL_LIB="$erl_xcomp_sysroot/usr/lib"
+ SSL_BINDIR="/usr/sbin"
+ dnl OpenBSD requires us to link with -L and -l
+ SSL_DYNAMIC_ONLY="yes"
+ fi
+ ;;
+ esac
+ fi
+dnl Now, certain linuxes have a 64bit libcrypto
+dnl that cannot build shared libraries (i.e. not PIC)
+dnl One could argue that this is wrong, but
+dnl so it is - be adoptable
+ if test "$ssl_found" = "yes" && test "$ssl_linkable" = "yes" && test "$SSL_DYNAMIC_ONLY" != "yes"; then
+ case $host_os in
+ linux*)
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$DED_CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$DED_LDFLAGS"
+ LIBS="$SSL_LIBDIR/libcrypto.a $STATIC_ZLIB_LIBS"
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [ssl_dyn_linkable=yes],
+ [ssl_dyn_linkable=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+ if test "x$ssl_dyn_linkable" != "xyes"; then
+ SSL_DYNAMIC_ONLY=yes
+ AC_MSG_WARN([SSL will be linked against dynamic lib as static lib is not purely relocatable])
+ fi
+ ;;
+ esac
+ fi
+
+
+
+
+ if test "x$ssl_found" != "xyes" || test "x$ssl_linkable" != "xyes"; then
+ if test "x$ssl_found" = "xyes"; then
+ AC_MSG_RESULT([found; but not usable])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ AC_MSG_WARN([No (usable) OpenSSL found, skipping ssl, ssh and crypto applications])
+
+ for a in ssl crypto ssh; do
+ echo "No usable OpenSSL found" > $ERL_TOP/lib/$a/SKIP
+ done
+ fi
+ ;;
+ *)
+ # Option given with PATH to package
+ if test ! -d "$with_ssl" ; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl=PATH)
+ fi
+ if test ! -d "$with_ssl_incl" ; then
+ AC_MSG_ERROR(Invalid path to option --with-ssl-incl=PATH)
+ fi
+ SSL_INCDIR="$with_ssl_incl"
+ SSL_CRYPTO_LIBNAME=crypto
+ SSL_SSL_LIBNAME=ssl
+ if test "x$MIXED_CYGWIN" = "xyes" -o "x$MIXED_MSYS" = "xyes" && test -d "$with_ssl/lib/VC"; then
+ if test -f "$with_ssl/lib/VC/libeay32.lib"; then
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ elif test -f "$with_ssl/lib/VC/openssl.lib"; then
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ elif test -f $with_ssl/lib/VC/libeay32MD.lib; then
+ SSL_CRYPTO_LIBNAME=libeay32MD
+ SSL_SSL_LIBNAME=ssleay32MD
+ if test "x$enable_dynamic_ssl" = "xno" && \
+ test -f $with_ssl/lib/VC/static/libeay32MD.lib; then
+ SSL_LIBDIR="$with_ssl/lib/VC/static"
+ else
+ SSL_LIBDIR="$with_ssl/lib/VC"
+ fi
+ elif test -f "$with_ssl/lib/libeay32.lib"; then
+ SSL_LIBDIR="$with_ssl/lib"
+ SSL_CRYPTO_LIBNAME=libeay32
+ SSL_SSL_LIBNAME=ssleay32
+ else
+ # This probably wont work, but that's what the user said, so...
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ elif test -f "$dir/lib/powerpc/libsslcrypto.a"; then
+ SSL_CRYPTO_LIBNAME=sslcrypto
+ SSL_LIBDIR="$with_ssl/lib/powerpc/"
+ elif test "x$ac_cv_sizeof_void_p" = "x8"; then
+ if test -f "$with_ssl/lib64/libcrypto.a"; then
+ SSL_LIBDIR="$with_ssl/lib64"
+ elif test -f "$with_ssl/lib/64/libcrypto.a"; then
+ SSL_LIBDIR="$with_ssl/lib/64"
+ elif test -f "$with_ssl/lib64/libcrypto.so"; then
+ SSL_LIBDIR="$with_ssl/lib64"
+ elif test -f "$with_ssl/lib/64/libcrypto.so"; then
+ SSL_LIBDIR="$with_ssl/lib/64"
+ else
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ else
+ SSL_LIBDIR="$with_ssl/lib"
+ fi
+ if test '!' -f "${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.a"; then
+ SSL_DYNAMIC_ONLY=yes
+ elif test '!' -f ${SSL_LIBDIR}/lib${SSL_CRYPTO_LIBNAME}.so -a '!' -f "$SSL_LIBDIR/lib${SSL_CRYPTO_LIBNAME}.dylib"; then
+ SSL_STATIC_ONLY=yes
+ fi
+ SSL_INCLUDE="-I$with_ssl_incl/include"
+ SSL_APP=ssl
+ CRYPTO_APP=crypto
+ SSH_APP=ssh
+ if test "$cross_compiling" = "yes"; then
+ SSL_RUNTIME_LIBDIR=`echo "$SSL_LIBDIR" | sed -n "s|^$erl_xcomp_sysroot\(/*\)\(.*\)\$|/\2|p"`
+ else
+ SSL_RUNTIME_LIBDIR="$SSL_LIBDIR"
+ fi
+esac
+
+if test "x$SSL_APP" != "x" ; then
+ dnl We found openssl, now check if we use kerberos 5 support
+ dnl FIXME: Do we still support platforms that have Kerberos?
+ AC_MSG_CHECKING(for OpenSSL kerberos 5 support)
+ old_CPPFLAGS=$CPPFLAGS
+ CPPFLAGS=$SSL_INCLUDE
+ AC_EGREP_CPP(^yes$,[
+#include <openssl/opensslv.h>
+#include <openssl/opensslconf.h>
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL && !defined(OPENSSL_NO_KRB5)
+yes
+#endif
+ ],[
+ AC_MSG_RESULT([yes])
+ ssl_krb5_enabled=yes
+ if test "x$SSL_DYNAMIC_ONLY" != "xyes"; then
+ if test -f "$SSL_LIBDIR/libkrb5.a"; then
+ SSL_LINK_WITH_KERBEROS=yes
+ STATIC_KERBEROS_LIBS="$SSL_LIBDIR/libkrb5.a"
+ if test -f "$SSL_LIBDIR/libkrb5support.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libkrb5support.a"
+ fi
+ if test -f "$SSL_LIBDIR/libk5crypto.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libk5crypto.a"
+ fi
+ if test -f "$SSL_LIBDIR/libresolv.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libresolv.a"
+ fi
+ if test -f "$SSL_LIBDIR/libcom_err.a"; then
+ STATIC_KERBEROS_LIBS="$STATIC_KERBEROS_LIBS $SSL_LIBDIR/libcom_err.a"
+ fi
+ else
+ AC_MSG_WARN([Kerberos needed but no kerberos static libraries found])
+ AC_MSG_WARN([Rescanning for dynamic SSL libraries])
+ enable_dynamic_ssl=yes
+ ssl_done=no
+ SSL_LINK_WITH_KERBEROS=no
+ STATIC_KERBEROS_LIBS=""
+ ssl_krb5_enabled=no
+ SSL_WITH_KERBEROS=no
+ fi
+ else
+ SSL_LINK_WITH_KERBEROS=no
+ STATIC_KERBEROS_LIBS=""
+ fi
+ ],[
+ AC_MSG_RESULT([no])
+ ssl_krb5_enabled=no
+ SSL_WITH_KERBEROS=no
+ ])
+ CPPFLAGS=$old_CPPFLAGS
+ SSL_KRB5_INCLUDE=
+ if test "x$ssl_krb5_enabled" = "xyes" ; then
+ AC_MSG_CHECKING(for krb5.h in standard locations)
+ for dir in $extra_dir "$SSL_INCDIR/include" "$SSL_INCDIR/include/openssl" \
+ "$SSL_INCDIR/include/kerberos" \
+ "$erl_xcomp_isysroot/cygdrive/c/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/local/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/kerberos/include" \
+ "$erl_xcomp_isysroot/usr/include"
+ do
+ if test -f "$dir/krb5.h" ; then
+ SSL_KRB5_INCLUDE="$dir"
+ break
+ fi
+ done
+ if test "x$SSL_KRB5_INCLUDE" = "x" ; then
+ AC_MSG_RESULT([not found])
+ SSL_APP=
+ CRYPTO_APP=
+ SSH_APP=
+ AC_MSG_WARN([OpenSSL is configured for kerberos but no krb5.h found])
+ for a in ssl crypto ssh ; do
+ echo "OpenSSL is configured for kerberos but no krb5.h found" > $ERL_TOP/lib/$a/SKIP
+ done
+ else
+ AC_MSG_RESULT([found in $SSL_KRB5_INCLUDE])
+ SSL_INCLUDE="$SSL_INCLUDE -I$SSL_KRB5_INCLUDE"
+ fi
+ fi
+fi
+
+done # while test ssl_done != yes
+
+SSL_DED_LD_RUNTIME_LIBRARY_PATH=
+ded_ld_rflg="$DED_LD_FLAG_RUNTIME_LIBRARY_PATH"
+
+
+case "$with_ssl_rpath" in
+
+yes) # Use standard lib locations for ssl runtime library path
+
+ if test "$SSL_APP" != "" && test "$SSL_DYNAMIC_ONLY" = "yes" && test "$ded_ld_rflg" != ""; then
+
+ AC_MSG_CHECKING(for ssl runtime library path to use)
+
+ libdirs="/lib"
+
+ if test "$ac_cv_sizeof_void_p" = "8"; then
+ dir_lib64=no
+ dir_lib_64=no
+
+ case "$SSL_RUNTIME_LIBDIR" in
+ */lib/64 | */lib/64/ ) dir_lib_64=yes;;
+ */lib64 | */lib64/ ) dir_lib64=yes;;
+ *) ;;
+ esac
+
+ for dir in $std_ssl_locations; do
+ test $dir_lib_64 = no &&
+ test -d "$erl_xcomp_sysroot$dir/lib/64" &&
+ dir_lib_64=yes
+ test $dir_lib64 = no &&
+ test -d "$erl_xcomp_sysroot$dir/lib64" &&
+ dir_lib64=yes
+ done
+
+ test $dir_lib_64 = yes && libdirs="/lib/64 $libdirs"
+ test $dir_lib64 = yes && libdirs="/lib64 $libdirs"
+ fi
+
+ for type in std x_std curr; do
+
+ ded_ld_rpath="$ded_ld_rflg$SSL_RUNTIME_LIBDIR"
+ rpath="$SSL_RUNTIME_LIBDIR"
+
+ if test $type != curr; then
+ for ldir in $libdirs; do
+ for dir in $std_ssl_locations; do
+ test "$SSL_LIBDIR" != "$dir$ldir" || continue
+ test $type != x_std || test -d "$dir$ldir" || continue
+ if test "$dir" = "/"; then
+ libdir="$ldir"
+ else
+ libdir="$dir$ldir"
+ fi
+ ded_ld_rpath="$ded_ld_rpath $ded_ld_rflg$libdir"
+ rpath="$rpath:$libdir"
+ done
+ done
+ fi
+
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$LDFLAGS $ld_rpath -L$SSL_LIBDIR"
+ LIBS="-lcrypto"
+ AC_TRY_LINK([
+ #include <stdio.h>
+ #include <openssl/hmac.h>
+ ],
+ [
+ HMAC(0, 0, 0, 0, 0, 0, 0);
+ ],
+ [rpath_success=yes],
+ [rpath_success=no])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+
+ test "$rpath_success" = "yes" && break
+ done
+
+ test "$rpath_success" = "yes" || { ded_ld_rpath=; rpath=; }
+
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
+
+ AC_MSG_RESULT([$rpath])
+ test "$rpath" != "" || AC_MSG_WARN([Cannot set run path during linking])
+ fi
+ ;;
+
+no) # Use no ssl runtime library path
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH=
+ ;;
+
+*) # Use ssl runtime library paths set by --with-ssl-rpath (without any check)
+ ded_ld_rpath=
+ delimit=
+ for dir in `echo $with_ssl_rpath | sed "s/,/ /g"`; do
+ ded_ld_rpath="$ded_ld_rpath$delimit$ded_ld_rflg$dir"
+ delimit=" "
+ done
+ SSL_DED_LD_RUNTIME_LIBRARY_PATH="$ded_ld_rpath"
+ ;;
+
+esac
+
+
+AC_ARG_ENABLE(fips,
+AS_HELP_STRING([--enable-fips], [enable OpenSSL FIPS mode support])
+AS_HELP_STRING([--disable-fips], [disable OpenSSL FIPS mode support (default)]),
+[ case "$enableval" in
+ yes) enable_fips_support=yes ;;
+ *) enable_fips_support=no ;;
+ esac ], enable_fips_support=no)
+
+if test "x$enable_fips_support" = "xyes" && test "$CRYPTO_APP" != ""; then
+ saveCFLAGS="$CFLAGS"
+ saveLDFLAGS="$LDFLAGS"
+ saveLIBS="$LIBS"
+ CFLAGS="$CFLAGS $SSL_INCLUDE"
+ LDFLAGS="$LDFLAGS $ded_ld_rpath -L$SSL_LIBDIR"
+ LIBS="-lcrypto"
+ AC_CHECK_FUNC([FIPS_mode_set],
+ [SSL_FLAGS="-DFIPS_SUPPORT"],
+ [SSL_FLAGS=])
+ CFLAGS="$saveCFLAGS"
+ LDFLAGS="$saveLDFLAGS"
+ LIBS="$saveLIBS"
+else
+ SSL_FLAGS=
+fi
+
+AC_SUBST(SSL_INCLUDE)
+AC_SUBST(SSL_INCDIR)
+AC_SUBST(SSL_LIBDIR)
+AC_SUBST(SSL_FLAGS)
+AC_SUBST(SSL_CRYPTO_LIBNAME)
+AC_SUBST(SSL_SSL_LIBNAME)
+AC_SUBST(SSL_DED_LD_RUNTIME_LIBRARY_PATH)
+AC_SUBST(SSL_DYNAMIC_ONLY)
+AC_SUBST(SSL_LINK_WITH_KERBEROS)
+AC_SUBST(STATIC_KERBEROS_LIBS)
+AC_SUBST(SSL_LINK_WITH_ZLIB)
+AC_SUBST(STATIC_ZLIB_LIBS)
+
+AC_OUTPUT(c_src/$host/Makefile:c_src/Makefile.in)
+
diff --git a/lib/crypto/doc/specs/.gitignore b/lib/crypto/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/crypto/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/crypto/doc/src/Makefile b/lib/crypto/doc/src/Makefile
index 2148062e78..cbcafb7375 100644
--- a/lib/crypto/doc/src/Makefile
+++ b/lib/crypto/doc/src/Makefile
@@ -39,7 +39,7 @@ XML_REF3_FILES = crypto.xml
XML_REF6_FILES = crypto_app.xml
XML_PART_FILES = usersguide.xml
-XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml
+XML_CHAPTER_FILES = notes.xml licenses.xml fips.xml engine_load.xml engine_keys.xml algorithm_details.xml
BOOK_FILES = book.xml
@@ -62,11 +62,17 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
+#in ssh it looks like this: SPECS_FLAGS = -I../../../public_key/include -I../../../public_key/src -I../../..
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -93,6 +99,7 @@ clean clean_docs clean_tex:
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
# ----------------------------------------------------
diff --git a/lib/crypto/doc/src/algorithm_details.xml b/lib/crypto/doc/src/algorithm_details.xml
new file mode 100644
index 0000000000..4d58d26970
--- /dev/null
+++ b/lib/crypto/doc/src/algorithm_details.xml
@@ -0,0 +1,341 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2014</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>Algorithm Details</title>
+ <prepared>Hans Nilsson</prepared>
+ <docno></docno>
+ <date>2018-08-22</date>
+ <rev>A</rev>
+ <file>algorithm_details.xml</file>
+ </header>
+ <p>
+ This chapter describes details of algorithms in the crypto application.
+ </p>
+ <p>The tables only documents the supported cryptos and key lengths. The user should not draw any conclusion
+ on security from the supplied tables.
+ </p>
+
+ <section>
+ <title>Ciphers</title>
+ <section>
+ <title>Block Ciphers</title>
+ <p>To be used in
+ <seealso marker="crypto#block_encrypt-3">block_encrypt/3</seealso>,
+ <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso>,
+ <seealso marker="crypto#block_decrypt-3">block_decrypt/3</seealso> and
+ <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
+ </p>
+ <p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell></row>
+ <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell><cell>16</cell></row>
+
+ <row><cell><c>aes_cfb8</c></cell> <cell>16, 24, 32</cell><cell>16</cell><cell>any</cell></row>
+
+ <row><cell><c>aes_ecb</c></cell><cell>16, 24, 32</cell><cell> </cell><cell>16</cell></row>
+
+ <row><cell><c>aes_ige256</c></cell><cell>16</cell><cell>32</cell><cell>16</cell></row>
+ <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>8</cell> <cell>any</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell><cell> </cell><cell>8</cell></row>
+ <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>any</cell></row>
+
+ <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
+ <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>any</cell></row>
+
+ <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell> <cell>8</cell></row>
+ <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>8</cell><cell>any</cell></row>
+ <row><cell><c>des_ecb</c></cell><cell>8</cell><cell> </cell><cell>8</cell></row>
+ <row><cell><c>des_ede3</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell><cell>8</cell></row>
+ <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell><cell>8</cell></row>
+ <tcaption>Block cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>AEAD Ciphers</title>
+ <p>To be used in <seealso marker="crypto#block_encrypt-4">block_encrypt/4</seealso> and
+ <seealso marker="crypto#block_decrypt-4">block_decrypt/4</seealso>.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>AAD length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Tag length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Block size</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
+ <row><cell><c>aes_ccm</c></cell> <cell>16,24,32</cell> <cell>7-13</cell> <cell>any</cell> <cell>even 4-16<br/>default: 12</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <row><cell><c>aes_gcm</c></cell> <cell>16,24,32</cell> <cell>&#8805;1</cell> <cell>any</cell> <cell>1-16<br/>default: 16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <row><cell><c>chacha20_poly1305</c></cell><cell>32</cell> <cell>1-16</cell> <cell>any</cell> <cell>16</cell> <cell>any</cell><cell>&#8805;1.1.0</cell></row>
+ <tcaption>AEAD cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>Stream Ciphers</title>
+ <p>To be used in <seealso marker="crypto#stream_init-2">stream_init/2</seealso> and
+ <seealso marker="crypto#stream_init/3">stream_init/3</seealso>.
+ </p>
+ <p>To dynamically check availability, check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>IV length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell></row>
+ <row><cell><c>aes_ctr</c></cell><cell>16, 24, 32</cell><cell>16</cell><cell>&#8805;1.0.1</cell></row>
+ <row><cell><c>rc4</c></cell><cell>&#8805;1</cell><cell> </cell> <cell>all</cell></row>
+ <tcaption>Stream cipher key lengths</tcaption>
+ </table>
+ </section>
+ </section>
+
+ <section>
+ <title>Message Authentication Codes (MACs)</title>
+
+ <section>
+ <title>CMAC</title>
+ <p>To be used in <seealso marker="crypto#cmac-3">cmac/3</seealso> and
+ <seealso marker="crypto#cmac-3">cmac/4</seealso>.
+ </p>
+ <p>CMAC with the following ciphers are available with OpenSSL 1.0.1 or later if not disabled by configuration.
+ </p>
+
+ <p>To dynamically check availability, check that the name <c>cmac</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ Also check that the name in the <i>Cipher and Mode</i> column is present in the
+ list with the <c>cipher</c> tag in the return value.
+ </p>
+ <table>
+ <row><cell><strong>Cipher and Mode</strong></cell><cell><strong>Key length</strong><br/><strong>[bytes]</strong></cell><cell><strong>Max Mac Length</strong><br/><strong>[bytes]</strong></cell></row>
+ <row><cell><c>aes_cbc</c></cell> <cell>16, 24, 32</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc128</c></cell><cell>16</cell><cell>16</cell></row>
+ <row><cell><c>aes_cbc256</c></cell><cell>32</cell><cell>16</cell></row>
+
+ <row><cell><c>aes_cfb8</c></cell> <cell>16</cell><cell>1</cell></row>
+
+ <row><cell><c>blowfish_cbc</c></cell> <cell>4-56</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_cfb64</c></cell> <cell>&#8805;1</cell> <cell>1</cell></row>
+ <row><cell><c>blowfish_ecb</c></cell><cell>&#8805;1</cell> <cell>8</cell></row>
+ <row><cell><c>blowfish_ofb64</c></cell><cell>&#8805;1</cell> <cell>1</cell></row>
+
+ <row><cell><c>des3_cbc</c><br/><i>(=DES EDE3 CBC)</i></cell><cell>[8,8,8]</cell><cell>8</cell></row>
+ <row><cell><c>des3_cfb</c><br/><i>(=DES EDE3 CFB)</i></cell><cell>[8,8,8]</cell><cell>1</cell></row>
+
+ <row><cell><c>des_cbc</c></cell><cell>8</cell><cell>8</cell></row>
+
+ <row><cell><c>des_cfb</c></cell><cell>8</cell><cell>1</cell></row>
+ <row><cell><c>des_ecb</c></cell><cell>8</cell><cell>1</cell></row>
+ <row><cell><c>rc2_cbc</c></cell><cell>&#8805;1</cell><cell>8</cell></row>
+ <tcaption>CMAC cipher key lengths</tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>HMAC</title>
+ <p>Available in all OpenSSL compatible with Erlang CRYPTO if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name <c>hmac</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>POLY1305</title>
+ <p>POLY1305 is available with OpenSSL 1.1.1 or later if not disabled by configuration.
+ </p>
+ <p>To dynamically check availability, check that the name <c>poly1305</c> is present in the
+ list with the <c>macs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ </section>
+
+ <section>
+ <title>Hash</title>
+
+ <p>To dynamically check availability, check that the wanted name in the <i>Names</i> column is present in the
+ list with the <c>hashs</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+
+
+ <table>
+ <row><cell><strong>Type</strong></cell>
+ <cell><strong>Names</strong></cell>
+ <cell><strong>Supported with</strong><br/><strong>OpenSSL versions</strong></cell>
+ </row>
+ <row><cell>SHA1</cell><cell>sha</cell><cell>all</cell></row>
+ <row><cell>SHA2</cell><cell>sha224, sha256, sha384, sha512</cell><cell>all</cell></row>
+ <row><cell>SHA3</cell><cell>sha3_224, sha3_256, sha3_384, sha3_512</cell><cell>&#8805;1.1.1</cell></row>
+ <row><cell>MD4</cell><cell>md4</cell><cell>all</cell></row>
+ <row><cell>MD5</cell><cell>md5</cell><cell>all</cell></row>
+ <row><cell>RIPEMD</cell><cell>ripemd160</cell><cell>all</cell></row>
+ <tcaption></tcaption>
+ </table>
+ </section>
+
+ <section>
+ <title>Public Key Cryptography</title>
+
+ <section>
+ <title>RSA</title>
+ <p>RSA is available with all OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>rsa</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ <table>
+ <row><cell><strong>Option</strong></cell>
+ <cell><strong>sign/verify</strong></cell>
+ <cell><strong>public encrypt</strong><br/><strong>private decrypt</strong></cell>
+ <cell><strong>private encrypt</strong><br/><strong>public decrypt</strong></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_x931_padding}</cell>
+ <cell>x</cell>
+ <cell></cell>
+ <cell>x</cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_padding}</cell>
+ <cell>x</cell>
+ <cell>x</cell>
+ <cell>x</cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_pss_padding}<br/>
+ {rsa_pss_saltlen, -2..}<br/>
+ {rsa_mgf1_md, atom()}
+ </cell>
+ <cell>x (2)<br/>
+ x (2)<br/>
+ x (2)</cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_pkcs1_oaep_padding}<br/>
+ {rsa_mgf1_md, atom()}<br/>
+ {rsa_oaep_label, binary()}}<br/>
+ {rsa_oaep_md, atom()}
+ </cell>
+ <cell></cell>
+ <cell>x (2)<br/>
+ x (2)<br/>
+ x (3)<br/>
+ x (3)
+ </cell>
+ <cell></cell>
+ </row>
+ <row><cell>{rsa_padding,rsa_no_padding}</cell>
+ <cell>x (1)</cell>
+ <cell></cell>
+ <cell></cell>
+ </row>
+ <!-- row><cell>{rsa_padding,rsa_sslv23_padding}</cell>
+ <cell></cell>
+ <cell></cell>
+ <cell></cell>
+ </row -->
+ <tcaption></tcaption>
+ </table>
+ <p>Notes:</p>
+ <list type="ordered">
+ <item>(1) OpenSSL &#8804; 1.0.0</item>
+ <item>(2) OpenSSL &#8805; 1.0.1</item>
+ <item>(3) OpenSSL &#8805; 1.1.0</item>
+ </list>
+ </section>
+
+ <section>
+ <title>DSS</title>
+ <p>DSS is available with OpenSSL versions compatible with Erlang CRYPTO if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>dss</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>ECDSA</title>
+ <p>ECDSA is available with OpenSSL 0.9.8o or later if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>ecdsa</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ If the atom <c>ec_gf2m</c> characteristic two field curves are available.
+ </p>
+ <p>The actual supported named curves could be checked by examining the list with the
+ <c>curves</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Diffie-Hellman</title>
+ <p>Diffie-Hellman computations are available with OpenSSL versions compatible with Erlang CRYPTO
+ if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>dh</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Elliptic Curve Diffie-Hellman</title>
+ <p>Elliptic Curve Diffie-Hellman is available with OpenSSL 0.9.8o or later if not disabled by configuration.
+ To dynamically check availability, check that the atom <c>ecdh</c> is present in the
+ list with the <c>public_keys</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+
+ <p>The Edward curves <c>x25519</c> and <c>x448</c> are supported with OpenSSL 1.1.1 or later
+ if not disabled by configuration.
+ </p>
+
+ <p>The actual supported named curves could be checked by examining the list with the
+ <c>curves</c> tag in the return value of
+ <seealso marker="crypto#supports-0">crypto:supports()</seealso>.
+ </p>
+ </section>
+
+ </section>
+
+
+</chapter>
+
+
+
+
+
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 42e411a0e3..b8ec41bea8 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -1,4 +1,3 @@
-<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -28,226 +27,528 @@
<description>
<p>This module provides a set of cryptographic functions.
</p>
- <list type="bulleted">
- <item>
- <p>Hash functions -
- <url href="http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf"> Secure Hash Standard</url>,
- <url href="http://www.ietf.org/rfc/rfc1321.txt"> The MD5 Message Digest Algorithm (RFC 1321)</url> and
- <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm (RFC 1320)</url>
- </p>
- </item>
- <item>
- <p>Hmac functions - <url href="http://www.ietf.org/rfc/rfc2104.txt"> Keyed-Hashing for Message Authentication (RFC 2104) </url></p>
- </item>
- <item>
- <p>Cmac functions - <url href="http://www.ietf.org/rfc/rfc4493.txt">The AES-CMAC Algorithm (RFC 4493)</url></p>
- </item>
- <item>
- <p>Block ciphers - <url href="http://csrc.nist.gov/groups/ST/toolkit/block_ciphers.html"> </url> DES and AES in
- Block Cipher Modes - <url href="http://csrc.nist.gov/groups/ST/toolkit/BCM/index.html"> ECB, CBC, CFB, OFB, CTR and GCM </url></p>
- </item>
- <item>
- <p><url href="http://www.ietf.org/rfc/rfc1321.txt"> RSA encryption RFC 1321 </url> </p>
- </item>
- <item>
- <p>Digital signatures <url href="http://csrc.nist.gov/publications/drafts/fips186-3/fips_186-3.pdf">Digital Signature Standard (DSS)</url> and<url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf"> Elliptic Curve Digital
- Signature Algorithm (ECDSA) </url> </p>
- </item>
- <item>
- <p><url href="http://www.ietf.org/rfc/rfc2945.txt"> Secure Remote Password Protocol (SRP - RFC 2945) </url></p>
- </item>
- <item>
- <p>gcm: Dworkin, M., "Recommendation for Block Cipher Modes of
- Operation: Galois/Counter Mode (GCM) and GMAC",
- National Institute of Standards and Technology SP 800-
- 38D, November 2007.</p>
- </item>
- </list>
- </description>
-
- <section>
- <title>DATA TYPES </title>
+ <taglist>
+ <tag>Hash functions</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>SHA1, SHA2</tag>
+ <item>
+ <url href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">
+ Secure Hash Standard [FIPS PUB 180-4]
+ </url>
+ </item>
+ <tag>SHA3</tag>
+ <item>
+ <url href="https://www.nist.gov/publications/sha-3-standard-permutation-based-hash-and-extendable-output-functions?pub_id=919061">
+ SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions [FIPS PUB 202]
+ </url>
+ </item>
+ <tag>MD5</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc1321.txt">The MD5 Message Digest Algorithm [RFC 1321]</url>
+ </item>
+ <tag>MD4</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc1320.txt">The MD4 Message Digest Algorithm [RFC 1320]</url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>MACs - Message Authentication Codes</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>Hmac functions</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc2104.txt">
+ Keyed-Hashing for Message Authentication [RFC 2104]
+ </url>
+ </item>
+ <tag>Cmac functions</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc4493.txt">
+ The AES-CMAC Algorithm [RFC 4493]
+ </url>
+ </item>
+ <tag>POLY1305</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Symmetric Ciphers</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>DES, 3DES and AES</tag>
+ <item>
+ <url href="https://csrc.nist.gov/projects/block-cipher-techniques">Block Cipher Techniques [NIST]</url>
+ </item>
+ <tag>Blowfish</tag>
+ <item>
+ <url href="https://www.schneier.com/academic/archives/1994/09/description_of_a_new.html">
+ Fast Software Encryption, Cambridge Security Workshop Proceedings (December 1993), Springer-Verlag, 1994, pp. 191-204.
+ </url>
+ </item>
+ <tag>Chacha20</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ <tag>Chacha20_poly1305</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc7539.txt">
+ ChaCha20 and Poly1305 for IETF Protocols [RFC 7539]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Modes</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>ECB, CBC, CFB, OFB and CTR</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/sp/800-38a/final">
+ Recommendation for Block Cipher Modes of Operation: Methods and Techniques [NIST SP 800-38A]
+ </url>
+ </item>
+ <tag>GCM</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/sp/800-38d/final">
+ Recommendation for Block Cipher Modes of Operation: Galois/Counter Mode (GCM) and GMAC [NIST SP 800-38D]
+ </url>
+ </item>
+ <tag>CCM</tag>
+ <item>
+ <url href="https://nvlpubs.nist.gov/nistpubs/legacy/sp/nistspecialpublication800-38c.pdf">
+ Recommendation for Block Cipher Modes of Operation:
+ The CCM Mode for Authentication and Confidentiality [NIST SP 800-38C]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+
+ <tag>Asymetric Ciphers - Public Key Techniques</tag>
+ <item>
+ <p></p>
+ <taglist>
+ <tag>RSA</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc3447.txt">
+ PKCS #1: RSA Cryptography Specifications [RFC 3447]
+ </url>
+ </item>
+ <tag>DSS</tag>
+ <item>
+ <url href="https://csrc.nist.gov/publications/detail/fips/186/4/final">
+ Digital Signature Standard (DSS) [FIPS 186-4]
+ </url>
+ </item>
+ <tag>ECDSA</tag>
+ <item>
+ <url href="http://csrc.nist.gov/groups/STM/cavp/documents/dss2/ecdsa2vs.pdf">
+ Elliptic Curve Digital Signature Algorithm [ECDSA]
+ </url>
+ </item>
+ <tag>SRP</tag>
+ <item>
+ <url href="http://www.ietf.org/rfc/rfc2945.txt">
+ The SRP Authentication and Key Exchange System [RFC 2945]
+ </url>
+ </item>
+ </taglist>
+ <p></p>
+ </item>
+ </taglist>
+
+ <note>
+ <p>The actual supported algorithms and features depends on their availability in the actual libcrypto used.
+ See the <seealso marker="crypto:crypto_app">crypto (App)</seealso> about dependencies.
+ </p>
+ <p>Enabling FIPS mode will also disable algorithms and features.
+ </p>
+ </note>
- <code>key_value() = integer() | binary() </code>
- <p>Always <c>binary()</c> when used as return value</p>
+ <p>The <seealso marker="users_guide">CRYPTO User's Guide</seealso> has more information on
+ FIPS, Engines and Algorithm Details like key lengths.
+ </p>
+ </description>
- <code>rsa_public() = [key_value()] = [E, N] </code>
- <p> Where E is the public exponent and N is public modulus. </p>
+ <datatypes>
+ <datatype_title>Ciphers</datatype_title>
+ <datatype>
+ <name name="stream_cipher"/>
+ <desc>
+ <p>Stream ciphers for
+ <seealso marker="#stream_encrypt-2">stream_encrypt/2</seealso> and
+ <seealso marker="#stream_decrypt-2">stream_decrypt/2</seealso> .
+ </p>
+ </desc>
+ </datatype>
- <code>rsa_private() = [key_value()] = [E, N, D] | [E, N, D, P1, P2, E1, E2, C] </code>
- <p>Where E is the public exponent, N is public modulus and D is
- the private exponent. The longer key format contains redundant
- information that will make the calculation faster. P1,P2 are first
- and second prime factors. E1,E2 are first and second exponents. C
- is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+ <datatype>
+ <name name="block_cipher_with_iv"/>
+ <name name="cbc_cipher"/>
+ <name name="cfb_cipher"/>
+ <desc>
+ <p>Block ciphers with initialization vector for
+ <seealso marker="#block_encrypt-4">block_encrypt/4</seealso> and
+ <seealso marker="#block_decrypt-4">block_decrypt/4</seealso> .
+ </p>
+ </desc>
+ </datatype>
- <code>dss_public() = [key_value()] = [P, Q, G, Y] </code>
- <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
+ <datatype>
+ <name name="block_cipher_without_iv"/>
+ <name name="ecb_cipher"/>
+ <desc>
+ <p>Block ciphers without initialization vector for
+ <seealso marker="#block_encrypt-3">block_encrypt/3</seealso> and
+ <seealso marker="#block_decrypt-3">block_decrypt/3</seealso> .
+ </p>
+ </desc>
+ </datatype>
- <code>dss_private() = [key_value()] = [P, Q, G, X] </code>
- <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+ <datatype>
+ <name name="aead_cipher"/>
+ <desc>
+ <p>Ciphers with simultaneous MAC-calculation or MAC-checking.
+ <seealso marker="#block_encrypt-4">block_encrypt/4</seealso> and
+ <seealso marker="#block_decrypt-4">block_decrypt/4</seealso> .
+ </p>
+ </desc>
+ </datatype>
- <code>srp_public() = key_value() </code>
- <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ <datatype_title>Digests</datatype_title>
+ <datatype>
+ <name name="sha1"/>
+ <name name="sha2"/>
+ <name name="sha3"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>srp_private() = key_value() </code>
- <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ <datatype>
+ <name name="compatibility_only_hash"/>
+ <desc>
+ <p>The <c>compatibility_only_hash()</c> algorithms are recommended only for compatibility with existing applications.</p>
+ </desc>
+ </datatype>
- <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
- <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
- Version = '3' | '6' | '6a'
- </p>
+ <datatype>
+ <name name="rsa_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>dh_public() = key_value() </code>
+ <datatype>
+ <name name="dss_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>dh_private() = key_value() </code>
+ <datatype>
+ <name name="ecdsa_digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>dh_params() = [key_value()] = [P, G] | [P, G, PrivateKeyBitLength]</code>
+ <datatype_title>Elliptic Curves</datatype_title>
+ <datatype>
+ <name name="ec_named_curve"/>
+ <name name="edwards_curve"/>
+ <desc>
+ <p>Note that some curves are disabled if FIPS is enabled.</p>
+ </desc>
+ </datatype>
- <code>ecdh_public() = key_value() </code>
+ <datatype>
+ <name name="ec_explicit_curve"/>
+ <name name="ec_field"/>
+ <name name="ec_curve"/>
+ <desc>
+ <p>Parametric curve definition.</p>
+ </desc>
+ </datatype>
- <code>ecdh_private() = key_value() </code>
+ <datatype>
+ <name name="ec_prime_field"/>
+ <name name="ec_characteristic_two_field"/>
+ <name name="ec_basis"/>
+ <desc>
+ <p>Curve definition details.</p>
+ </desc>
+ </datatype>
- <code>ecdh_params() = ec_named_curve() | ec_explicit_curve()</code>
+ <datatype_title>Keys</datatype_title>
+ <datatype>
+ <name name="key"/>
+ <name name="des3_key"/>
+ <desc>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
+ <p>A key for des3 is a list of three iolists</p>
+ </desc>
+ </datatype>
- <code>ec_explicit_curve() =
- {ec_field(), Prime :: key_value(), Point :: key_value(), Order :: integer(),
- CoFactor :: none | integer()} </code>
+ <datatype>
+ <name name="key_integer"/>
+ <desc>
+ <p>Always <c>binary()</c> when used as return value</p>
+ </desc>
+ </datatype>
- <code>ec_field() = {prime_field, Prime :: integer()} |
- {characteristic_two_field, M :: integer(), Basis :: ec_basis()}</code>
+ <datatype_title>Public/Private Keys</datatype_title>
+ <datatype>
+ <name name="rsa_public"/>
+ <name name="rsa_private"/>
+ <name name="rsa_params"/>
+ <desc>
+ <code>rsa_public() = [E, N]</code>
+ <code>rsa_private() = [E, N, D] | [E, N, D, P1, P2, E1, E2, C]</code>
+ <p>Where E is the public exponent, N is public modulus and D is
+ the private exponent. The longer key format contains redundant
+ information that will make the calculation faster. P1,P2 are first
+ and second prime factors. E1,E2 are first and second exponents. C
+ is the CRT coefficient. Terminology is taken from <url href="http://www.ietf.org/rfc/rfc3477.txt"> RFC 3447</url>.</p>
+ </desc>
+ </datatype>
- <code>ec_basis() = {tpbasis, K :: non_neg_integer()} |
- {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} |
- onbasis</code>
+ <datatype>
+ <name name="dss_public"/>
+ <name name="dss_private"/>
+ <desc>
+ <code>dss_public() = [P, Q, G, Y] </code>
+ <p>Where P, Q and G are the dss parameters and Y is the public key.</p>
- <code>ec_named_curve() ->
- sect571r1| sect571k1| sect409r1| sect409k1| secp521r1| secp384r1| secp224r1| secp224k1|
- secp192k1| secp160r2| secp128r2| secp128r1| sect233r1| sect233k1| sect193r2| sect193r1|
- sect131r2| sect131r1| sect283r1| sect283k1| sect163r2| secp256k1| secp160k1| secp160r1|
- secp112r2| secp112r1| sect113r2| sect113r1| sect239k1| sect163r1| sect163k1| secp256r1|
- secp192r1|
- brainpoolP160r1| brainpoolP160t1| brainpoolP192r1| brainpoolP192t1| brainpoolP224r1|
- brainpoolP224t1| brainpoolP256r1| brainpoolP256t1| brainpoolP320r1| brainpoolP320t1|
- brainpoolP384r1| brainpoolP384t1| brainpoolP512r1| brainpoolP512t1
- </code>
- <p>Note that the <em>sect</em> curves are GF2m (characteristic two) curves and are only supported if the
- underlying OpenSSL has support for them.
- See also <seealso marker="#supports-0">crypto:supports/0</seealso>
- </p>
+ <code>dss_private() = [P, Q, G, X] </code>
+ <p>Where P, Q and G are the dss parameters and X is the private key.</p>
+ </desc>
+ </datatype>
- <marker id="type-engine_key_ref"/>
- <marker id="engine_key_ref_type"/>
- <code>engine_key_ref() = #{engine := engine_ref(),
- key_id := key_id(),
- password => password()}</code>
+ <datatype>
+ <name name="ecdsa_public"/>
+ <name name="ecdsa_private"/>
+ <name name="ecdsa_params"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>engine_ref() = term()</code>
- <p>The result of a call to <seealso marker="#engine_load-3">engine_load/3</seealso>.
- </p>
+ <datatype>
+ <name name="srp_public"/>
+ <name name="srp_private"/>
+ <desc>
+ <code>srp_public() = key_integer() </code>
+ <p>Where is <c>A</c> or <c>B</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+
+ <code>srp_private() = key_integer() </code>
+ <p>Where is <c>a</c> or <c>b</c> from <url href="http://srp.stanford.edu/design.html">SRP design</url></p>
+ </desc>
+ </datatype>
- <code>key_id() = string() | binary()</code>
- <p>Identifies the key to be used. The format depends on the loaded engine. It is passed to
- the <c>ENGINE_load_(private|public)_key</c> functions in libcrypto.
- </p>
+ <datatype>
+ <name name="srp_gen_params"/>
+ <name name="srp_comp_params"/>
+ <desc>
+ <marker id="type-srp_user_gen_params"/>
+ <code>srp_user_gen_params() = [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom()]</code>
+ <marker id="type-srp_host_gen_params"/>
+ <code>srp_host_gen_params() = [Verifier::binary(), Prime::binary(), Version::atom() ]</code>
+ <marker id="type-srp_user_comp_params"/>
+ <code>srp_user_comp_params() = [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | ScramblerArg::list()]</code>
+ <marker id="type-srp_host_comp_params"/>
+ <code>srp_host_comp_params() = [Verifier::binary(), Prime::binary(), Version::atom() | ScramblerArg::list()]</code>
+ <p>Where Verifier is <c>v</c>, Generator is <c>g</c> and Prime is<c> N</c>, DerivedKey is <c>X</c>, and Scrambler is
+ <c>u</c> (optional will be generated if not provided) from <url href="http://srp.stanford.edu/design.html">SRP design</url>
+ Version = '3' | '6' | '6a'
+ </p>
+ </desc>
+ </datatype>
- <code>password() = string() | binary()</code>
- <p>The key's password
- </p>
+ <datatype_title>Public Key Ciphers</datatype_title>
- <code>stream_cipher() = rc4 | aes_ctr </code>
+ <datatype>
+ <name name="pk_encrypt_decrypt_algs"/>
+ <desc>
+ <p>Algorithms for public key encrypt/decrypt. Only RSA is supported.</p>
+ </desc>
+ </datatype>
- <code>block_cipher() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ige256 | blowfish_cbc |
- blowfish_cfb64 | des_cbc | des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc </code>
+ <datatype>
+ <name name="pk_encrypt_decrypt_opts"/>
+ <name name="rsa_opt"/>
+ <name name="rsa_padding"/>
+ <desc>
+ <p>Options for public key encrypt/decrypt. Only RSA is supported.</p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ </desc>
+ </datatype>
- <code>aead_cipher() = aes_gcm | chacha20_poly1305 </code>
+ <datatype>
+ <name name="rsa_compat_opts"/>
+ <desc>
+ <p>Those option forms are kept only for compatibility and should not be used in new code.</p>
+ </desc>
+ </datatype>
- <code>stream_key() = aes_key() | rc4_key() </code>
+ <datatype_title>Public Key Sign and Verify</datatype_title>
- <code>block_key() = aes_key() | blowfish_key() | des_key()| des3_key() </code>
+ <datatype>
+ <name name="pk_sign_verify_algs"/>
+ <desc>
+ <p>Algorithms for sign and verify.</p>
+ </desc>
+ </datatype>
- <code>aes_key() = iodata() </code> <p>Key length is 128, 192 or 256 bits</p>
+ <datatype>
+ <name name="pk_sign_verify_opts"/>
+ <name name="rsa_sign_verify_opt"/>
+ <name name="rsa_sign_verify_padding"/>
+ <desc>
+ <p>Options for sign and verify.</p>
+ <warning>
+ <!-- In RefMan rsa_opt(), rsa_sign_verify_opt() and User's man RSA -->
+ <p>The RSA options are experimental.
+ </p>
+ <p>The exact set of options and there syntax <em>may</em> be changed
+ without prior notice.</p>
+ </warning>
+ </desc>
+ </datatype>
- <code>rc4_key() = iodata() </code> <p>Variable key length from 8 bits up to 2048 bits (usually between 40 and 256)</p>
+ <datatype_title>Diffie-Hellman Keys and parameters</datatype_title>
+ <datatype>
+ <name name="dh_public"/>
+ <name name="dh_private"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>blowfish_key() = iodata() </code> <p>Variable key length from 32 bits up to 448 bits</p>
+ <datatype>
+ <name name="dh_params"/>
+ <desc>
+ <code>dh_params() = [P, G] | [P, G, PrivateKeyBitLength]</code>
+ </desc>
+ </datatype>
- <code>des_key() = iodata() </code> <p>Key length is 64 bits (in CBC mode only 8 bits are used)</p>
+ <datatype>
+ <name name="ecdh_public"/>
+ <name name="ecdh_private"/>
+ <name name="ecdh_params"/>
+ <desc>
+ </desc>
+ </datatype>
- <code>des3_key() = [binary(), binary(), binary()] </code> <p>Each key part is 64 bits (in CBC mode only 8 bits are used)</p>
+ <datatype_title>Types for Engines</datatype_title>
- <code>digest_type() = md5 | sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype>
+ <name name="engine_key_ref"/>
+ <name name="engine_ref"/>
+ <desc>
+ <p>The result of a call to <seealso marker="#engine_load-3">engine_load/3</seealso>.
+ </p>
+ </desc>
+ </datatype>
- <code>rsa_digest_type() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype>
+ <name name="key_id"/>
+ <desc>
+ <p>Identifies the key to be used. The format depends on the loaded engine. It is passed to
+ the <c>ENGINE_load_(private|public)_key</c> functions in libcrypto.
+ </p>
+ </desc>
+ </datatype>
- <code>dss_digest_type() = sha | sha224 | sha256 | sha384 | sha512</code> <p>Note that the actual supported
- dss_digest_type depends on the underlying crypto library. In OpenSSL version >= 1.0.1 the listed digest are supported, while in 1.0.0 only sha, sha224 and sha256 are supported. In version 0.9.8 only sha is supported.</p>
+ <datatype>
+ <name name="password"/>
+ <desc>
+ <p>The password of the key stored in an engine.
+ </p>
+ </desc>
+ </datatype>
- <code>ecdsa_digest_type() = sha | sha224 | sha256 | sha384 | sha512</code>
+ <datatype>
+ <name name="engine_method_type"/>
+ </datatype>
- <code>sign_options() = [{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}]</code>
+ <datatype>
+ <name name="engine_cmnd"/>
+ <desc>
+ <p>Pre and Post commands for <seealso marker="#engine_load-3">engine_load/3 and /4</seealso>.
+ </p>
+ </desc>
+ </datatype>
- <code>rsa_sign_padding() = rsa_pkcs1_padding | rsa_pkcs1_pss_padding</code>
+ <datatype_title>Internal data types</datatype_title>
- <code> hash_algorithms() = md5 | ripemd160 | sha | sha224 | sha256 | sha384 | sha512 </code> <p>md4 is also supported for hash_init/1 and hash/2.
- Note that both md4 and md5 are recommended only for compatibility with existing applications.
- </p>
- <code> cipher_algorithms() = aes_cbc | aes_cfb8 | aes_cfb128 | aes_ctr | aes_gcm |
- aes_ige256 | blowfish_cbc | blowfish_cfb64 | chacha20_poly1305 | des_cbc |
- des_cfb | des3_cbc | des3_cfb | des_ede3 | rc2_cbc | rc4 </code>
- <code> mac_algorithms() = hmac | cmac</code>
- <code> public_key_algorithms() = rsa |dss | ecdsa | dh | ecdh | ec_gf2m</code>
- <p>Note that ec_gf2m is not strictly a public key algorithm, but a restriction on what curves are supported
- with ecdsa and ecdh.
- </p>
- <code>engine_method_type() = engine_method_rsa | engine_method_dsa | engine_method_dh |
- engine_method_rand | engine_method_ecdh | engine_method_ecdsa |
- engine_method_ciphers | engine_method_digests | engine_method_store |
- engine_method_pkey_meths | engine_method_pkey_asn1_meths</code>
+ <datatype>
+ <name name="stream_state"/>
+ <name name="hmac_state"/>
+ <name name="hash_state"/>
+ <desc>
+ <p>Contexts with an internal state that should not be manipulated but passed between function calls.
+ </p>
+ </desc>
+ </datatype>
- </section>
+ </datatypes>
+ <!--================ FUNCTIONS ================-->
<funcs>
<func>
- <name>block_encrypt(Type, Key, PlainText) -> CipherText</name>
+ <name name="block_encrypt" arity="3"/>
<fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = des_ecb | blowfish_ecb | aes_ecb </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- </type>
<desc>
- <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
<func>
- <name>block_decrypt(Type, Key, CipherText) -> PlainText</name>
+ <name name="block_decrypt" arity="3"/>
<fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
- <type>
- <v>Type = des_ecb | blowfish_ecb | aes_ecb </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
- </type>
<desc>
<p>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
<func>
<name>block_encrypt(Type, Key, Ivec, PlainText) -> CipherText</name>
<name>block_encrypt(AeadType, Key, Ivec, {AAD, PlainText}) -> {CipherText, CipherTag}</name>
- <name>block_encrypt(aes_gcm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name>
+ <name>block_encrypt(aes_gcm | aes_ccm, Key, Ivec, {AAD, PlainText, TagLength}) -> {CipherText, CipherTag}</name>
<fsummary>Encrypt <c>PlainText</c> according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Type = block_cipher() </v>
- <v>AeadType = aead_cipher() </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
<v>AAD = IVec = CipherText = CipherTag = binary()</v>
<v>TagLength = 1..16</v>
</type>
@@ -257,8 +558,11 @@
<p>In AEAD (Authenticated Encryption with Associated Data) mode, encrypt
<c>PlainText</c>according to <c>Type</c> block cipher and calculate
<c>CipherTag</c> that also authenticates the <c>AAD</c> (Associated Authenticated Data).</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
@@ -267,10 +571,10 @@
<name>block_decrypt(AeadType, Key, Ivec, {AAD, CipherText, CipherTag}) -> PlainText | error</name>
<fsummary>Decrypt <c>CipherText</c> according to <c>Type</c> block cipher</fsummary>
<type>
- <v>Type = block_cipher() </v>
- <v>AeadType = aead_cipher() </v>
- <v>Key = block_key() </v>
- <v>PlainText = iodata() </v>
+ <v>Type = <seealso marker="#type-block_cipher_with_iv">block_cipher_with_iv()</seealso></v>
+ <v>AeadType = <seealso marker="#type-aead_cipher">aead_cipher()</seealso></v>
+ <v>Key = <seealso marker="#type-key">key()</seealso> | <seealso marker="#type-des3_key">des3_key()</seealso></v>
+ <v>PlainText = iodata()</v>
<v>AAD = IVec = CipherText = CipherTag = binary()</v>
</type>
<desc>
@@ -280,19 +584,17 @@
<c>CipherText</c>according to <c>Type</c> block cipher and check the authenticity
the <c>PlainText</c> and <c>AAD</c> (Associated Authenticated Data) using the
<c>CipherTag</c>. May return <c>error</c> if the decryption or validation fail's</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
+ <p>For keylengths, iv-sizes and blocksizes see the
+ <seealso marker="crypto:algorithm_details#ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
<func>
- <name>bytes_to_integer(Bin) -> Integer </name>
+ <name name="bytes_to_integer" arity="1"/>
<fsummary>Convert binary representation, of an integer, to an Erlang integer.</fsummary>
- <type>
- <v>Bin = binary() - as returned by crypto functions</v>
-
- <v>Integer = integer() </v>
- </type>
<desc>
<p>Convert binary representation, of an integer, to an Erlang integer.
</p>
@@ -300,17 +602,8 @@
</func>
<func>
- <name>compute_key(Type, OthersPublicKey, MyKey, Params) -> SharedSecret</name>
+ <name name="compute_key" arity="4"/>
<fsummary>Computes the shared secret</fsummary>
- <type>
- <v> Type = dh | ecdh | srp </v>
- <v>OthersPublicKey = dh_public() | ecdh_public() | srp_public() </v>
- <v>MyKey = dh_private() | ecdh_private() | {srp_public(),srp_private()}</v>
- <v>Params = dh_params() | ecdh_params() | SrpUserParams | SrpHostParams</v>
- <v>SrpUserParams = {user, [DerivedKey::binary(), Prime::binary(), Generator::binary(), Version::atom() | [Scrambler:binary()]]} </v>
- <v>SrpHostParams = {host, [Verifier::binary(), Prime::binary(), Version::atom() | [Scrambler::binary]]} </v>
- <v>SharedSecret = binary()</v>
- </type>
<desc>
<p>Computes the shared secret from the private key and the other party's public key.
See also <seealso marker="public_key:public_key#compute_key-2">public_key:compute_key/2</seealso>
@@ -319,85 +612,61 @@
</func>
<func>
- <name>exor(Data1, Data2) -> Result</name>
+ <name name="exor" arity="2"/>
<fsummary>XOR data</fsummary>
- <type>
- <v>Data1, Data2 = iodata()</v>
- <v>Result = binary()</v>
- </type>
<desc>
<p>Performs bit-wise XOR (exclusive or) on the data supplied.</p>
</desc>
</func>
- <func>
- <name>generate_key(Type, Params) -> {PublicKey, PrivKeyOut} </name>
- <name>generate_key(Type, Params, PrivKeyIn) -> {PublicKey, PrivKeyOut} </name>
+
+ <func>
+ <name name="generate_key" arity="2"/>
+ <name name="generate_key" arity="3"/>
<fsummary>Generates a public key of type <c>Type</c></fsummary>
- <type>
- <v> Type = dh | ecdh | rsa | srp </v>
- <v>Params = dh_params() | ecdh_params() | RsaParams | SrpUserParams | SrpHostParams </v>
- <v>RsaParams = {ModulusSizeInBits::integer(), PublicExponent::key_value()}</v>
- <v>SrpUserParams = {user, [Generator::binary(), Prime::binary(), Version::atom()]}</v>
- <v>SrpHostParams = {host, [Verifier::binary(), Generator::binary(), Prime::binary(), Version::atom()]}</v>
- <v>PublicKey = dh_public() | ecdh_public() | rsa_public() | srp_public() </v>
- <v>PrivKeyIn = undefined | dh_private() | ecdh_private() | srp_private() </v>
- <v>PrivKeyOut = dh_private() | ecdh_private() | rsa_private() | srp_private() </v>
- </type>
<desc>
<p>Generates a public key of type <c>Type</c>.
See also <seealso marker="public_key:public_key#generate_key-1">public_key:generate_key/1</seealso>.
- May throw exception an exception of class <c>error</c>:
+ May raise exception:
</p>
<list type="bulleted">
- <item><c>badarg</c>: an argument is of wrong type or has an illegal value,</item>
- <item><c>low_entropy</c>: the random generator failed due to lack of secure "randomness",</item>
- <item><c>computation_failed</c>: the computation fails of another reason than <c>low_entropy</c>.</item>
+ <item><c>error:badarg</c>: an argument is of wrong type or has an illegal value,</item>
+ <item><c>error:low_entropy</c>: the random generator failed due to lack of secure "randomness",</item>
+ <item><c>error:computation_failed</c>: the computation fails of another reason than <c>low_entropy</c>.</item>
</list>
<note>
<p>RSA key generation is only available if the runtime was
built with dirty scheduler support. Otherwise, attempting to
- generate an RSA key will throw exception <c>error:notsup</c>.</p>
+ generate an RSA key will raise exception <c>error:notsup</c>.</p>
</note>
</desc>
</func>
<func>
- <name>hash(Type, Data) -> Digest</name>
+ <name name="hash" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Type = md4 | hash_algorithms()</v>
- <v>Data = iodata()</v>
- <v>Digest = binary()</v>
- </type>
<desc>
<p>Computes a message digest of type <c>Type</c> from <c>Data</c>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
</desc>
</func>
<func>
- <name>hash_init(Type) -> Context</name>
+ <name name="hash_init" arity="1"/>
<fsummary></fsummary>
- <type>
- <v>Type = md4 | hash_algorithms()</v>
- </type>
<desc>
<p>Initializes the context for streaming hash operations. <c>Type</c> determines
which digest to use. The returned context should be used as argument
to <seealso marker="#hash_update-2">hash_update</seealso>.</p>
- <p>May throw exception <c>notsup</c> in case the chosen <c>Type</c>
- is not supported by the underlying OpenSSL implementation.</p>
+ <p>May raise exception <c>error:notsup</c> in case the chosen <c>Type</c>
+ is not supported by the underlying libcrypto implementation.</p>
</desc>
</func>
<func>
- <name>hash_update(Context, Data) -> NewContext</name>
+ <name name="hash_update" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Data = iodata()</v>
- </type>
<desc>
<p>Updates the digest represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using <seealso marker="#hash_init-1">hash_init</seealso>
@@ -406,12 +675,10 @@
or <seealso marker="#hash_final-1">hash_final</seealso>.</p>
</desc>
</func>
+
<func>
- <name>hash_final(Context) -> Digest</name>
+ <name name="hash_final" arity="1"/>
<fsummary></fsummary>
- <type>
- <v>Digest = binary()</v>
- </type>
<desc>
<p>Finalizes the hash operation referenced by <c>Context</c> returned
from a previous call to <seealso marker="#hash_update-2">hash_update</seealso>.
@@ -421,16 +688,9 @@
</func>
<func>
- <name>hmac(Type, Key, Data) -> Mac</name>
- <name>hmac(Type, Key, Data, MacLength) -> Mac</name>
+ <name name="hmac" arity="3"/>
+ <name name="hmac" arity="4"/>
<fsummary></fsummary>
- <type>
- <v>Type = hash_algorithms() - except ripemd160</v>
- <v>Key = iodata()</v>
- <v>Data = iodata()</v>
- <v>MacLength = integer()</v>
- <v>Mac = binary()</v>
- </type>
<desc>
<p>Computes a HMAC of type <c>Type</c> from <c>Data</c> using
<c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
@@ -439,13 +699,8 @@
</func>
<func>
- <name>hmac_init(Type, Key) -> Context</name>
+ <name name="hmac_init" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Type = hash_algorithms() - except ripemd160</v>
- <v>Key = iodata()</v>
- <v>Context = binary()</v>
- </type>
<desc>
<p>Initializes the context for streaming HMAC operations. <c>Type</c> determines
which hash function to use in the HMAC operation. <c>Key</c> is the authentication
@@ -454,12 +709,8 @@
</func>
<func>
- <name>hmac_update(Context, Data) -> NewContext</name>
+ <name name="hmac_update" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Context = NewContext = binary()</v>
- <v>Data = iodata()</v>
- </type>
<desc>
<p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c>
must have been generated using an HMAC init function (such as
@@ -472,16 +723,13 @@
call to hmac_update or hmac_final. The semantics of reusing old contexts
in any way is undefined and could even crash the VM in earlier releases.
The reason for this limitation is a lack of support in the underlying
- OpenSSL API.</p></warning>
+ libcrypto API.</p></warning>
</desc>
</func>
<func>
- <name>hmac_final(Context) -> Mac</name>
+ <name name="hmac_final" arity="1"/>
<fsummary></fsummary>
- <type>
- <v>Context = Mac = binary()</v>
- </type>
<desc>
<p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is
determined by the type of hash function used to generate it.</p>
@@ -489,12 +737,8 @@
</func>
<func>
- <name>hmac_final_n(Context, HashLen) -> Mac</name>
+ <name name="hmac_final_n" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Context = Mac = binary()</v>
- <v>HashLen = non_neg_integer()</v>
- </type>
<desc>
<p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than
zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p>
@@ -502,16 +746,9 @@
</func>
<func>
- <name>cmac(Type, Key, Data) -> Mac</name>
- <name>cmac(Type, Key, Data, MacLength) -> Mac</name>
+ <name name="cmac" arity="3"/>
+ <name name="cmac" arity="4"/>
<fsummary>Calculates the Cipher-based Message Authentication Code.</fsummary>
- <type>
- <v>Type = block_cipher()</v>
- <v>Key = iodata()</v>
- <v>Data = iodata()</v>
- <v>MacLength = integer()</v>
- <v>Mac = binary()</v>
- </type>
<desc>
<p>Computes a CMAC of type <c>Type</c> from <c>Data</c> using
<c>Key</c> as the authentication key.</p> <p><c>MacLength</c>
@@ -520,20 +757,21 @@
</func>
<func>
- <name>info_fips() -> Status</name>
+ <name name="info_fips" arity="0"/>
<fsummary>Provides information about the FIPS operating status.</fsummary>
- <type>
- <v>Status = enabled | not_enabled | not_supported</v>
- </type>
<desc>
<p>Provides information about the FIPS operating status of
- crypto and the underlying OpenSSL library. If crypto was built
+ crypto and the underlying libcrypto library. If crypto was built
with FIPS support this can be either <c>enabled</c> (when
running in FIPS mode) or <c>not_enabled</c>. For other builds
- this value is always <c>not_supported</c>.</p>
+ this value is always <c>not_supported</c>.
+ </p>
+ <p>See <seealso marker="#enable_fips_mode-1">enable_fips_mode/1</seealso> about how to enable
+ FIPS mode.
+ </p>
<warning>
<p>In FIPS mode all non-FIPS compliant algorithms are
- disabled and throw exception <c>not_supported</c>. Check
+ disabled and raise exception <c>error:notsup</c>. Check
<seealso marker="#supports-0">supports</seealso> that in
FIPS mode returns the restricted list of available
algorithms.</p>
@@ -542,13 +780,23 @@
</func>
<func>
- <name>info_lib() -> [{Name,VerNum,VerStr}]</name>
+ <name name="enable_fips_mode" arity="1"/>
+ <fsummary>Change FIPS mode.</fsummary>
+ <desc>
+ <p>Enables (<c>Enable = true</c>) or disables (<c>Enable = false</c>) FIPS mode. Returns <c>true</c> if
+ the operation was successful or <c>false</c> otherwise.
+ </p>
+ <p>Note that to enable FIPS mode succesfully, OTP must be built with the configure option <c>--enable-fips</c>,
+ and the underlying libcrypto must also support FIPS.
+ </p>
+ <p>See also <seealso marker="#info_fips-0">info_fips/0</seealso>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="info_lib" arity="0"/>
<fsummary>Provides information about the libraries used by crypto.</fsummary>
- <type>
- <v>Name = binary()</v>
- <v>VerNum = integer()</v>
- <v>VerStr = binary()</v>
- </type>
<desc>
<p>Provides the name and version of the libraries used by crypto.</p>
<p><c>Name</c> is the name of the library. <c>VerNum</c> is
@@ -561,52 +809,45 @@
<note><p>
From OTP R16 the <em>numeric version</em> represents the version of the OpenSSL
<em>header files</em> (<c>openssl/opensslv.h</c>) used when crypto was compiled.
- The text variant represents the OpenSSL library used at runtime.
+ The text variant represents the libcrypto library used at runtime.
In earlier OTP versions both numeric and text was taken from the library.
</p></note>
</desc>
</func>
<func>
- <name>mod_pow(N, P, M) -> Result</name>
+ <name name="mod_pow" arity="3"/>
<fsummary>Computes the function: N^P mod M</fsummary>
- <type>
- <v>N, P, M = binary() | integer()</v>
- <v>Result = binary() | error</v>
- </type>
<desc>
<p>Computes the function <c>N^P mod M</c>.</p>
</desc>
</func>
<func>
- <name>next_iv(Type, Data) -> NextIVec</name>
- <name>next_iv(Type, Data, IVec) -> NextIVec</name>
- <fsummary></fsummary>
- <type>
- <v>Type = des_cbc | des3_cbc | aes_cbc | des_cfb</v>
- <v>Data = iodata()</v>
- <v>IVec = NextIVec = binary()</v>
- </type>
- <desc>
- <p>Returns the initialization vector to be used in the next
- iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
- encrypted data from the previous iteration step. The <c>IVec</c>
- argument is only needed for <c>des_cfb</c> as the vector used
- in the previous iteration step.</p>
- </desc>
+ <name name="next_iv" arity="2"/>
+ <name name="next_iv" arity="3"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Returns the initialization vector to be used in the next
+ iteration of encrypt/decrypt of type <c>Type</c>. <c>Data</c> is the
+ encrypted data from the previous iteration step. The <c>IVec</c>
+ argument is only needed for <c>des_cfb</c> as the vector used
+ in the previous iteration step.</p>
+ </desc>
</func>
<func>
- <name>private_decrypt(Type, CipherText, PrivateKey, Padding) -> PlainText</name>
+ <name name="poly1305" arity="2"/>
+ <fsummary></fsummary>
+ <desc>
+ <p>Computes a POLY1305 message authentication code (<c>Mac</c>) from <c>Data</c> using
+ <c>Key</c> as the authentication key.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="private_decrypt" arity="4"/>
<fsummary>Decrypts CipherText using the private Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>CipherText = binary()</v>
- <v>PrivateKey = rsa_private() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
- </type>
<desc>
<p>Decrypts the <c>CipherText</c>, encrypted with
<seealso marker="#public_encrypt-4">public_encrypt/4</seealso> (or equivalent function)
@@ -619,34 +860,8 @@
</func>
<func>
- <name>privkey_to_pubkey(Type, EnginePrivateKeyRef) -> PublicKey</name>
- <fsummary>Fetches a public key from an Engine stored private key.</fsummary>
- <type>
- <v>Type = rsa | dss</v>
- <v>EnginePrivateKeyRef = engine_key_ref()</v>
- <v>PublicKey = rsa_public() | dss_public()</v>
- </type>
- <desc>
- <p>Fetches the corresponding public key from a private key stored in an Engine.
- The key must be of the type indicated by the Type parameter.
- </p>
- </desc>
- </func>
-
- <func>
- <name>private_encrypt(Type, PlainText, PrivateKey, Padding) -> CipherText</name>
+ <name name="private_encrypt" arity="4"/>
<fsummary>Encrypts PlainText using the private Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>PlainText = binary()</v>
- <d> The size of the <c>PlainText</c> must be less
- than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
- used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
- used, where N is public modulus of the RSA key.</d>
- <v>PrivateKey = rsa_private() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>CipherText = binary()</v>
- </type>
<desc>
<p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
and returns the ciphertext. This is a low level signature operation
@@ -656,16 +871,10 @@
</p>
</desc>
</func>
+
<func>
- <name>public_decrypt(Type, CipherText, PublicKey, Padding) -> PlainText</name>
+ <name name="public_decrypt" arity="4"/>
<fsummary>Decrypts CipherText using the public Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>CipherText = binary()</v>
- <v>PublicKey = rsa_public() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_no_padding</v>
- <v>PlainText = binary()</v>
- </type>
<desc>
<p>Decrypts the <c>CipherText</c>, encrypted with
<seealso marker="#private_encrypt-4">private_encrypt/4</seealso>(or equivalent function)
@@ -678,19 +887,8 @@
</func>
<func>
- <name>public_encrypt(Type, PlainText, PublicKey, Padding) -> CipherText</name>
+ <name name="public_encrypt" arity="4"/>
<fsummary>Encrypts PlainText using the public Key.</fsummary>
- <type>
- <v>Type = rsa</v>
- <v>PlainText = binary()</v>
- <d> The size of the <c>PlainText</c> must be less
- than <c>byte_size(N)-11</c> if <c>rsa_pkcs1_padding</c> is
- used, and <c>byte_size(N)</c> if <c>rsa_no_padding</c> is
- used, where N is public modulus of the RSA key.</d>
- <v>PublicKey = rsa_public() | engine_key_ref()</v>
- <v>Padding = rsa_pkcs1_padding | rsa_pkcs1_oaep_padding | rsa_no_padding</v>
- <v>CipherText = binary()</v>
- </type>
<desc>
<p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c>
and returns the <c>CipherText</c>. This is a low level signature operation
@@ -701,18 +899,15 @@
</func>
<func>
- <name>rand_seed(Seed) -> ok</name>
+ <name name="rand_seed" arity="1"/>
<fsummary>Set the seed for random bytes generation</fsummary>
- <type>
- <v>Seed = binary()</v>
- </type>
<desc>
<p>Set the seed for PRNG to the given binary. This calls the
RAND_seed function from openssl. Only use this if the system
you are running on does not have enough "randomness" built in.
Normally this is when
<seealso marker="#strong_rand_bytes/1">strong_rand_bytes/1</seealso>
- throws <c>low_entropy</c></p>
+ raises <c>error:low_entropy</c></p>
</desc>
</func>
@@ -730,36 +925,15 @@
</func>
<func>
- <name>sign(Algorithm, DigestType, Msg, Key) -> binary()</name>
- <name>sign(Algorithm, DigestType, Msg, Key, Options) -> binary()</name>
- <fsummary> Create digital signature.</fsummary>
- <type>
- <v>Algorithm = rsa | dss | ecdsa </v>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "cleartext" data to be
- signed or it is the hashed value of "cleartext" i.e. the
- digest (plaintext).</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Key = rsa_private() | dss_private() | [ecdh_private(),ecdh_params()] | engine_key_ref()</v>
- <v>Options = sign_options()</v>
- </type>
- <desc>
- <p>Creates a digital signature.</p>
- <p>Algorithm <c>dss</c> can only be used together with digest type
- <c>sha</c>.</p>
- <p>See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>.</p>
- </desc>
- </func>
-
- <func>
- <name>start() -> ok</name>
+ <name name="start" arity="0"/>
<fsummary> Equivalent to application:start(crypto). </fsummary>
<desc>
<p> Equivalent to application:start(crypto).</p>
</desc>
</func>
+
<func>
- <name>stop() -> ok</name>
+ <name name="stop" arity="0"/>
<fsummary> Equivalent to application:stop(crypto).</fsummary>
<desc>
<p> Equivalent to application:stop(crypto).</p>
@@ -767,23 +941,20 @@
</func>
<func>
- <name>strong_rand_bytes(N) -> binary()</name>
+ <name name="strong_rand_bytes" arity="1"/>
<fsummary>Generate a binary of random bytes</fsummary>
- <type>
- <v>N = integer()</v>
- </type>
<desc>
<p>Generates N bytes randomly uniform 0..255, and returns the
result in a binary. Uses a cryptographically secure prng seeded and
periodically mixed with operating system provided entropy. By default
this is the <c>RAND_bytes</c> method from OpenSSL.</p>
- <p>May throw exception <c>low_entropy</c> in case the random generator
+ <p>May raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".</p>
</desc>
</func>
<func>
- <name>rand_seed() -> rand:state()</name>
+ <name name="rand_seed" arity="0"/>
<fsummary>Strong random number generation plugin state</fsummary>
<desc>
<p>
@@ -799,7 +970,7 @@
<p>
When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
- may throw exception <c>low_entropy</c> in case the random generator
+ may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
</p>
<p><em>Example</em></p>
@@ -811,7 +982,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>rand_seed_s() -> rand:state()</name>
+ <name name="rand_seed_s" arity="0"/>
<fsummary>Strong random number generation plugin state</fsummary>
<desc>
<p>
@@ -825,12 +996,12 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<p>
When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
- may throw exception <c>low_entropy</c> in case the random generator
+ may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
</p>
<note>
<p>
- The state returned from this function can not be used
+ The state returned from this function cannot be used
to get a reproducable random sequence as from
the other
<seealso marker="stdlib:rand">rand</seealso>
@@ -856,7 +1027,8 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<p>
Creates state object for
<seealso marker="stdlib:rand">random number generation</seealso>,
- in order to generate cryptographically strong random numbers.
+ in order to generate cryptographically strong random numbers,
+ and saves it in the process dictionary before returning it as well.
See also
<seealso marker="stdlib:rand#seed-1">rand:seed/1</seealso> and
<seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>.
@@ -864,15 +1036,9 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<p>
When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
- may throw exception <c>low_entropy</c> in case the random generator
+ may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
</p>
- <p>
- The cache size can be changed from its default value using the
- <seealso marker="crypto_app">
- crypto app's
- </seealso> configuration parameter <c>rand_cache_size</c>.
- </p>
<p><em>Example</em></p>
<pre>
_ = crypto:rand_seed_alg(crypto_cache),
@@ -882,6 +1048,34 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
+ <name>rand_seed_alg(Alg, Seed) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
+ <type>
+ <v>Alg = crypto_aes</v>
+ </type>
+ <desc>
+ <marker id="rand_seed_alg-2" />
+ <p>
+ Creates a state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically unpredictable random numbers,
+ and saves it in the process dictionary before returning it as well.
+ See also
+ <seealso marker="#rand_seed_alg_s-2">rand_seed_alg_s/2</seealso>.
+ </p>
+ <p><em>Example</em></p>
+ <pre>
+_ = crypto:rand_seed_alg(crypto_aes, "my seed"),
+IntegerValue = rand:uniform(42), % [1; 42]
+FloatValue = rand:uniform(), % [0.0; 1.0[
+_ = crypto:rand_seed_alg(crypto_aes, "my seed"),
+IntegerValue = rand:uniform(42), % Same values
+FloatValue = rand:uniform(). % again
+ </pre>
+ </desc>
+ </func>
+
+ <func>
<name>rand_seed_alg_s(Alg) -> rand:state()</name>
<fsummary>Strong random number generation plugin state</fsummary>
<type>
@@ -909,7 +1103,7 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<p>
When using the state object from this function the
<seealso marker="stdlib:rand">rand</seealso> functions using it
- may throw exception <c>low_entropy</c> in case the random generator
+ may raise exception <c>error:low_entropy</c> in case the random generator
failed due to lack of secure "randomness".
</p>
<p>
@@ -918,9 +1112,15 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
crypto app's
</seealso> configuration parameter <c>rand_cache_size</c>.
</p>
+ <p>
+ When using the state object from this function the
+ <seealso marker="stdlib:rand">rand</seealso> functions using it
+ may throw exception <c>low_entropy</c> in case the random generator
+ failed due to lack of secure "randomness".
+ </p>
<note>
<p>
- The state returned from this function can not be used
+ The state returned from this function cannot be used
to get a reproducable random sequence as from
the other
<seealso marker="stdlib:rand">rand</seealso>
@@ -940,45 +1140,102 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>stream_init(Type, Key) -> State</name>
- <fsummary></fsummary>
+ <name>rand_seed_alg_s(Alg, Seed) -> rand:state()</name>
+ <fsummary>Strong random number generation plugin state</fsummary>
<type>
- <v>Type = rc4 </v>
- <v>State = opaque() </v>
- <v>Key = iodata()</v>
+ <v>Alg = crypto_aes</v>
</type>
<desc>
+ <marker id="rand_seed_alg_s-2" />
+ <p>
+ Creates a state object for
+ <seealso marker="stdlib:rand">random number generation</seealso>,
+ in order to generate cryptographically unpredictable random numbers.
+ See also
+ <seealso marker="#rand_seed_alg-1">rand_seed_alg/1</seealso>.
+ </p>
+ <p>
+ To get a long period the Xoroshiro928 generator from the
+ <seealso marker="stdlib:rand">rand</seealso>
+ module is used as a counter (with period 2^928 - 1)
+ and the generator states are scrambled through AES
+ to create 58-bit pseudo random values.
+ </p>
+ <p>
+ The result should be statistically completely unpredictable
+ random values, since the scrambling is cryptographically strong
+ and the period is ridiculously long. But the generated numbers
+ are not to be regarded as cryptographically strong since
+ there is no re-keying schedule.
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>
+ If you need cryptographically strong random numbers use
+ <seealso marker="#rand_seed_alg_s-1">rand_seed_alg_s/1</seealso>
+ with <c>Alg =:= crypto</c> or <c>Alg =:= crypto_cache</c>.
+ </p>
+ </item>
+ <item>
+ <p>
+ If you need to be able to repeat the sequence use this function.
+ </p>
+ </item>
+ <item>
+ <p>
+ If you do not need the statistical quality of this function,
+ there are faster algorithms in the
+ <seealso marker="stdlib:rand">rand</seealso>
+ module.
+ </p>
+ </item>
+ </list>
+ <p>
+ Thanks to the used generator the state object supports the
+ <seealso marker="stdlib:rand#jump-0"><c>rand:jump/0,1</c></seealso>
+ function with distance 2^512.
+ </p>
+ <p>
+ Numbers are generated in batches and cached for speed reasons.
+ The cache size can be changed from its default value using the
+ <seealso marker="crypto_app">
+ crypto app's
+ </seealso> configuration parameter <c>rand_cache_size</c>.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="stream_init" arity="2"/>
+ <fsummary></fsummary>
+ <desc>
<p>Initializes the state for use in RC4 stream encryption
<seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
<seealso marker="#stream_decrypt-2">stream_decrypt</seealso></p>
+ <p>For keylengths see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
<func>
- <name>stream_init(Type, Key, IVec) -> State</name>
+ <name name="stream_init" arity="3"/>
<fsummary></fsummary>
- <type>
- <v>Type = aes_ctr </v>
- <v>State = opaque() </v>
- <v>Key = iodata()</v>
- <v>IVec = binary()</v>
- </type>
<desc>
<p>Initializes the state for use in streaming AES encryption using Counter mode (CTR).
<c>Key</c> is the AES key and must be either 128, 192, or 256 bits long. <c>IVec</c> is
an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with
<seealso marker="#stream_encrypt-2">stream_encrypt</seealso> and
<seealso marker="#stream_decrypt-2">stream_decrypt</seealso>.</p>
+ <p>For keylengths and iv-sizes see the
+ <seealso marker="crypto:algorithm_details#stream-ciphers">User's Guide</seealso>.
+ </p>
</desc>
</func>
<func>
- <name>stream_encrypt(State, PlainText) -> { NewState, CipherText}</name>
+ <name name="stream_encrypt" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>Text = iodata()</v>
- <v>CipherText = binary()</v>
- </type>
<desc>
<p>Encrypts <c>PlainText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
<c>Text</c> can be any number of bytes. The initial <c>State</c> is created using
@@ -988,12 +1245,8 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>stream_decrypt(State, CipherText) -> { NewState, PlainText }</name>
+ <name name="stream_decrypt" arity="2"/>
<fsummary></fsummary>
- <type>
- <v>CipherText = iodata()</v>
- <v>PlainText = binary()</v>
- </type>
<desc>
<p>Decrypts <c>CipherText</c> according to the stream cipher <c>Type</c> specified in stream_init/3.
<c>PlainText</c> can be any number of bytes. The initial <c>State</c> is created using
@@ -1003,60 +1256,57 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>supports() -> AlgorithmList </name>
+ <name name="supports" arity="0"/>
<fsummary>Provide a list of available crypto algorithms.</fsummary>
- <type>
- <v> AlgorithmList = [{hashs, [hash_algorithms()]},
- {ciphers, [cipher_algorithms()]},
- {public_keys, [public_key_algorithms()]},
- {macs, [mac_algorithms()]}]
- </v>
- </type>
<desc>
<p> Can be used to determine which crypto algorithms that are supported
- by the underlying OpenSSL library</p>
+ by the underlying libcrypto library</p>
+ <p>Note: the <c>rsa_opts</c> entry is in an experimental state and may change or be removed without notice.
+ No guarantee for the accuarcy of the rsa option's value list should be assumed.
+ </p>
</desc>
</func>
<func>
- <name>ec_curves() -> EllipticCurveList </name>
+ <name name="ec_curves" arity="0"/>
<fsummary>Provide a list of available named elliptic curves.</fsummary>
- <type>
- <v>EllipticCurveList = [ec_named_curve()]</v>
- </type>
<desc>
<p>Can be used to determine which named elliptic curves are supported.</p>
</desc>
</func>
<func>
- <name>ec_curve(NamedCurve) -> EllipticCurve </name>
+ <name name="ec_curve" arity="1"/>
<fsummary>Get the defining parameters of a elliptic curve.</fsummary>
- <type>
- <v>NamedCurve = ec_named_curve()</v>
- <v>EllipticCurve = ec_explicit_curve()</v>
- </type>
<desc>
<p>Return the defining parameters of a elliptic curve.</p>
</desc>
</func>
- <func>
- <name>verify(Algorithm, DigestType, Msg, Signature, Key) -> boolean()</name>
- <name>verify(Algorithm, DigestType, Msg, Signature, Key, Options) -> boolean()</name>
+ <func>
+ <name name="sign" arity="4"/>
+ <name name="sign" arity="5"/>
+ <fsummary> Create digital signature.</fsummary>
+ <desc>
+ <p>Creates a digital signature.</p>
+ <p>The msg is either the binary "cleartext" data to be
+ signed or it is the hashed value of "cleartext" i.e. the
+ digest (plaintext).</p>
+ <p>Algorithm <c>dss</c> can only be used together with digest type
+ <c>sha</c>.</p>
+ <p>See also <seealso marker="public_key:public_key#sign-3">public_key:sign/3</seealso>.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="verify" arity="5"/>
+ <name name="verify" arity="6"/>
<fsummary>Verifies a digital signature.</fsummary>
- <type>
- <v> Algorithm = rsa | dss | ecdsa </v>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The msg is either the binary "cleartext" data
- or it is the hashed value of "cleartext" i.e. the digest (plaintext).</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Signature = binary()</v>
- <v>Key = rsa_public() | dss_public() | [ecdh_public(),ecdh_params()] | engine_key_ref()</v>
- <v>Options = sign_options()</v>
- </type>
<desc>
<p>Verifies a digital signature</p>
+ <p>The msg is either the binary "cleartext" data to be
+ signed or it is the hashed value of "cleartext" i.e. the
+ digest (plaintext).</p>
<p>Algorithm <c>dss</c> can only be used together with digest type
<c>sha</c>.</p>
@@ -1066,17 +1316,24 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
<!-- Engine functions -->
<func>
- <name>engine_get_all_methods() -> Result</name>
+ <name name="privkey_to_pubkey" arity="2"/>
+ <fsummary>Fetches a public key from an Engine stored private key.</fsummary>
+ <desc>
+ <p>Fetches the corresponding public key from a private key stored in an Engine.
+ The key must be of the type indicated by the Type parameter.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_all_methods" arity="0"/>
<fsummary>Return list of all possible engine methods</fsummary>
- <type>
- <v>Result = [EngineMethod::atom()]</v>
- </type>
<desc>
<p>
Returns a list of all possible engine methods.
</p>
- <p>
- May throw exception notsup in case there is
+ <p>
+ May raise exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1087,23 +1344,18 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_load(EngineId, PreCmds, PostCmds) -> Result</name>
+ <name name="engine_load" arity="3"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>EngineId = unicode:chardata()</v>
- <v>PreCmds, PostCmds = [{unicode:chardata(), unicode:chardata()}]</v>
- <v>Result = {ok, Engine::term()} | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Loads the OpenSSL engine given by <c>EngineId</c> if it is available and then returns ok and
- an engine handle. This function is the same as calling <c>engine_load/4</c> with
- <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ an engine handle. This function is the same as calling <c>engine_load/4</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
returned if the engine can't be loaded.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1114,22 +1366,16 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_load(EngineId, PreCmds, PostCmds, EngineMethods) -> Result</name>
+ <name name="engine_load" arity="4"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>EngineId = unicode:chardata()</v>
- <v>PreCmds, PostCmds = [{unicode:chardata(), unicode:chardata()}]</v>
- <v>EngineMethods = [engine_method_type()]</v>
- <v>Result = {ok, Engine::term()} | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Loads the OpenSSL engine given by <c>EngineId</c> if it is available and then returns ok and
an engine handle. An error tuple is returned if the engine can't be loaded.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1140,20 +1386,16 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_unload(Engine) -> Result</name>
+ <name name="engine_unload" arity="1"/>
<fsummary>Dynamical load an encryption engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
- Unloads the OpenSSL engine given by <c>EngineId</c>.
+ Unloads the OpenSSL engine given by <c>Engine</c>.
An error tuple is returned if the engine can't be unloaded.
</p>
<p>
- The function throws a badarg if the parameter is in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameter is in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
@@ -1164,146 +1406,225 @@ _FloatValue = rand:uniform(). % [0.0; 1.0[</pre>
</func>
<func>
- <name>engine_list() -> Result</name>
- <fsummary>List the known engine ids</fsummary>
- <type>
- <v>Result = [EngineId::unicode:chardata()]</v>
- </type>
+ <name name="engine_by_id" arity="1"/>
+ <fsummary>Get a reference to an already loaded engine</fsummary>
<desc>
- <p>List the id's of all engines in OpenSSL's internal list.</p>
<p>
- It may also throw the exception notsup in case there is
+ Get a reference to an already loaded engine with <c>EngineId</c>.
+ An error tuple is returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameter is in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
<p>
- See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
in the User's Guide.
</p>
</desc>
</func>
<func>
- <name>engine_ctrl_cmd_string(Engine, CmdName, CmdArg) -> Result</name>
+ <name name="engine_ctrl_cmd_string" arity="3"/>
<fsummary>Sends ctrl commands to an OpenSSL engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>CmdName = unicode:chardata()</v>
- <v>CmdArg = unicode:chardata()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Sends ctrl commands to the OpenSSL engine given by <c>Engine</c>.
- This function is the same as calling <c>engine_ctrl_cmd_string/4</c> with
+ This function is the same as calling <c>engine_ctrl_cmd_string/4</c> with
<c>Optional</c> set to <c>false</c>.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
</desc>
</func>
<func>
- <name>engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) -> Result</name>
+ <name name="engine_ctrl_cmd_string" arity="4"/>
<fsummary>Sends ctrl commands to an OpenSSL engine</fsummary>
- <type>
- <v>Engine = term()</v>
- <v>CmdName = unicode:chardata()</v>
- <v>CmdArg = unicode:chardata()</v>
- <v>Optional = boolean()</v>
- <v>Result = ok | {error, Reason::term()}</v>
- </type>
<desc>
<p>
Sends ctrl commands to the OpenSSL engine given by <c>Engine</c>.
- <c>Optional</c> is a boolean argument that can relax the semantics of the function.
- If set to <c>true</c> it will only return failure if the ENGINE supported the given
- command name but failed while executing it, if the ENGINE doesn't support the command
- name it will simply return success without doing anything. In this case we assume
+ <c>Optional</c> is a boolean argument that can relax the semantics of the function.
+ If set to <c>true</c> it will only return failure if the ENGINE supported the given
+ command name but failed while executing it, if the ENGINE doesn't support the command
+ name it will simply return success without doing anything. In this case we assume
the user is only supplying commands specific to the given ENGINE so we set this to
<c>false</c>.
</p>
<p>
- The function throws a badarg if the parameters are in wrong format.
- It may also throw the exception notsup in case there is
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_add" arity="1"/>
+ <fsummary>Add engine to OpenSSL internal list</fsummary>
+ <desc>
+ <p>Add the engine to OpenSSL's internal list.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_remove" arity="1"/>
+ <fsummary>Remove engine to OpenSSL internal list</fsummary>
+ <desc>
+ <p>Remove the engine from OpenSSL's internal list.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_id" arity="1"/>
+ <fsummary>Fetch engine ID</fsummary>
+ <desc>
+ <p>Return the ID for the engine, or an empty binary if there is no id set.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_get_name" arity="1"/>
+ <fsummary>Fetch engine name</fsummary>
+ <desc>
+ <p>Return the name (eg a description) for the engine, or an empty binary if there is no name set.</p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="engine_list" arity="0"/>
+ <fsummary>List the known engine ids</fsummary>
+ <desc>
+ <p>List the id's of all engines in OpenSSL's internal list.</p>
+ <p>
+ It may also raise the exception <c>error:notsup</c> in case there is
no engine support in the underlying OpenSSL implementation.
</p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ <p>
+ May raise exception <c>error:notsup</c> in case engine functionality is not supported by the underlying
+ OpenSSL implementation.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_loaded" arity="2"/>
+ <fsummary>Ensure encryption engine just loaded once</fsummary>
+ <desc>
+ <p>
+ Loads the OpenSSL engine given by <c>EngineId</c> and the path to the dynamic library
+ implementing the engine. This function is the same as calling <c>ensure_engine_loaded/3</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ returned if the engine can't be loaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_loaded" arity="3"/>
+ <fsummary>Ensure encryption engine just loaded once</fsummary>
+ <desc>
+ <p>
+ Loads the OpenSSL engine given by <c>EngineId</c> and the path to the dynamic library
+ implementing the engine. This function differs from the normal engine_load in that sense it
+ also add the engine id to the internal list in OpenSSL. Then in the following calls to the function
+ it just fetch the reference to the engine instead of loading it again.
+ An error tuple is returned if the engine can't be loaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_unloaded" arity="1"/>
+ <fsummary>Unload an engine loaded with the ensure function</fsummary>
+ <desc>
+ <p>
+ Unloads an engine loaded with the <c>ensure_engine_loaded</c> function.
+ It both removes the label from the OpenSSL internal engine list and unloads the engine.
+ This function is the same as calling <c>ensure_engine_unloaded/2</c> with
+ <c>EngineMethods</c> set to a list of all the possible methods. An error tuple is
+ returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="ensure_engine_unloaded" arity="2"/>
+ <fsummary>Unload an engine loaded with the ensure function</fsummary>
+ <desc>
+ <p>
+ Unloads an engine loaded with the <c>ensure_engine_loaded</c> function.
+ It both removes the label from the OpenSSL internal engine list and unloads the engine.
+ An error tuple is returned if the engine can't be unloaded.
+ </p>
+ <p>
+ The function raises a <c>error:badarg</c> if the parameters are in wrong format.
+ It may also raise the exception <c>error:notsup</c> in case there is
+ no engine support in the underlying OpenSSL implementation.
+ </p>
+ <p>
+ See also the chapter <seealso marker="crypto:engine_load#engine_load">Engine Load</seealso>
+ in the User's Guide.
+ </p>
</desc>
</func>
</funcs>
- <!-- Maybe put this in the users guide -->
- <!-- <section> -->
- <!-- <title>DES in CBC mode</title> -->
- <!-- <p>The Data Encryption Standard (DES) defines an algorithm for -->
- <!-- encrypting and decrypting an 8 byte quantity using an 8 byte key -->
- <!-- (actually only 56 bits of the key is used). -->
- <!-- </p> -->
- <!-- <p>When it comes to encrypting and decrypting blocks that are -->
- <!-- multiples of 8 bytes various modes are defined (NIST SP -->
- <!-- 800-38A). One of those modes is the Cipher Block Chaining (CBC) -->
- <!-- mode, where the encryption of an 8 byte segment depend not only -->
- <!-- of the contents of the segment itself, but also on the result of -->
- <!-- encrypting the previous segment: the encryption of the previous -->
- <!-- segment becomes the initializing vector of the encryption of the -->
- <!-- current segment. -->
- <!-- </p> -->
- <!-- <p>Thus the encryption of every segment depends on the encryption -->
- <!-- key (which is secret) and the encryption of the previous -->
- <!-- segment, except the first segment which has to be provided with -->
- <!-- an initial initializing vector. That vector could be chosen at -->
- <!-- random, or be a counter of some kind. It does not have to be -->
- <!-- secret. -->
- <!-- </p> -->
- <!-- <p>The following example is drawn from the old FIPS 81 standard -->
- <!-- (replaced by NIST SP 800-38A), where both the plain text and the -->
- <!-- resulting cipher text is settled. The following code fragment -->
- <!-- returns `true'. -->
- <!-- </p> -->
- <!-- <pre><![CDATA[ -->
-
- <!-- Key = <<16#01,16#23,16#45,16#67,16#89,16#ab,16#cd,16#ef>>, -->
- <!-- IVec = <<16#12,16#34,16#56,16#78,16#90,16#ab,16#cd,16#ef>>, -->
- <!-- P = "Now is the time for all ", -->
- <!-- C = crypto:des_cbc_encrypt(Key, IVec, P), -->
- <!-- % Which is the same as -->
- <!-- P1 = "Now is t", P2 = "he time ", P3 = "for all ", -->
- <!-- C1 = crypto:des_cbc_encrypt(Key, IVec, P1), -->
- <!-- C2 = crypto:des_cbc_encrypt(Key, C1, P2), -->
- <!-- C3 = crypto:des_cbc_encrypt(Key, C2, P3), -->
-
- <!-- C = <<C1/binary, C2/binary, C3/binary>>, -->
- <!-- C = <<16#e5,16#c7,16#cd,16#de,16#87,16#2b,16#f2,16#7c, -->
- <!-- 16#43,16#e9,16#34,16#00,16#8c,16#38,16#9c,16#0f, -->
- <!-- 16#68,16#37,16#88,16#49,16#9a,16#7c,16#05,16#f6>>, -->
- <!-- <<"Now is the time for all ">> == -->
- <!-- crypto:des_cbc_decrypt(Key, IVec, C). -->
- <!-- ]]></pre> -->
- <!-- <p>The following is true for the DES CBC mode. For all -->
- <!-- decompositions <c>P1 ++ P2 = P</c> of a plain text message -->
- <!-- <c>P</c> (where the length of all quantities are multiples of 8 -->
- <!-- bytes), the encryption <c>C</c> of <c>P</c> is equal to <c>C1 ++ -->
- <!-- C2</c>, where <c>C1</c> is obtained by encrypting <c>P1</c> with -->
- <!-- <c>Key</c> and the initializing vector <c>IVec</c>, and where -->
- <!-- <c>C2</c> is obtained by encrypting <c>P2</c> with <c>Key</c> -->
- <!-- and the initializing vector <c>last8(C1)</c>, -->
- <!-- where <c>last(Binary)</c> denotes the last 8 bytes of the -->
- <!-- binary <c>Binary</c>. -->
- <!-- </p> -->
- <!-- <p>Similarly, for all decompositions <c>C1 ++ C2 = C</c> of a -->
- <!-- cipher text message <c>C</c> (where the length of all quantities -->
- <!-- are multiples of 8 bytes), the decryption <c>P</c> of <c>C</c> -->
- <!-- is equal to <c>P1 ++ P2</c>, where <c>P1</c> is obtained by -->
- <!-- decrypting <c>C1</c> with <c>Key</c> and the initializing vector -->
- <!-- <c>IVec</c>, and where <c>P2</c> is obtained by decrypting -->
- <!-- <c>C2</c> with <c>Key</c> and the initializing vector -->
- <!-- <c>last8(C1)</c>, where <c>last8(Binary)</c> is as above. -->
- <!-- </p> -->
- <!-- <p>For DES3 (which uses three 64 bit keys) the situation is the -->
- <!-- same. -->
- <!-- </p> -->
- <!-- </section> -->
+
</erlref>
diff --git a/lib/crypto/doc/src/engine_keys.xml b/lib/crypto/doc/src/engine_keys.xml
index 38714fed8a..b28606fb4e 100644
--- a/lib/crypto/doc/src/engine_keys.xml
+++ b/lib/crypto/doc/src/engine_keys.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year><year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -40,7 +40,7 @@
</p>
<p>
An engine could among other tasks provide a storage for
- private or public keys. Such a storage could be made safer than the normal file system. Thoose techniques are not
+ private or public keys. Such a storage could be made safer than the normal file system. Those techniques are not
described in this User's Guide. Here we concentrate on how to use private or public keys stored in
such an engine.
</p>
@@ -62,7 +62,7 @@
on the Engine loaded
</item>
<item>an Erlang map is constructed with the Engine reference, the key reference and possibly a key passphrase if
- needed by the Engine. See the <seealso marker="crypto:crypto#engine_key_ref_type">Reference Manual</seealso> for
+ needed by the Engine. See the <seealso marker="crypto:crypto#type-engine_key_ref">Reference Manual</seealso> for
details of the map.
</item>
</list>
diff --git a/lib/crypto/doc/src/engine_load.xml b/lib/crypto/doc/src/engine_load.xml
index e5c3f5d561..5f7ccc784b 100644
--- a/lib/crypto/doc/src/engine_load.xml
+++ b/lib/crypto/doc/src/engine_load.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2017</year><year>2017</year>
+ <year>2017</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,6 +42,9 @@
operations. The hardware implementation usually offers improved performance over its
software-based counterpart, which is known as cryptographic acceleration.
</p>
+ <note>
+ <p>The file name requirement on the engine dynamic library can differ between SSL versions.</p>
+ </note>
</section>
<section>
@@ -54,9 +57,6 @@
<code>
1> {ok, Engine} = crypto:engine_load(&lt;&lt;"otp_test_engine">>, [], []).
{ok, #Ref}</code>
- <note>
- <p>The file name requirement on the engine dynamic library can differ between SSL versions.</p>
- </note>
</section>
<section>
@@ -72,9 +72,6 @@
&lt;&lt;"LOAD">>],
[]).
{ok, #Ref}</code>
- <note>
- <p>The dynamic engine is not supported in LibreSSL from version 2.2.1</p>
- </note>
</section>
<section>
@@ -100,6 +97,28 @@ engine_method_pkey_meths, engine_method_pkey_asn1_meths].
</section>
<section>
+ <title>Load with the ensure loaded function</title>
+ <p>
+ This function makes sure the engine is loaded just once and the ID is added to the internal
+ engine list of OpenSSL. The following calls to the function will check if the ID is loaded
+ and then just get a new reference to the engine.
+ </p>
+ <code>
+ 5> {ok, Engine} = crypto:ensure_engine_loaded(&lt;&lt;"MD5">>,
+ &lt;&lt;"/some/path/otp_test_engine.so">>).
+ {ok, #Ref}</code>
+ <p>
+ To unload it use crypto:ensure_engine_unloaded/1 which removes the ID from the internal list
+ before unloading the engine.
+ </p>
+ <code>
+ 6> crypto:ensure_engine_unloaded(&lt;&lt;"MD5">>).
+ ok</code>
+ </section>
+
+
+
+ <section>
<title>List all engines currently loaded</title>
<code>
5> crypto:engine_list().
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 2e48b48d67..d81a8ddd87 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,164 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.3.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The RSA options <c>rsa_mgf1_md</c>, <c>rsa_oaep_md</c>,
+ and <c>rsa_oaep_label</c> were always disabled. They will
+ now be enabled when a suitable cryptolib is used.</p>
+ <p>
+ They are still experimental and may change without prior
+ notice.</p>
+ <p>
+ Own Id: OTP-15212 Aux Id: ERL-675, PR1899, PR838 </p>
+ </item>
+ <item>
+ <p>
+ The ciphers <c>aes_ige256</c> and <c>blowfish_cbc</c> had
+ naming issues in <c>crypto:next_iv/2</c>.</p>
+ <p>
+ Own Id: OTP-15283</p>
+ </item>
+ <item>
+ <p>
+ the <c>RSA_SSLV23_PADDING</c> is disabled if LibreSSL is
+ used as cryptlib. This is due to compilation problems.</p>
+ <p>
+ This will be investigated further in the future.</p>
+ <p>
+ Own Id: OTP-15303</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The supported named elliptic curves are now reported in
+ <c>crypto:supports/0</c> in a new entry tagged by
+ <c>'curves'</c>.</p>
+ <p>
+ The function <c>crypto:ec_curves/0</c> is kept for
+ compatibility.</p>
+ <p>
+ Own Id: OTP-14717 Aux Id: OTP-15244 </p>
+ </item>
+ <item>
+ <p>
+ The typing in the CRYPTO and PUBLIC_KEY applications are
+ reworked and a few mistakes are corrected.</p>
+ <p>
+ The documentation is now generated from the typing and
+ some clarifications are made.</p>
+ <p>
+ A new chapter on Algorithm Details such as key sizes and
+ availability is added to the CRYPTO User's Guide.</p>
+ <p>
+ Own Id: OTP-15134</p>
+ </item>
+ <item>
+ <p>
+ Support for SHA3 both as a separate hash and in HMAC is
+ now available if OpenSSL 1.1.1 or higher is used as
+ cryptolib.</p>
+ <p>
+ Available lengths are reported in the <c>'hashs'</c>
+ entry in <c>crypto:supports/0</c> as <c>sha3_*</c>.</p>
+ <p>
+ Own Id: OTP-15153</p>
+ </item>
+ <item>
+ <p>
+ The mac algorithm <c>poly1305</c> and the cipher
+ algorithm <c>chacha20</c> are now supported if OpenSSL
+ 1.1.1 or higher is used as cryptolib.</p>
+ <p>
+ Own Id: OTP-15164 Aux Id: OTP-15209 </p>
+ </item>
+ <item>
+ <p>
+ The key exchange Edward curves <c>x25519</c> and
+ <c>x448</c> are now supported if OpenSSL 1.1.1 or higher
+ is used as cryptolib.</p>
+ <p>
+ Own Id: OTP-15240 Aux Id: OTP-15133 </p>
+ </item>
+ <item>
+ <p>
+ The supported RSA options for sign/verify and
+ encrypt/decrypt are now reported in
+ <c>crypto:supports/0</c> in a new entry tagged by
+ '<c>rsa_opts</c>'.</p>
+ <p>
+ The exakt set is still experimental and may change
+ without prior notice.</p>
+ <p>
+ Own Id: OTP-15260</p>
+ </item>
+ <item>
+ <p>
+ The cipher <c>aes_ccm</c> is added.</p>
+ <p>
+ Own Id: OTP-15286</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Update the crypto engine functions to handle multiple
+ loads of an engine. </p> <p><c>engine_load/3/4</c> is
+ updated so it doesn't add the engine ID to OpenSSLs
+ internal list of engines which makes it possible to run
+ the engine_load more than once if it doesn't contain
+ global data.</p> <p>Added <c>ensure_engine_loaded/2/3</c>
+ which guarantees that the engine just is loaded once and
+ the following calls just returns a reference to it. This
+ is done by add the ID to the internal OpenSSL list and
+ check if it is already registered when the function is
+ called.</p> <p>Added <c>ensure_engine_unloaded/1/2</c> to
+ unload engines loaded with ensure_engine_loaded.</p>
+ <p>Then some more utility functions are added.</p>
+ <p><c>engine_add/1</c>, adds the engine to OpenSSL
+ internal list</p> <p><c>engine_remove/1</c>, remove the
+ engine from OpenSSL internal list</p>
+ <p><c>engine_get_id/1</c>, fetch the engines id</p>
+ <p><c>engine_get_name/1</c>, fetch the engine name</p>
+ <p>
+ Own Id: OTP-15233</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Crypto 4.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -78,6 +236,22 @@
</section>
+<section><title>Crypto 4.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a node crash in <c>crypto:compute_key(ecdh,
+ ...)</c> when passing a wrongly typed Others
+ argument.</p>
+ <p>
+ Own Id: OTP-15194 Aux Id: ERL-673 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/crypto/doc/src/specs.xml b/lib/crypto/doc/src/specs.xml
new file mode 100644
index 0000000000..66c79a906b
--- /dev/null
+++ b/lib/crypto/doc/src/specs.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_crypto.xml"/>
+</specs>
diff --git a/lib/crypto/doc/src/usersguide.xml b/lib/crypto/doc/src/usersguide.xml
index 0124121433..2dfc966609 100644
--- a/lib/crypto/doc/src/usersguide.xml
+++ b/lib/crypto/doc/src/usersguide.xml
@@ -50,4 +50,5 @@
<xi:include href="fips.xml"/>
<xi:include href="engine_load.xml"/>
<xi:include href="engine_keys.xml"/>
+ <xi:include href="algorithm_details.xml"/>
</part>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 714cba58b9..9915a5a6f3 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -29,10 +29,12 @@
-export([generate_key/2, generate_key/3, compute_key/4]).
-export([hmac/3, hmac/4, hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([cmac/3, cmac/4]).
+-export([poly1305/2]).
-export([exor/2, strong_rand_bytes/1, mod_pow/3]).
--export([rand_seed/0, rand_seed_alg/1]).
--export([rand_seed_s/0, rand_seed_alg_s/1]).
+-export([rand_seed/0, rand_seed_alg/1, rand_seed_alg/2]).
+-export([rand_seed_s/0, rand_seed_alg_s/1, rand_seed_alg_s/2]).
-export([rand_plugin_next/1]).
+-export([rand_plugin_aes_next/1, rand_plugin_aes_jump/1]).
-export([rand_plugin_uniform/1]).
-export([rand_plugin_uniform/2]).
-export([rand_cache_plugin_next/1]).
@@ -51,19 +53,49 @@
engine_load/3,
engine_load/4,
engine_unload/1,
+ engine_by_id/1,
engine_list/0,
engine_ctrl_cmd_string/3,
- engine_ctrl_cmd_string/4
+ engine_ctrl_cmd_string/4,
+ engine_add/1,
+ engine_remove/1,
+ engine_get_id/1,
+ engine_get_name/1,
+ ensure_engine_loaded/2,
+ ensure_engine_loaded/3,
+ ensure_engine_unloaded/1,
+ ensure_engine_unloaded/2
]).
+-export_type([ %% A minimum exported: only what public_key needs.
+ dh_private/0,
+ dh_public/0,
+ dss_digest_type/0,
+ ec_named_curve/0,
+ ecdsa_digest_type/0,
+ pk_encrypt_decrypt_opts/0,
+ pk_sign_verify_opts/0,
+ rsa_digest_type/0,
+ sha1/0,
+ sha2/0
+ ]).
+
-export_type([engine_ref/0,
key_id/0,
password/0
]).
-
+%%% Opaque types must be exported :(
+-export_type([
+ stream_state/0,
+ hmac_state/0,
+ hash_state/0
+ ]).
+
%% Private. For tests.
--export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2, get_test_engine/0]).
+-export([packed_openssl_version/4, engine_methods_convert_to_bitmask/2,
+ get_test_engine/0]).
+-export([rand_plugin_aes_jump_2pow20/1]).
-deprecated({rand_uniform, 2, next_major_release}).
@@ -73,16 +105,187 @@
%% Used by strong_rand_float/0
-define(HALF_DBL_EPSILON, 1.1102230246251565e-16). % math:pow(2, -53)
-%%-type ecdsa_digest_type() :: 'md5' | 'sha' | 'sha256' | 'sha384' | 'sha512'.
+
+%%% ===== BEGIN NEW TYPING ====
+
+%%% Basic
+-type key_integer() :: integer() | binary(). % Always binary() when used as return value
+
+%%% Keys
+-type rsa_public() :: [key_integer()] . % [E, N]
+-type rsa_private() :: [key_integer()] . % [E, N, D] | [E, N, D, P1, P2, E1, E2, C]
+-type rsa_params() :: {ModulusSizeInBits::integer(), PublicExponent::key_integer()} .
+
+-type dss_public() :: [key_integer()] . % [P, Q, G, Y]
+-type dss_private() :: [key_integer()] . % [P, Q, G, X]
+
+-type ecdsa_public() :: key_integer() .
+-type ecdsa_private() :: key_integer() .
+-type ecdsa_params() :: ec_named_curve() | edwards_curve() | ec_explicit_curve() .
+
+-type srp_public() :: key_integer() .
+-type srp_private() :: key_integer() .
+-type srp_gen_params() :: {user,srp_user_gen_params()} | {host,srp_host_gen_params()}.
+-type srp_comp_params() :: {user,srp_user_comp_params()} | {host,srp_host_comp_params()}.
+-type srp_user_gen_params() :: list(binary() | atom() | list()) .
+-type srp_host_gen_params() :: list(binary() | atom() | list()) .
+-type srp_user_comp_params() :: list(binary() | atom()) .
+-type srp_host_comp_params() :: list(binary() | atom()) .
+
+-type dh_public() :: key_integer() .
+-type dh_private() :: key_integer() .
+-type dh_params() :: [key_integer()] . % [P, G] | [P, G, PrivateKeyBitLength]
+
+-type ecdh_public() :: key_integer() .
+-type ecdh_private() :: key_integer() .
+-type ecdh_params() :: ec_named_curve() | edwards_curve() | ec_explicit_curve() .
+
+
+%%% Curves
+
+-type ec_explicit_curve() :: {Field :: ec_field(),
+ Curve :: ec_curve(),
+ BasePoint :: binary(),
+ Order :: binary(),
+ CoFactor :: none | % FIXME: Really?
+ binary()
+ } .
+
+-type ec_curve() :: {A :: binary(),
+ B :: binary(),
+ Seed :: none | binary()
+ } .
+
+-type ec_field() :: ec_prime_field() | ec_characteristic_two_field() .
+
+-type ec_prime_field() :: {prime_field, Prime :: integer()} .
+-type ec_characteristic_two_field() :: {characteristic_two_field, M :: integer(), Basis :: ec_basis()} .
+
+-type ec_basis() :: {tpbasis, K :: non_neg_integer()}
+ | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()}
+ | onbasis .
+
+-type ec_named_curve() :: brainpoolP160r1
+ | brainpoolP160t1
+ | brainpoolP192r1
+ | brainpoolP192t1
+ | brainpoolP224r1
+ | brainpoolP224t1
+ | brainpoolP256r1
+ | brainpoolP256t1
+ | brainpoolP320r1
+ | brainpoolP320t1
+ | brainpoolP384r1
+ | brainpoolP384t1
+ | brainpoolP512r1
+ | brainpoolP512t1
+ | c2pnb163v1
+ | c2pnb163v2
+ | c2pnb163v3
+ | c2pnb176v1
+ | c2pnb208w1
+ | c2pnb272w1
+ | c2pnb304w1
+ | c2pnb368w1
+ | c2tnb191v1
+ | c2tnb191v2
+ | c2tnb191v3
+ | c2tnb239v1
+ | c2tnb239v2
+ | c2tnb239v3
+ | c2tnb359v1
+ | c2tnb431r1
+ | ipsec3
+ | ipsec4
+ | prime192v1
+ | prime192v2
+ | prime192v3
+ | prime239v1
+ | prime239v2
+ | prime239v3
+ | prime256v1
+ | secp112r1
+ | secp112r2
+ | secp128r1
+ | secp128r2
+ | secp160k1
+ | secp160r1
+ | secp160r2
+ | secp192k1
+ | secp192r1
+ | secp224k1
+ | secp224r1
+ | secp256k1
+ | secp256r1
+ | secp384r1
+ | secp521r1
+ | sect113r1
+ | sect113r2
+ | sect131r1
+ | sect131r2
+ | sect163k1
+ | sect163r1
+ | sect163r2
+ | sect193r1
+ | sect193r2
+ | sect233k1
+ | sect233r1
+ | sect239k1
+ | sect283k1
+ | sect283r1
+ | sect409k1
+ | sect409r1
+ | sect571k1
+ | sect571r1
+ | wtls1
+ | wtls10
+ | wtls11
+ | wtls12
+ | wtls3
+ | wtls4
+ | wtls5
+ | wtls6
+ | wtls7
+ | wtls8
+ | wtls9
+ .
+
+-type edwards_curve() :: x25519
+ | x448 .
+
+%%%
+-type block_cipher_with_iv() :: cbc_cipher()
+ | cfb_cipher()
+ | aes_cbc128
+ | aes_cbc256
+ | aes_ige256
+ | blowfish_ofb64
+ | des3_cbf % cfb misspelled
+ | des_ede3
+ | rc2_cbc .
+
+-type cbc_cipher() :: des_cbc | des3_cbc | aes_cbc | blowfish_cbc .
+-type aead_cipher() :: aes_gcm | aes_ccm | chacha20_poly1305 .
+-type cfb_cipher() :: aes_cfb128 | aes_cfb8 | blowfish_cfb64 | des3_cfb | des_cfb .
+
+-type block_cipher_without_iv() :: ecb_cipher() .
+-type ecb_cipher() :: des_ecb | blowfish_ecb | aes_ecb .
+
+-type key() :: iodata().
+-type des3_key() :: [key()].
+
+%%%
+-type rsa_digest_type() :: sha1() | sha2() | md5 | ripemd160 .
+-type dss_digest_type() :: sha1() | sha2() .
+-type ecdsa_digest_type() :: sha1() | sha2() .
+
+-type sha1() :: sha .
+-type sha2() :: sha224 | sha256 | sha384 | sha512 .
+-type sha3() :: sha3_224 | sha3_256 | sha3_384 | sha3_512 .
+
+-type compatibility_only_hash() :: md5 | md4 .
+
-type crypto_integer() :: binary() | integer().
-%%-type ec_named_curve() :: atom().
-%%-type ec_point() :: crypto_integer().
-%%-type ec_basis() :: {tpbasis, K :: non_neg_integer()} | {ppbasis, K1 :: non_neg_integer(), K2 :: non_neg_integer(), K3 :: non_neg_integer()} | onbasis.
-%%-type ec_field() :: {prime_field, Prime :: integer()} | {characteristic_two_field, M :: integer(), Basis :: ec_basis()}.
-%%-type ec_prime() :: {A :: crypto_integer(), B :: crypto_integer(), Seed :: binary() | none}.
-%%-type ec_curve_spec() :: {Field :: ec_field(), Prime :: ec_prime(), Point :: crypto_integer(), Order :: integer(), CoFactor :: none | integer()}.
-%%-type ec_curve() :: ec_named_curve() | ec_curve_spec().
-%%-type ec_key() :: {Curve :: ec_curve(), PrivKey :: binary() | undefined, PubKey :: ec_point() | undefined}.
-compile(no_native).
-on_load(on_load/0).
@@ -98,150 +301,240 @@ nif_stub_error(Line) ->
%% Crypto app version history:
%% (no version): Driver implementation
%% 2.0 : NIF implementation, requires OTP R14
+
+%% When generating documentation from crypto.erl, the macro ?CRYPTO_VSN is not defined.
+%% That causes the doc generation to stop...
+-ifndef(CRYPTO_VSN).
+-define(CRYPTO_VSN, "??").
+-endif.
version() -> ?CRYPTO_VSN.
+-spec start() -> ok | {error, Reason::term()}.
start() ->
application:start(crypto).
+-spec stop() -> ok | {error, Reason::term()}.
stop() ->
application:stop(crypto).
+-spec supports() -> [Support]
+ when Support :: {hashs, Hashs}
+ | {ciphers, Ciphers}
+ | {public_keys, PKs}
+ | {macs, Macs}
+ | {curves, Curves}
+ | {rsa_opts, RSAopts},
+ Hashs :: [sha1() | sha2() | sha3() | ripemd160 | compatibility_only_hash()],
+ Ciphers :: [stream_cipher()
+ | block_cipher_with_iv() | block_cipher_without_iv()
+ | aead_cipher()
+ ],
+ PKs :: [rsa | dss | ecdsa | dh | ecdh | ec_gf2m],
+ Macs :: [hmac | cmac | poly1305],
+ Curves :: [ec_named_curve() | edwards_curve()],
+ RSAopts :: [rsa_sign_verify_opt() | rsa_opt()] .
supports()->
- {Hashs, PubKeys, Ciphers, Macs, Curves} = algorithms(),
-
+ {Hashs, PubKeys, Ciphers, Macs, Curves, RsaOpts} = algorithms(),
[{hashs, Hashs},
{ciphers, Ciphers},
{public_keys, PubKeys},
- {macs, Macs}
- | case Curves of
- [] -> [];
- _ -> [{curves, Curves}] % Only show this experimental feature
- % if OpenSSL 1.1.1 beta4 or higher (where
- % eddsa and eddh is enabled)
- end
+ {macs, Macs},
+ {curves, Curves},
+ {rsa_opts, RsaOpts}
].
+-spec info_lib() -> [{Name,VerNum,VerStr}] when Name :: binary(),
+ VerNum :: integer(),
+ VerStr :: binary() .
info_lib() -> ?nif_stub.
-spec info_fips() -> not_supported | not_enabled | enabled.
info_fips() -> ?nif_stub.
--spec enable_fips_mode(boolean()) -> boolean().
-
+-spec enable_fips_mode(Enable) -> Result when Enable :: boolean(),
+ Result :: boolean().
enable_fips_mode(_) -> ?nif_stub.
--spec hash(_, iodata()) -> binary().
+%%%================================================================
+%%%
+%%% Hashing
+%%%
+%%%================================================================
-hash(Hash, Data0) ->
- Data = iolist_to_binary(Data0),
- MaxBytes = max_bytes(),
- hash(Hash, Data, erlang:byte_size(Data), MaxBytes).
+-define(HASH_HASH_ALGORITHM, sha1() | sha2() | sha3() | ripemd160 | compatibility_only_hash() ).
--spec hash_init('md5'|'md4'|'ripemd160'|
- 'sha'|'sha224'|'sha256'|'sha384'|'sha512') -> any().
+-spec hash(Type, Data) -> Digest when Type :: ?HASH_HASH_ALGORITHM,
+ Data :: iodata(),
+ Digest :: binary().
+hash(Type, Data) ->
+ Data1 = iolist_to_binary(Data),
+ MaxBytes = max_bytes(),
+ hash(Type, Data1, erlang:byte_size(Data1), MaxBytes).
-hash_init(Hash) ->
- notsup_to_error(hash_init_nif(Hash)).
+-opaque hash_state() :: reference().
--spec hash_update(_, iodata()) -> any().
+-spec hash_init(Type) -> State when Type :: ?HASH_HASH_ALGORITHM,
+ State :: hash_state().
+hash_init(Type) ->
+ notsup_to_error(hash_init_nif(Type)).
-hash_update(State, Data0) ->
- Data = iolist_to_binary(Data0),
+-spec hash_update(State, Data) -> NewState when State :: hash_state(),
+ NewState :: hash_state(),
+ Data :: iodata() .
+hash_update(Context, Data) ->
+ Data1 = iolist_to_binary(Data),
MaxBytes = max_bytes(),
- hash_update(State, Data, erlang:byte_size(Data), MaxBytes).
+ hash_update(Context, Data1, erlang:byte_size(Data1), MaxBytes).
--spec hash_final(_) -> binary().
+-spec hash_final(State) -> Digest when State :: hash_state(),
+ Digest :: binary().
+hash_final(Context) ->
+ notsup_to_error(hash_final_nif(Context)).
-hash_final(State) ->
- notsup_to_error(hash_final_nif(State)).
+%%%================================================================
+%%%
+%%% MACs (Message Authentication Codes)
+%%%
+%%%================================================================
+%%%---- HMAC
--spec hmac(_, iodata(), iodata()) -> binary().
--spec hmac(_, iodata(), iodata(), integer()) -> binary().
--spec hmac_init(atom(), iodata()) -> binary().
--spec hmac_update(binary(), iodata()) -> binary().
--spec hmac_final(binary()) -> binary().
--spec hmac_final_n(binary(), integer()) -> binary().
+-define(HMAC_HASH_ALGORITHM, sha1() | sha2() | sha3() | compatibility_only_hash()).
-hmac(Type, Key, Data0) ->
- Data = iolist_to_binary(Data0),
- hmac(Type, Key, Data, undefined, erlang:byte_size(Data), max_bytes()).
-hmac(Type, Key, Data0, MacSize) ->
- Data = iolist_to_binary(Data0),
- hmac(Type, Key, Data, MacSize, erlang:byte_size(Data), max_bytes()).
+%%%---- hmac/3,4
+
+-spec hmac(Type, Key, Data) ->
+ Mac when Type :: ?HMAC_HASH_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary() .
+hmac(Type, Key, Data) ->
+ Data1 = iolist_to_binary(Data),
+ hmac(Type, Key, Data1, undefined, erlang:byte_size(Data1), max_bytes()).
+
+-spec hmac(Type, Key, Data, MacLength) ->
+ Mac when Type :: ?HMAC_HASH_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ MacLength :: integer(),
+ Mac :: binary() .
+
+hmac(Type, Key, Data, MacLength) ->
+ Data1 = iolist_to_binary(Data),
+ hmac(Type, Key, Data1, MacLength, erlang:byte_size(Data1), max_bytes()).
+
+%%%---- hmac_init, hamc_update, hmac_final
+
+-opaque hmac_state() :: binary().
+-spec hmac_init(Type, Key) ->
+ State when Type :: ?HMAC_HASH_ALGORITHM,
+ Key :: iodata(),
+ State :: hmac_state() .
hmac_init(Type, Key) ->
notsup_to_error(hmac_init_nif(Type, Key)).
+%%%---- hmac_update
+
+-spec hmac_update(State, Data) -> NewState when Data :: iodata(),
+ State :: hmac_state(),
+ NewState :: hmac_state().
hmac_update(State, Data0) ->
Data = iolist_to_binary(Data0),
hmac_update(State, Data, erlang:byte_size(Data), max_bytes()).
+%%%---- hmac_final
+
+-spec hmac_final(State) -> Mac when State :: hmac_state(),
+ Mac :: binary().
hmac_final(Context) ->
notsup_to_error(hmac_final_nif(Context)).
+
+-spec hmac_final_n(State, HashLen) -> Mac when State :: hmac_state(),
+ HashLen :: integer(),
+ Mac :: binary().
hmac_final_n(Context, HashLen) ->
notsup_to_error(hmac_final_nif(Context, HashLen)).
--spec cmac(_, iodata(), iodata()) -> binary().
--spec cmac(_, iodata(), iodata(), integer()) -> binary().
+%%%---- CMAC
+-define(CMAC_CIPHER_ALGORITHM, cbc_cipher() | cfb_cipher() | blowfish_cbc | des_ede3 | rc2_cbc ).
+
+-spec cmac(Type, Key, Data) ->
+ Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ Mac :: binary().
cmac(Type, Key, Data) ->
notsup_to_error(cmac_nif(Type, Key, Data)).
-cmac(Type, Key, Data, MacSize) ->
- erlang:binary_part(cmac(Type, Key, Data), 0, MacSize).
-
-%% Ecrypt/decrypt %%%
-
--spec block_encrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des3_cfb | des_ede3 |
- blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
- aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
- aes_cbc |
- rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
- (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata()}) -> {binary(), binary()};
- (aes_gcm, Key::iodata(), Ivec::binary(), {AAD::binary(), Data::iodata(), TagLength::1..16}) -> {binary(), binary()}.
-
-block_encrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
- Type =:= des_cfb;
- Type =:= blowfish_cbc;
- Type =:= blowfish_cfb64;
- Type =:= blowfish_ofb64;
- Type =:= aes_cbc128;
- Type =:= aes_cfb8;
- Type =:= aes_cfb128;
- Type =:= aes_cbc256;
- Type =:= aes_cbc;
- Type =:= rc2_cbc ->
- block_crypt_nif(Type, Key, Ivec, Data, true);
-block_encrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
- Type =:= des_ede3 ->
+
+-spec cmac(Type, Key, Data, MacLength) ->
+ Mac when Type :: ?CMAC_CIPHER_ALGORITHM,
+ Key :: iodata(),
+ Data :: iodata(),
+ MacLength :: integer(),
+ Mac :: binary().
+cmac(Type, Key, Data, MacLength) ->
+ erlang:binary_part(cmac(Type, Key, Data), 0, MacLength).
+
+%%%---- POLY1305
+
+-spec poly1305(iodata(), iodata()) -> Mac when Mac :: binary().
+
+poly1305(Key, Data) ->
+ poly1305_nif(Key, Data).
+
+%%%================================================================
+%%%
+%%% Encrypt/decrypt
+%%%
+%%%================================================================
+
+%%%---- Block ciphers
+
+-spec block_encrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), PlainText::iodata()) -> binary();
+ (Type::aead_cipher(), Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata()}) ->
+ {binary(), binary()};
+ (aes_gcm | aes_ccm, Key::iodata(), Ivec::binary(), {AAD::binary(), PlainText::iodata(), TagLength::1..16}) ->
+ {binary(), binary()}.
+
+block_encrypt(Type, Key, Ivec, PlainText) when Type =:= des_cbc;
+ Type =:= des_cfb;
+ Type =:= blowfish_cbc;
+ Type =:= blowfish_cfb64;
+ Type =:= blowfish_ofb64;
+ Type =:= aes_cbc128;
+ Type =:= aes_cfb8;
+ Type =:= aes_cfb128;
+ Type =:= aes_cbc256;
+ Type =:= aes_cbc;
+ Type =:= rc2_cbc ->
+ block_crypt_nif(Type, Key, Ivec, PlainText, true);
+block_encrypt(Type, Key0, Ivec, PlainText) when Type =:= des3_cbc;
+ Type =:= des_ede3 ->
Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, true);
-block_encrypt(des3_cbf, Key0, Ivec, Data) ->
+ block_crypt_nif(des_ede3_cbc, Key, Ivec, PlainText, true);
+block_encrypt(des3_cbf, Key0, Ivec, PlainText) -> % cfb misspelled
Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, true);
-block_encrypt(des3_cfb, Key0, Ivec, Data) ->
+ block_crypt_nif(des_ede3_cbf, Key, Ivec, PlainText, true);
+block_encrypt(des3_cfb, Key0, Ivec, PlainText) ->
Key = check_des3_key(Key0),
- block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, true);
-block_encrypt(aes_ige256, Key, Ivec, Data) ->
- notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, true));
-block_encrypt(aes_gcm, Key, Ivec, {AAD, Data}) ->
- aes_gcm_encrypt(Key, Ivec, AAD, Data);
-block_encrypt(aes_gcm, Key, Ivec, {AAD, Data, TagLength}) ->
- aes_gcm_encrypt(Key, Ivec, AAD, Data, TagLength);
-block_encrypt(chacha20_poly1305, Key, Ivec, {AAD, Data}) ->
- chacha20_poly1305_encrypt(Key, Ivec, AAD, Data).
-
--spec block_decrypt(des_cbc | des_cfb |
- des3_cbc | des3_cbf | des3_cfb | des_ede3 |
- blowfish_cbc | blowfish_cfb64 | blowfish_ofb64 |
- aes_cbc128 | aes_cfb8 | aes_cfb128 | aes_cbc256 | aes_ige256 |
- aes_cbc |
- rc2_cbc,
- Key::iodata(), Ivec::binary(), Data::iodata()) -> binary();
- (aes_gcm | chacha20_poly1305, Key::iodata(), Ivec::binary(),
+ block_crypt_nif(des_ede3_cfb, Key, Ivec, PlainText, true);
+block_encrypt(aes_ige256, Key, Ivec, PlainText) ->
+ notsup_to_error(aes_ige_crypt_nif(Key, Ivec, PlainText, true));
+block_encrypt(Type, Key, Ivec, {AAD, PlainText}) when Type =:= aes_gcm;
+ Type =:= aes_ccm ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText);
+block_encrypt(Type, Key, Ivec, {AAD, PlainText, TagLength}) when Type =:= aes_gcm;
+ Type =:= aes_ccm ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, TagLength);
+block_encrypt(chacha20_poly1305=Type, Key, Ivec, {AAD, PlainText}) ->
+ aead_encrypt(Type, Key, Ivec, AAD, PlainText, 16).
+
+
+-spec block_decrypt(Type::block_cipher_with_iv(), Key::key()|des3_key(), Ivec::binary(), Data::iodata()) -> binary();
+ (Type::aead_cipher(), Key::iodata(), Ivec::binary(),
{AAD::binary(), Data::iodata(), Tag::binary()}) -> binary() | error.
block_decrypt(Type, Key, Ivec, Data) when Type =:= des_cbc;
Type =:= des_cfb;
@@ -259,7 +552,7 @@ block_decrypt(Type, Key0, Ivec, Data) when Type =:= des3_cbc;
Type =:= des_ede3 ->
Key = check_des3_key(Key0),
block_crypt_nif(des_ede3_cbc, Key, Ivec, Data, false);
-block_decrypt(des3_cbf, Key0, Ivec, Data) ->
+block_decrypt(des3_cbf, Key0, Ivec, Data) -> % cfb misspelled
Key = check_des3_key(Key0),
block_crypt_nif(des_ede3_cbf, Key, Ivec, Data, false);
block_decrypt(des3_cfb, Key0, Ivec, Data) ->
@@ -267,23 +560,27 @@ block_decrypt(des3_cfb, Key0, Ivec, Data) ->
block_crypt_nif(des_ede3_cfb, Key, Ivec, Data, false);
block_decrypt(aes_ige256, Key, Ivec, Data) ->
notsup_to_error(aes_ige_crypt_nif(Key, Ivec, Data, false));
-block_decrypt(aes_gcm, Key, Ivec, {AAD, Data, Tag}) ->
- aes_gcm_decrypt(Key, Ivec, AAD, Data, Tag);
-block_decrypt(chacha20_poly1305, Key, Ivec, {AAD, Data, Tag}) ->
- chacha20_poly1305_decrypt(Key, Ivec, AAD, Data, Tag).
+block_decrypt(Type, Key, Ivec, {AAD, Data, Tag}) when Type =:= aes_gcm;
+ Type =:= aes_ccm;
+ Type =:= chacha20_poly1305 ->
+ aead_decrypt(Type, Key, Ivec, AAD, Data, Tag).
+
--spec block_encrypt(des_ecb | blowfish_ecb | aes_ecb, Key::iodata(), Data::iodata()) -> binary().
+-spec block_encrypt(Type::block_cipher_without_iv(), Key::key(), PlainText::iodata()) -> binary().
-block_encrypt(Type, Key, Data) ->
- block_crypt_nif(Type, Key, Data, true).
+block_encrypt(Type, Key, PlainText) ->
+ block_crypt_nif(Type, Key, PlainText, true).
--spec block_decrypt(des_ecb | blowfish_ecb | aes_ecb, Key::iodata(), Data::iodata()) -> binary().
+
+-spec block_decrypt(Type::block_cipher_without_iv(), Key::key(), Data::iodata()) -> binary().
block_decrypt(Type, Key, Data) ->
block_crypt_nif(Type, Key, Data, false).
--spec next_iv(des_cbc | des3_cbc | aes_cbc | aes_ige, Data::iodata()) -> binary().
+-spec next_iv(Type:: cbc_cipher(), Data) -> NextIVec when % Type :: cbc_cipher(), %des_cbc | des3_cbc | aes_cbc | aes_ige,
+ Data :: iodata(),
+ NextIVec :: binary().
next_iv(Type, Data) when is_binary(Data) ->
IVecSize = case Type of
des_cbc -> 8;
@@ -296,7 +593,9 @@ next_iv(Type, Data) when is_binary(Data) ->
next_iv(Type, Data) when is_list(Data) ->
next_iv(Type, list_to_binary(Data)).
--spec next_iv(des_cfb, Data::iodata(), Ivec::binary()) -> binary().
+-spec next_iv(des_cfb, Data, IVec) -> NextIVec when Data :: iodata(),
+ IVec :: binary(),
+ NextIVec :: binary().
next_iv(des_cfb, Data, IVec) ->
IVecAndData = list_to_binary([IVec, Data]),
@@ -305,38 +604,57 @@ next_iv(des_cfb, Data, IVec) ->
next_iv(Type, Data, _Ivec) ->
next_iv(Type, Data).
+%%%---- Stream ciphers
+
+-opaque stream_state() :: {stream_cipher(), reference()}.
+
+-type stream_cipher() :: rc4 | aes_ctr | chacha20 .
+
+-spec stream_init(Type, Key, IVec) -> State when Type :: aes_ctr | chacha20,
+ Key :: iodata(),
+ IVec :: binary(),
+ State :: stream_state() .
stream_init(aes_ctr, Key, Ivec) ->
- {aes_ctr, aes_ctr_stream_init(Key, Ivec)}.
+ {aes_ctr, aes_ctr_stream_init(Key, Ivec)};
+stream_init(chacha20, Key, Ivec) ->
+ {chacha20, chacha20_stream_init(Key,Ivec)}.
+
+-spec stream_init(Type, Key) -> State when Type :: rc4,
+ Key :: iodata(),
+ State :: stream_state() .
stream_init(rc4, Key) ->
{rc4, notsup_to_error(rc4_set_key(Key))}.
+-spec stream_encrypt(State, PlainText) -> {NewState, CipherText}
+ when State :: stream_state(),
+ PlainText :: iodata(),
+ NewState :: stream_state(),
+ CipherText :: iodata() .
stream_encrypt(State, Data0) ->
Data = iolist_to_binary(Data0),
MaxByts = max_bytes(),
stream_crypt(fun do_stream_encrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
+-spec stream_decrypt(State, CipherText) -> {NewState, PlainText}
+ when State :: stream_state(),
+ CipherText :: iodata(),
+ NewState :: stream_state(),
+ PlainText :: iodata() .
stream_decrypt(State, Data0) ->
Data = iolist_to_binary(Data0),
MaxByts = max_bytes(),
stream_crypt(fun do_stream_decrypt/2, State, Data, erlang:byte_size(Data), MaxByts, []).
-%%
-%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
-%%
+
+%%%================================================================
+%%%
+%%% RAND - pseudo random numbers using RN_ and BN_ functions in crypto lib
+%%%
+%%%================================================================
-type rand_cache_seed() ::
nonempty_improper_list(non_neg_integer(), binary()).
--spec strong_rand_bytes(non_neg_integer()) -> binary().
--spec rand_seed() -> rand:state().
--spec rand_seed_s() -> rand:state().
--spec rand_seed_alg(Alg :: atom()) ->
- {rand:alg_handler(),
- atom() | rand_cache_seed()}.
--spec rand_seed_alg_s(Alg :: atom()) ->
- {rand:alg_handler(),
- atom() | rand_cache_seed()}.
--spec rand_uniform(crypto_integer(), crypto_integer()) ->
- crypto_integer().
+-spec strong_rand_bytes(N::non_neg_integer()) -> binary().
strong_rand_bytes(Bytes) ->
case strong_rand_bytes_nif(Bytes) of
false -> erlang:error(low_entropy);
@@ -345,40 +663,87 @@ strong_rand_bytes(Bytes) ->
strong_rand_bytes_nif(_Bytes) -> ?nif_stub.
+-spec rand_seed() -> rand:state().
rand_seed() ->
rand:seed(rand_seed_s()).
+-spec rand_seed_s() -> rand:state().
rand_seed_s() ->
rand_seed_alg_s(?MODULE).
+-spec rand_seed_alg(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
rand_seed_alg(Alg) ->
rand:seed(rand_seed_alg_s(Alg)).
+-spec rand_seed_alg(Alg :: atom(), Seed :: term()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg(Alg, Seed) ->
+ rand:seed(rand_seed_alg_s(Alg, Seed)).
+
-define(CRYPTO_CACHE_BITS, 56).
-rand_seed_alg_s(?MODULE) ->
- {#{ type => ?MODULE,
- bits => 64,
- next => fun ?MODULE:rand_plugin_next/1,
- uniform => fun ?MODULE:rand_plugin_uniform/1,
- uniform_n => fun ?MODULE:rand_plugin_uniform/2},
- no_seed};
-rand_seed_alg_s(crypto_cache) ->
+-define(CRYPTO_AES_BITS, 58).
+
+-spec rand_seed_alg_s(Alg :: atom()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) ->
+ State;
+rand_seed_alg_s({Alg, AlgState}) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),AlgState};
+ rand_seed_alg_s(Alg) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),mk_alg_state(Alg)}.
+%%
+-spec rand_seed_alg_s(Alg :: atom(), Seed :: term()) ->
+ {rand:alg_handler(),
+ atom() | rand_cache_seed()}.
+rand_seed_alg_s(Alg, Seed) when is_atom(Alg) ->
+ {mk_alg_handler(Alg),mk_alg_state({Alg,Seed})}.
+
+mk_alg_handler(?MODULE = Alg) ->
+ #{ type => Alg,
+ bits => 64,
+ next => fun ?MODULE:rand_plugin_next/1,
+ uniform => fun ?MODULE:rand_plugin_uniform/1,
+ uniform_n => fun ?MODULE:rand_plugin_uniform/2};
+mk_alg_handler(crypto_cache = Alg) ->
+ #{ type => Alg,
+ bits => ?CRYPTO_CACHE_BITS,
+ next => fun ?MODULE:rand_cache_plugin_next/1};
+mk_alg_handler(crypto_aes = Alg) ->
+ #{ type => Alg,
+ bits => ?CRYPTO_AES_BITS,
+ next => fun ?MODULE:rand_plugin_aes_next/1,
+ jump => fun ?MODULE:rand_plugin_aes_jump/1}.
+
+mk_alg_state(?MODULE) ->
+ no_seed;
+mk_alg_state(crypto_cache) ->
CacheBits = ?CRYPTO_CACHE_BITS,
- EnvCacheSize =
- application:get_env(
- crypto, rand_cache_size, CacheBits * 16), % Cache 16 * 8 words
- Bytes = (CacheBits + 7) div 8,
+ BytesPerWord = (CacheBits + 7) div 8,
+ GenBytes =
+ ((rand_cache_size() + (2*BytesPerWord - 1)) div BytesPerWord)
+ * BytesPerWord,
+ {CacheBits, GenBytes, <<>>};
+mk_alg_state({crypto_aes,Seed}) ->
+ %% 16 byte words (128 bit crypto blocks)
+ GenWords = (rand_cache_size() + 31) div 16,
+ Key = crypto:hash(sha256, Seed),
+ {F,Count} = longcount_seed(Seed),
+ {Key,GenWords,F,Count}.
+
+rand_cache_size() ->
+ DefaultCacheSize = 1024,
CacheSize =
- case ((EnvCacheSize + (Bytes - 1)) div Bytes) * Bytes of
- Sz when is_integer(Sz), Bytes =< Sz ->
- Sz;
- _ ->
- Bytes
- end,
- {#{ type => crypto_cache,
- bits => CacheBits,
- next => fun ?MODULE:rand_cache_plugin_next/1},
- {CacheBits, CacheSize, <<>>}}.
+ application:get_env(crypto, rand_cache_size, DefaultCacheSize),
+ if
+ is_integer(CacheSize), 0 =< CacheSize ->
+ CacheSize;
+ true ->
+ DefaultCacheSize
+ end.
rand_plugin_next(Seed) ->
{bytes_to_integer(strong_rand_range(1 bsl 64)), Seed}.
@@ -389,12 +754,97 @@ rand_plugin_uniform(State) ->
rand_plugin_uniform(Max, State) ->
{bytes_to_integer(strong_rand_range(Max)) + 1, State}.
-rand_cache_plugin_next({CacheBits, CacheSize, <<>>}) ->
+
+rand_cache_plugin_next({CacheBits, GenBytes, <<>>}) ->
rand_cache_plugin_next(
- {CacheBits, CacheSize, strong_rand_bytes(CacheSize)});
-rand_cache_plugin_next({CacheBits, CacheSize, Cache}) ->
+ {CacheBits, GenBytes, strong_rand_bytes(GenBytes)});
+rand_cache_plugin_next({CacheBits, GenBytes, Cache}) ->
<<I:CacheBits, NewCache/binary>> = Cache,
- {I, {CacheBits, CacheSize, NewCache}}.
+ {I, {CacheBits, GenBytes, NewCache}}.
+
+
+%% Encrypt 128 bit counter values and use the 58 lowest
+%% encrypted bits as random numbers.
+%%
+%% The 128 bit counter is handled as 4 32 bit words
+%% to avoid bignums. Generate a bunch of numbers
+%% at the time and cache them.
+%%
+-dialyzer({no_improper_lists, rand_plugin_aes_next/1}).
+rand_plugin_aes_next([V|Cache]) ->
+ {V,Cache};
+rand_plugin_aes_next({Key,GenWords,F,Count}) ->
+ rand_plugin_aes_next(Key, GenWords, F, Count);
+rand_plugin_aes_next({Key,GenWords,F,_JumpBase,Count}) ->
+ rand_plugin_aes_next(Key, GenWords, F, Count).
+%%
+rand_plugin_aes_next(Key, GenWords, F, Count) ->
+ {Cleartext,NewCount} = aes_cleartext(<<>>, F, Count, GenWords),
+ Encrypted = crypto:block_encrypt(aes_ecb, Key, Cleartext),
+ [V|Cache] = aes_cache(Encrypted, {Key,GenWords,F,Count,NewCount}),
+ {V,Cache}.
+
+%% A jump advances the counter 2^512 steps; the jump function
+%% is applied to the jump base and then the number of used
+%% numbers from the cache has to be wasted for the jump to be correct
+%%
+rand_plugin_aes_jump({#{type := crypto_aes} = Alg, Cache}) ->
+ {Alg,rand_plugin_aes_jump(fun longcount_jump/1, 0, Cache)}.
+%% Count cached words and subtract their number from jump
+-dialyzer({no_improper_lists, rand_plugin_aes_jump/3}).
+rand_plugin_aes_jump(Jump, J, [_|Cache]) ->
+ rand_plugin_aes_jump(Jump, J + 1, Cache);
+rand_plugin_aes_jump(Jump, J, {Key,GenWords,F,JumpBase, _Count}) ->
+ rand_plugin_aes_jump(Jump, GenWords - J, Key, GenWords, F, JumpBase);
+rand_plugin_aes_jump(Jump, 0, {Key,GenWords,F,JumpBase}) ->
+ rand_plugin_aes_jump(Jump, 0, Key, GenWords, F, JumpBase).
+%%
+rand_plugin_aes_jump(Jump, Skip, Key, GenWords, F, JumpBase) ->
+ Count = longcount_next_count(Skip, Jump(JumpBase)),
+ {Key,GenWords,F,Count}.
+
+rand_plugin_aes_jump_2pow20(Cache) ->
+ rand_plugin_aes_jump(fun longcount_jump_2pow20/1, 0, Cache).
+
+
+longcount_seed(Seed) ->
+ <<X:64, _:6, F:12, S2:58, S1:58, S0:58>> =
+ crypto:hash(sha256, [Seed,<<"Xoroshiro928">>]),
+ {F,rand:exro928_seed([S0,S1,S2|rand:seed58(13, X)])}.
+
+longcount_next_count(0, Count) ->
+ Count;
+longcount_next_count(N, Count) ->
+ longcount_next_count(N - 1, rand:exro928_next_state(Count)).
+
+longcount_next(Count) ->
+ rand:exro928_next(Count).
+
+longcount_jump(Count) ->
+ rand:exro928_jump_2pow512(Count).
+
+longcount_jump_2pow20(Count) ->
+ rand:exro928_jump_2pow20(Count).
+
+
+%% Build binary with counter values to cache
+aes_cleartext(Cleartext, _F, Count, 0) ->
+ {Cleartext,Count};
+aes_cleartext(Cleartext, F, Count, GenWords) ->
+ {{S0,S1}, NewCount} = longcount_next(Count),
+ aes_cleartext(
+ <<Cleartext/binary, F:12, S1:58, S0:58>>,
+ F, NewCount, GenWords - 1).
+
+%% Parse and cache encrypted counter values aka random numbers
+-dialyzer({no_improper_lists, aes_cache/2}).
+aes_cache(<<>>, Cache) ->
+ Cache;
+aes_cache(
+ <<_:(128 - ?CRYPTO_AES_BITS), V:?CRYPTO_AES_BITS, Encrypted/binary>>,
+ Cache) ->
+ [V|aes_cache(Encrypted, Cache)].
+
strong_rand_range(Range) when is_integer(Range), Range > 0 ->
BinRange = int_to_bin(Range),
@@ -412,7 +862,9 @@ strong_rand_float() ->
WholeRange = strong_rand_range(1 bsl 53),
?HALF_DBL_EPSILON * bytes_to_integer(WholeRange).
-rand_uniform(From,To) when is_binary(From), is_binary(To) ->
+-spec rand_uniform(crypto_integer(), crypto_integer()) ->
+ crypto_integer().
+rand_uniform(From, To) when is_binary(From), is_binary(To) ->
case rand_uniform_nif(From,To) of
<<Len:32/integer, MSB, Rest/binary>> when MSB > 127 ->
<<(Len + 1):32/integer, 0, MSB, Rest/binary>>;
@@ -447,116 +899,228 @@ rand_seed(Seed) when is_binary(Seed) ->
rand_seed_nif(_Seed) -> ?nif_stub.
--spec mod_pow(binary()|integer(), binary()|integer(), binary()|integer()) -> binary() | error.
-mod_pow(Base, Exponent, Prime) ->
- case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
- <<0>> -> error;
- R -> R
- end.
+%%%================================================================
+%%%
+%%% Sign/verify
+%%%
+%%%================================================================
+-type pk_sign_verify_algs() :: rsa | dss | ecdsa .
-verify(Algorithm, Type, Data, Signature, Key) ->
- verify(Algorithm, Type, Data, Signature, Key, []).
+-type pk_sign_verify_opts() :: [ rsa_sign_verify_opt() ] .
-%% Backwards compatible
-verify(Algorithm = dss, none, Digest, Signature, Key, Options) ->
- verify(Algorithm, sha, {digest, Digest}, Signature, Key, Options);
-verify(Algorithm, Type, Data, Signature, Key, Options) ->
- case pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options) of
- notsup -> erlang:error(notsup);
- Boolean -> Boolean
- end.
+-type rsa_sign_verify_opt() :: {rsa_padding, rsa_sign_verify_padding()}
+ | {rsa_pss_saltlen, integer()} .
+-type rsa_sign_verify_padding() :: rsa_pkcs1_padding | rsa_pkcs1_pss_padding
+ | rsa_x931_padding | rsa_no_padding
+ .
+
+
+%%%----------------------------------------------------------------
+%%% Sign
+
+-spec sign(Algorithm, DigestType, Msg, Key)
+ -> Signature
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type(),
+ Msg :: binary() | {digest,binary()},
+ Key :: rsa_private()
+ | dss_private()
+ | [ecdsa_private()|ecdsa_params()]
+ | engine_key_ref(),
+ Signature :: binary() .
sign(Algorithm, Type, Data, Key) ->
sign(Algorithm, Type, Data, Key, []).
-%% Backwards compatible
-sign(Algorithm = dss, none, Digest, Key, Options) ->
- sign(Algorithm, sha, {digest, Digest}, Key, Options);
-sign(Algorithm, Type, Data, Key, Options) ->
+
+-spec sign(Algorithm, DigestType, Msg, Key, Options)
+ -> Signature
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type()
+ | none,
+ Msg :: binary() | {digest,binary()},
+ Key :: rsa_private()
+ | dss_private()
+ | [ecdsa_private() | ecdsa_params()]
+ | engine_key_ref(),
+ Options :: pk_sign_verify_opts(),
+ Signature :: binary() .
+
+sign(Algorithm0, Type0, Data, Key, Options) ->
+ {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
case pkey_sign_nif(Algorithm, Type, Data, format_pkey(Algorithm, Key), Options) of
error -> erlang:error(badkey, [Algorithm, Type, Data, Key, Options]);
notsup -> erlang:error(notsup);
Signature -> Signature
end.
+pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
+%%%----------------------------------------------------------------
+%%% Verify
+
+-spec verify(Algorithm, DigestType, Msg, Signature, Key)
+ -> Result
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type(),
+ Msg :: binary() | {digest,binary()},
+ Signature :: binary(),
+ Key :: rsa_private()
+ | dss_private()
+ | [ecdsa_private() | ecdsa_params()]
+ | engine_key_ref(),
+ Result :: boolean().
--type key_id() :: string() | binary() .
--type password() :: string() | binary() .
-
--type engine_key_ref() :: #{engine := engine_ref(),
- key_id := key_id(),
- password => password(),
- term() => term()
- }.
-
--type pk_algs() :: rsa | ecdsa | dss .
--type pk_key() :: engine_key_ref() | [integer() | binary()] .
--type pk_opt() :: list() | rsa_padding() .
-
--spec public_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec public_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec private_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
--spec private_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
+verify(Algorithm, Type, Data, Signature, Key) ->
+ verify(Algorithm, Type, Data, Signature, Key, []).
-public_encrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, false, true) of
- error -> erlang:error(encrypt_failed, [Algorithm, In, Key, Options]);
+-spec verify(Algorithm, DigestType, Msg, Signature, Key, Options)
+ -> Result
+ when Algorithm :: pk_sign_verify_algs(),
+ DigestType :: rsa_digest_type()
+ | dss_digest_type()
+ | ecdsa_digest_type(),
+ Msg :: binary() | {digest,binary()},
+ Signature :: binary(),
+ Key :: rsa_public()
+ | dss_public()
+ | [ecdsa_public() | ecdsa_params()]
+ | engine_key_ref(),
+ Options :: pk_sign_verify_opts(),
+ Result :: boolean().
+
+verify(Algorithm0, Type0, Data, Signature, Key, Options) ->
+ {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
+ case pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options) of
notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-public_encrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- public_encrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+ Boolean -> Boolean
+ end.
-private_decrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, true, false) of
- error -> erlang:error(decrypt_failed, [Algorithm, In, Key, Options]);
- notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-private_decrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- private_decrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+pkey_verify_nif(_Algorithm, _Type, _Data, _Signature, _Key, _Options) -> ?nif_stub.
-private_encrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, true, true) of
- error -> erlang:error(encrypt_failed, [Algorithm, In, Key, Options]);
- notsup -> erlang:error(notsup);
- Out -> Out
- end;
-%% Backwards compatible
-private_encrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- private_encrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
+%% Backwards compatible:
+sign_verify_compatibility(dss, none, Digest) ->
+ {sha, {digest, Digest}};
+sign_verify_compatibility(Algorithm0, Type0, _Digest) ->
+ {Algorithm0, Type0}.
-public_decrypt(Algorithm, In, Key, Options) when is_list(Options) ->
- case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, false, false) of
- error -> erlang:error(decrypt_failed, [Algorithm, In, Key, Options]);
+%%%================================================================
+%%%
+%%% Public/private encrypt/decrypt
+%%%
+%%% Only rsa works so far (although ecdsa | dss should do it)
+%%%================================================================
+-type pk_encrypt_decrypt_algs() :: rsa .
+
+-type pk_encrypt_decrypt_opts() :: [rsa_opt()] | rsa_compat_opts().
+
+-type rsa_compat_opts() :: [{rsa_pad, rsa_padding()}]
+ | rsa_padding() .
+
+-type rsa_padding() :: rsa_pkcs1_padding
+ | rsa_pkcs1_oaep_padding
+ | rsa_sslv23_padding
+ | rsa_x931_padding
+ | rsa_no_padding.
+
+-type rsa_opt() :: {rsa_padding, rsa_padding()}
+ | {signature_md, atom()}
+ | {rsa_mgf1_md, sha}
+ | {rsa_oaep_label, binary()}
+ | {rsa_oaep_md, sha} .
+
+%%%---- Encrypt with public key
+
+-spec public_encrypt(Algorithm, PlainText, PublicKey, Options) ->
+ CipherText when Algorithm :: pk_encrypt_decrypt_algs(),
+ PlainText :: binary(),
+ PublicKey :: rsa_public() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ CipherText :: binary().
+public_encrypt(Algorithm, PlainText, PublicKey, Options) ->
+ pkey_crypt(Algorithm, PlainText, PublicKey, Options, false, true).
+
+%%%---- Decrypt with private key
+
+-spec private_decrypt(Algorithm, CipherText, PrivateKey, Options) ->
+ PlainText when Algorithm :: pk_encrypt_decrypt_algs(),
+ CipherText :: binary(),
+ PrivateKey :: rsa_private() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
+private_decrypt(Algorithm, CipherText, PrivateKey, Options) ->
+ pkey_crypt(Algorithm, CipherText, PrivateKey, Options, true, false).
+
+%%%---- Encrypt with private key
+
+-spec private_encrypt(Algorithm, PlainText, PrivateKey, Options) ->
+ CipherText when Algorithm :: pk_encrypt_decrypt_algs(),
+ PlainText :: binary(),
+ PrivateKey :: rsa_private() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ CipherText :: binary().
+private_encrypt(Algorithm, PlainText, PrivateKey, Options) ->
+ pkey_crypt(Algorithm, PlainText, PrivateKey, Options, true, true).
+
+%%%---- Decrypt with public key
+
+-spec public_decrypt(Algorithm, CipherText, PublicKey, Options) ->
+ PlainText when Algorithm :: pk_encrypt_decrypt_algs(),
+ CipherText :: binary(),
+ PublicKey :: rsa_public() | engine_key_ref(),
+ Options :: pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
+public_decrypt(Algorithm, CipherText, PublicKey, Options) ->
+ pkey_crypt(Algorithm, CipherText, PublicKey, Options, false, false).
+
+%%%---- Call the nif, but fix a compatibility issue first
+
+%% Backwards compatible (rsa_pad -> rsa_padding is handled by the pkey_crypt_nif):
+pkey_crypt(rsa, Text, Key, Padding, PubPriv, EncDec) when is_atom(Padding) ->
+ pkey_crypt(rsa, Text, Key, [{rsa_padding, Padding}], PubPriv, EncDec);
+
+pkey_crypt(Alg, Text, Key, Options, PubPriv, EncDec) ->
+ case pkey_crypt_nif(Alg, Text, format_pkey(Alg,Key), Options, PubPriv, EncDec) of
+ error when EncDec==true -> erlang:error(encrypt_failed, [Alg, Text, Key, Options]);
+ error when EncDec==false -> erlang:error(decrypt_failed, [Alg, Text, Key, Options]);
notsup -> erlang:error(notsup);
Out -> Out
- end;
-%% Backwards compatible
-public_decrypt(Algorithm = rsa, In, Key, Padding) when is_atom(Padding) ->
- public_decrypt(Algorithm, In, Key, [{rsa_padding, Padding}]).
-
-
-%%
-%% XOR - xor to iolists and return a binary
-%% NB doesn't check that they are the same size, just concatenates
-%% them and sends them to the driver
-%%
--spec exor(iodata(), iodata()) -> binary().
+ end.
-exor(Bin1, Bin2) ->
- Data1 = iolist_to_binary(Bin1),
- Data2 = iolist_to_binary(Bin2),
- MaxBytes = max_bytes(),
- exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []).
+pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_stub.
+%%%================================================================
+%%%
+%%%
+%%%
+%%%================================================================
+
+-spec generate_key(Type, Params)
+ -> {PublicKey, PrivKeyOut}
+ when Type :: dh | ecdh | rsa | srp,
+ PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
+ PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | rsa_params() | srp_gen_params()
+ .
generate_key(Type, Params) ->
generate_key(Type, Params, undefined).
+-spec generate_key(Type, Params, PrivKeyIn)
+ -> {PublicKey, PrivKeyOut}
+ when Type :: dh | ecdh | rsa | srp,
+ PublicKey :: dh_public() | ecdh_public() | rsa_public() | srp_public(),
+ PrivKeyIn :: undefined | dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ PrivKeyOut :: dh_private() | ecdh_private() | rsa_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | rsa_params() | srp_comp_params()
+ .
+
generate_key(dh, DHParameters0, PrivateKey) ->
{DHParameters, Len} =
case DHParameters0 of
@@ -603,6 +1167,14 @@ generate_key(ecdh, Curve, PrivKey) ->
evp_generate_key_nif(_Curve) -> ?nif_stub.
+-spec compute_key(Type, OthersPublicKey, MyPrivateKey, Params)
+ -> SharedSecret
+ when Type :: dh | ecdh | srp,
+ SharedSecret :: binary(),
+ OthersPublicKey :: dh_public() | ecdh_public() | srp_public(),
+ MyPrivateKey :: dh_private() | ecdh_private() | {srp_public(),srp_private()},
+ Params :: dh_params() | ecdh_params() | srp_comp_params()
+ .
compute_key(dh, OthersPublicKey, MyPrivateKey, DHParameters) ->
case dh_compute_key_nif(ensure_int_as_bin(OthersPublicKey),
@@ -655,71 +1227,121 @@ compute_key(ecdh, Others, My, Curve) ->
evp_compute_key_nif(_Curve, _OthersBin, _MyBin) -> ?nif_stub.
-%%======================================================================
-%% Engine functions
-%%======================================================================
+
+%%%================================================================
+%%%
+%%% XOR - xor to iolists and return a binary
+%%% NB doesn't check that they are the same size, just concatenates
+%%% them and sends them to the driver
+%%%
+%%%================================================================
+
+-spec exor(iodata(), iodata()) -> binary().
+
+exor(Bin1, Bin2) ->
+ Data1 = iolist_to_binary(Bin1),
+ Data2 = iolist_to_binary(Bin2),
+ MaxBytes = max_bytes(),
+ exor(Data1, Data2, erlang:byte_size(Data1), MaxBytes, []).
+
+
+%%%================================================================
+%%%
+%%% Exponentiation modulo
+%%%
+%%%================================================================
+
+-spec mod_pow(N, P, M) -> Result when N :: binary() | integer(),
+ P :: binary() | integer(),
+ M :: binary() | integer(),
+ Result :: binary() | error .
+mod_pow(Base, Exponent, Prime) ->
+ case mod_exp_nif(ensure_int_as_bin(Base), ensure_int_as_bin(Exponent), ensure_int_as_bin(Prime), 0) of
+ <<0>> -> error;
+ R -> R
+ end.
+
+%%%======================================================================
+%%%
+%%% Engine functions
+%%%
+%%%======================================================================
+
+%%%---- Refering to keys stored in an engine:
+-type key_id() :: string() | binary() .
+-type password() :: string() | binary() .
+
+-type engine_key_ref() :: #{engine := engine_ref(),
+ key_id := key_id(),
+ password => password(),
+ term() => term()
+ }.
+
+%%%---- Commands:
+-type engine_cmnd() :: {unicode:chardata(), unicode:chardata()}.
+
%%----------------------------------------------------------------------
%% Function: engine_get_all_methods/0
%%----------------------------------------------------------------------
-type engine_method_type() :: engine_method_rsa | engine_method_dsa | engine_method_dh |
engine_method_rand | engine_method_ecdh | engine_method_ecdsa |
engine_method_ciphers | engine_method_digests | engine_method_store |
- engine_method_pkey_meths | engine_method_pkey_asn1_meths |
+ engine_method_pkey_meths | engine_method_pkey_asn1_meths |
engine_method_ec.
-type engine_ref() :: term().
--spec engine_get_all_methods() ->
- [engine_method_type()].
+-spec engine_get_all_methods() -> Result when Result :: [engine_method_type()].
engine_get_all_methods() ->
notsup_to_error(engine_get_all_methods_nif()).
%%----------------------------------------------------------------------
%% Function: engine_load/3
%%----------------------------------------------------------------------
--spec engine_load(EngineId::unicode:chardata(),
- PreCmds::[{unicode:chardata(), unicode:chardata()}],
- PostCmds::[{unicode:chardata(), unicode:chardata()}]) ->
- {ok, Engine::engine_ref()} | {error, Reason::term()}.
-engine_load(EngineId, PreCmds, PostCmds) when is_list(PreCmds), is_list(PostCmds) ->
+-spec engine_load(EngineId, PreCmds, PostCmds) ->
+ Result when EngineId::unicode:chardata(),
+ PreCmds::[engine_cmnd()],
+ PostCmds::[engine_cmnd()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+engine_load(EngineId, PreCmds, PostCmds) when is_list(PreCmds),
+ is_list(PostCmds) ->
engine_load(EngineId, PreCmds, PostCmds, engine_get_all_methods()).
%%----------------------------------------------------------------------
%% Function: engine_load/4
%%----------------------------------------------------------------------
--spec engine_load(EngineId::unicode:chardata(),
- PreCmds::[{unicode:chardata(), unicode:chardata()}],
- PostCmds::[{unicode:chardata(), unicode:chardata()}],
- EngineMethods::[engine_method_type()]) ->
- {ok, Engine::term()} | {error, Reason::term()}.
+-spec engine_load(EngineId, PreCmds, PostCmds, EngineMethods) ->
+ Result when EngineId::unicode:chardata(),
+ PreCmds::[engine_cmnd()],
+ PostCmds::[engine_cmnd()],
+ EngineMethods::[engine_method_type()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
engine_load(EngineId, PreCmds, PostCmds, EngineMethods) when is_list(PreCmds),
is_list(PostCmds) ->
try
ok = notsup_to_error(engine_load_dynamic_nif()),
case notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId))) of
{ok, Engine} ->
- ok = engine_load_1(Engine, PreCmds, PostCmds, EngineMethods),
- {ok, Engine};
+ engine_load_1(Engine, PreCmds, PostCmds, EngineMethods);
{error, Error1} ->
{error, Error1}
end
catch
- throw:Error2 ->
- Error2
+ throw:Error2 ->
+ Error2
end.
engine_load_1(Engine, PreCmds, PostCmds, EngineMethods) ->
try
ok = engine_nif_wrapper(engine_ctrl_cmd_strings_nif(Engine, ensure_bin_cmds(PreCmds), 0)),
- ok = engine_nif_wrapper(engine_add_nif(Engine)),
ok = engine_nif_wrapper(engine_init_nif(Engine)),
engine_load_2(Engine, PostCmds, EngineMethods),
- ok
+ {ok, Engine}
catch
- throw:Error ->
- %% The engine couldn't initialise, release the structural reference
- ok = engine_free_nif(Engine),
- throw(Error)
+ throw:Error ->
+ %% The engine couldn't initialise, release the structural reference
+ ok = engine_free_nif(Engine),
+ throw(Error)
end.
engine_load_2(Engine, PostCmds, EngineMethods) ->
@@ -738,18 +1360,18 @@ engine_load_2(Engine, PostCmds, EngineMethods) ->
%%----------------------------------------------------------------------
%% Function: engine_unload/1
%%----------------------------------------------------------------------
--spec engine_unload(Engine::term()) ->
- ok | {error, Reason::term()}.
+-spec engine_unload(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()}.
engine_unload(Engine) ->
engine_unload(Engine, engine_get_all_methods()).
--spec engine_unload(Engine::term(), EngineMethods::[engine_method_type()]) ->
- ok | {error, Reason::term()}.
+-spec engine_unload(Engine, EngineMethods) -> Result when Engine :: engine_ref(),
+ EngineMethods :: [engine_method_type()],
+ Result :: ok | {error, Reason::term()}.
engine_unload(Engine, EngineMethods) ->
try
[ok = engine_nif_wrapper(engine_unregister_nif(Engine, engine_method_atom_to_int(Method))) ||
Method <- EngineMethods],
- ok = engine_nif_wrapper(engine_remove_nif(Engine)),
%% Release the functional reference from engine_init_nif
ok = engine_nif_wrapper(engine_finish_nif(Engine)),
%% Release the structural reference from engine_by_id_nif
@@ -760,19 +1382,63 @@ engine_unload(Engine, EngineMethods) ->
end.
%%----------------------------------------------------------------------
+%% Function: engine_by_id/1
+%%----------------------------------------------------------------------
+-spec engine_by_id(EngineId) -> Result when EngineId :: unicode:chardata(),
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()} .
+engine_by_id(EngineId) ->
+ try
+ notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId)))
+ catch
+ throw:Error ->
+ Error
+ end.
+
+%%----------------------------------------------------------------------
+%% Function: engine_add/1
+%%----------------------------------------------------------------------
+-spec engine_add(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()} .
+engine_add(Engine) ->
+ notsup_to_error(engine_add_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_remove/1
+%%----------------------------------------------------------------------
+-spec engine_remove(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()} .
+engine_remove(Engine) ->
+ notsup_to_error(engine_remove_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_get_id/1
+%%----------------------------------------------------------------------
+-spec engine_get_id(Engine) -> EngineId when Engine :: engine_ref(),
+ EngineId :: unicode:chardata().
+engine_get_id(Engine) ->
+ notsup_to_error(engine_get_id_nif(Engine)).
+
+%%----------------------------------------------------------------------
+%% Function: engine_get_name/1
+%%----------------------------------------------------------------------
+-spec engine_get_name(Engine) -> EngineName when Engine :: engine_ref(),
+ EngineName :: unicode:chardata().
+engine_get_name(Engine) ->
+ notsup_to_error(engine_get_name_nif(Engine)).
+
+%%----------------------------------------------------------------------
%% Function: engine_list/0
%%----------------------------------------------------------------------
--spec engine_list() ->
- [EngineId::binary()].
+-spec engine_list() -> Result when Result :: [EngineId::unicode:chardata()].
engine_list() ->
case notsup_to_error(engine_get_first_nif()) of
{ok, <<>>} ->
[];
{ok, Engine} ->
case notsup_to_error(engine_get_id_nif(Engine)) of
- {ok, <<>>} ->
+ <<>> ->
engine_list(Engine, []);
- {ok, EngineId} ->
+ EngineId ->
engine_list(Engine, [EngineId])
end
end.
@@ -783,9 +1449,9 @@ engine_list(Engine0, IdList) ->
lists:reverse(IdList);
{ok, Engine1} ->
case notsup_to_error(engine_get_id_nif(Engine1)) of
- {ok, <<>>} ->
+ <<>> ->
engine_list(Engine1, IdList);
- {ok, EngineId} ->
+ EngineId ->
engine_list(Engine1, [EngineId |IdList])
end
end.
@@ -793,24 +1459,26 @@ engine_list(Engine0, IdList) ->
%%----------------------------------------------------------------------
%% Function: engine_ctrl_cmd_string/3
%%----------------------------------------------------------------------
--spec engine_ctrl_cmd_string(Engine::term(),
- CmdName::unicode:chardata(),
- CmdArg::unicode:chardata()) ->
- ok | {error, Reason::term()}.
+-spec engine_ctrl_cmd_string(Engine, CmdName, CmdArg) ->
+ Result when Engine::term(),
+ CmdName::unicode:chardata(),
+ CmdArg::unicode:chardata(),
+ Result :: ok | {error, Reason::term()}.
engine_ctrl_cmd_string(Engine, CmdName, CmdArg) ->
engine_ctrl_cmd_string(Engine, CmdName, CmdArg, false).
%%----------------------------------------------------------------------
%% Function: engine_ctrl_cmd_string/4
%%----------------------------------------------------------------------
--spec engine_ctrl_cmd_string(Engine::term(),
- CmdName::unicode:chardata(),
- CmdArg::unicode:chardata(),
- Optional::boolean()) ->
- ok | {error, Reason::term()}.
+-spec engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
+ Result when Engine::term(),
+ CmdName::unicode:chardata(),
+ CmdArg::unicode:chardata(),
+ Optional::boolean(),
+ Result :: ok | {error, Reason::term()}.
engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
- case engine_ctrl_cmd_strings_nif(Engine,
- ensure_bin_cmds([{CmdName, CmdArg}]),
+ case engine_ctrl_cmd_strings_nif(Engine,
+ ensure_bin_cmds([{CmdName, CmdArg}]),
bool_to_int(Optional)) of
ok ->
ok;
@@ -820,6 +1488,97 @@ engine_ctrl_cmd_string(Engine, CmdName, CmdArg, Optional) ->
{error, Error}
end.
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_loaded/2
+%% Special version of load that only uses dynamic engine to load
+%%----------------------------------------------------------------------
+-spec ensure_engine_loaded(EngineId, LibPath) ->
+ Result when EngineId :: unicode:chardata(),
+ LibPath :: unicode:chardata(),
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+ensure_engine_loaded(EngineId, LibPath) ->
+ ensure_engine_loaded(EngineId, LibPath, engine_get_all_methods()).
+
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_loaded/3
+%% Special version of load that only uses dynamic engine to load
+%%----------------------------------------------------------------------
+-spec ensure_engine_loaded(EngineId, LibPath, EngineMethods) ->
+ Result when EngineId :: unicode:chardata(),
+ LibPath :: unicode:chardata(),
+ EngineMethods :: [engine_method_type()],
+ Result :: {ok, Engine::engine_ref()} | {error, Reason::term()}.
+ensure_engine_loaded(EngineId, LibPath, EngineMethods) ->
+ try
+ List = crypto:engine_list(),
+ case lists:member(EngineId, List) of
+ true ->
+ notsup_to_error(engine_by_id_nif(ensure_bin_chardata(EngineId)));
+ false ->
+ ok = notsup_to_error(engine_load_dynamic_nif()),
+ case notsup_to_error(engine_by_id_nif(ensure_bin_chardata(<<"dynamic">>))) of
+ {ok, Engine} ->
+ PreCommands = [{<<"SO_PATH">>, ensure_bin_chardata(LibPath)},
+ {<<"ID">>, ensure_bin_chardata(EngineId)},
+ <<"LOAD">>],
+ ensure_engine_loaded_1(Engine, PreCommands, EngineMethods);
+ {error, Error1} ->
+ {error, Error1}
+ end
+ end
+ catch
+ throw:Error2 ->
+ Error2
+ end.
+
+ensure_engine_loaded_1(Engine, PreCmds, Methods) ->
+ try
+ ok = engine_nif_wrapper(engine_ctrl_cmd_strings_nif(Engine, ensure_bin_cmds(PreCmds), 0)),
+ ok = engine_nif_wrapper(engine_add_nif(Engine)),
+ ok = engine_nif_wrapper(engine_init_nif(Engine)),
+ ensure_engine_loaded_2(Engine, Methods),
+ {ok, Engine}
+ catch
+ throw:Error ->
+ %% The engine couldn't initialise, release the structural reference
+ ok = engine_free_nif(Engine),
+ throw(Error)
+ end.
+
+ensure_engine_loaded_2(Engine, Methods) ->
+ try
+ [ok = engine_nif_wrapper(engine_register_nif(Engine, engine_method_atom_to_int(Method))) ||
+ Method <- Methods],
+ ok
+ catch
+ throw:Error ->
+ %% The engine registration failed, release the functional reference
+ ok = engine_finish_nif(Engine),
+ throw(Error)
+ end.
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_unloaded/1
+%%----------------------------------------------------------------------
+-spec ensure_engine_unloaded(Engine) -> Result when Engine :: engine_ref(),
+ Result :: ok | {error, Reason::term()}.
+ensure_engine_unloaded(Engine) ->
+ ensure_engine_unloaded(Engine, engine_get_all_methods()).
+
+%%----------------------------------------------------------------------
+%% Function: ensure_engine_unloaded/2
+%%----------------------------------------------------------------------
+-spec ensure_engine_unloaded(Engine, EngineMethods) ->
+ Result when Engine :: engine_ref(),
+ EngineMethods :: [engine_method_type()],
+ Result :: ok | {error, Reason::term()}.
+ensure_engine_unloaded(Engine, EngineMethods) ->
+ case engine_remove(Engine) of
+ ok ->
+ engine_unload(Engine, EngineMethods);
+ {error, E} ->
+ {error, E}
+ end.
+
%%--------------------------------------------------------------------
%%% On load
%%--------------------------------------------------------------------
@@ -886,13 +1645,17 @@ path2bin(Path) when is_list(Path) ->
Bin
end.
-%%--------------------------------------------------------------------
+%%%================================================================
+%%%================================================================
+%%%
%%% Internal functions
-%%--------------------------------------------------------------------
+%%%
+%%%================================================================
+
max_bytes() ->
?MAX_BYTES_TO_NIF.
-notsup_to_error(notsup) ->
+notsup_to_error(notsup) ->
erlang:error(notsup);
notsup_to_error(Other) ->
Other.
@@ -948,9 +1711,12 @@ hmac_final_nif(_Context) -> ?nif_stub.
hmac_final_nif(_Context, _MacSize) -> ?nif_stub.
%% CMAC
-
cmac_nif(_Type, _Key, _Data) -> ?nif_stub.
+%% POLY1305
+poly1305_nif(_Key, _Data) -> ?nif_stub.
+
+
%% CIPHERS --------------------------------------------------------------------
block_crypt_nif(_Type, _Key, _Ivec, _Text, _IsEncrypt) -> ?nif_stub.
@@ -970,16 +1736,11 @@ check_des3_key(Key) ->
%% AES - in Galois/Counter Mode (GCM)
%%
%% The default tag length is EVP_GCM_TLS_TAG_LEN(16),
-aes_gcm_encrypt(Key, Ivec, AAD, In) ->
- aes_gcm_encrypt(Key, Ivec, AAD, In, 16).
-aes_gcm_encrypt(_Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
-aes_gcm_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
+aead_encrypt(Type=aes_ccm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 12);
+aead_encrypt(Type=aes_gcm, Key, Ivec, AAD, In) -> aead_encrypt(Type, Key, Ivec, AAD, In, 16).
-%%
-%% Chacha20/Ppoly1305
-%%
-chacha20_poly1305_encrypt(_Key, _Ivec, _AAD, _In) -> ?nif_stub.
-chacha20_poly1305_decrypt(_Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
+aead_encrypt(_Type, _Key, _Ivec, _AAD, _In, _TagLength) -> ?nif_stub.
+aead_decrypt(_Type, _Key, _Ivec, _AAD, _In, _Tag) -> ?nif_stub.
%%
%% AES - with 256 bit key in infinite garble extension mode (IGE)
@@ -1005,27 +1766,25 @@ do_stream_encrypt({aes_ctr, State0}, Data) ->
{{aes_ctr, State}, Cipher};
do_stream_encrypt({rc4, State0}, Data) ->
{State, Cipher} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Cipher}.
+ {{rc4, State}, Cipher};
+do_stream_encrypt({chacha20, State0}, Data) ->
+ {State, Cipher} = chacha20_stream_encrypt(State0, Data),
+ {{chacha20, State}, Cipher}.
do_stream_decrypt({aes_ctr, State0}, Data) ->
{State, Text} = aes_ctr_stream_decrypt(State0, Data),
{{aes_ctr, State}, Text};
do_stream_decrypt({rc4, State0}, Data) ->
{State, Text} = rc4_encrypt_with_state(State0, Data),
- {{rc4, State}, Text}.
+ {{rc4, State}, Text};
+do_stream_decrypt({chacha20, State0}, Data) ->
+ {State, Cipher} = chacha20_stream_decrypt(State0, Data),
+ {{chacha20, State}, Cipher}.
%%
%% AES - in counter mode (CTR) with state maintained for multi-call streaming
%%
--type ctr_state() :: { iodata(), binary(), binary(), integer() } | binary().
-
--spec aes_ctr_stream_init(iodata(), binary()) -> ctr_state().
--spec aes_ctr_stream_encrypt(ctr_state(), binary()) ->
- { ctr_state(), binary() }.
--spec aes_ctr_stream_decrypt(ctr_state(), binary()) ->
- { ctr_state(), binary() }.
-
aes_ctr_stream_init(_Key, _IVec) -> ?nif_stub.
aes_ctr_stream_encrypt(_State, _Data) -> ?nif_stub.
aes_ctr_stream_decrypt(_State, _Cipher) -> ?nif_stub.
@@ -1036,6 +1795,13 @@ aes_ctr_stream_decrypt(_State, _Cipher) -> ?nif_stub.
rc4_set_key(_Key) -> ?nif_stub.
rc4_encrypt_with_state(_State, _Data) -> ?nif_stub.
+%%
+%% CHACHA20 - stream cipher
+%%
+chacha20_stream_init(_Key, _IVec) -> ?nif_stub.
+chacha20_stream_encrypt(_State, _Data) -> ?nif_stub.
+chacha20_stream_decrypt(_State, _Data) -> ?nif_stub.
+
%% Secure remote password -------------------------------------------------------------------
user_srp_gen_key(Private, Generator, Prime) ->
@@ -1102,11 +1868,6 @@ srp_user_secret_nif(_A, _U, _B, _Multiplier, _Generator, _Exponent, _Prime) -> ?
srp_value_B_nif(_Multiplier, _Verifier, _Generator, _Exponent, _Prime) -> ?nif_stub.
-%% Digital signatures --------------------------------------------------------------------
-
-pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
-pkey_verify_nif(_Algorithm, _Type, _Data, _Signature, _Key, _Options) -> ?nif_stub.
-
%% Public Keys --------------------------------------------------------------------
%% RSA Rivest-Shamir-Adleman functions
%%
@@ -1128,13 +1889,20 @@ ec_key_generate(_Curve, _Key) -> ?nif_stub.
ecdh_compute_key_nif(_Others, _Curve, _My) -> ?nif_stub.
+-spec ec_curves() -> [EllipticCurve] when EllipticCurve :: ec_named_curve() | edwards_curve() .
+
ec_curves() ->
crypto_ec_curves:curves().
+-spec ec_curve(CurveName) -> ExplicitCurve when CurveName :: ec_named_curve(),
+ ExplicitCurve :: ec_explicit_curve() .
ec_curve(X) ->
crypto_ec_curves:curve(X).
+-spec privkey_to_pubkey(Type, EnginePrivateKeyRef) -> PublicKey when Type :: rsa | dss,
+ EnginePrivateKeyRef :: engine_key_ref(),
+ PublicKey :: rsa_public() | dss_public() .
privkey_to_pubkey(Alg, EngineMap) when Alg == rsa; Alg == dss; Alg == ecdsa ->
try privkey_to_pubkey_nif(Alg, format_pkey(Alg,EngineMap))
of
@@ -1148,7 +1916,7 @@ privkey_to_pubkey(Alg, EngineMap) when Alg == rsa; Alg == dss; Alg == ecdsa ->
error:notsup ->
{error, notsup}
end.
-
+
privkey_to_pubkey_nif(_Alg, _EngineMap) -> ?nif_stub.
@@ -1160,10 +1928,16 @@ term_to_nif_prime({prime_field, Prime}) ->
{prime_field, ensure_int_as_bin(Prime)};
term_to_nif_prime(PrimeField) ->
PrimeField.
+
term_to_nif_curve({A, B, Seed}) ->
{ensure_int_as_bin(A), ensure_int_as_bin(B), Seed}.
+
nif_curve_params({PrimeField, Curve, BasePoint, Order, CoFactor}) ->
- {term_to_nif_prime(PrimeField), term_to_nif_curve(Curve), ensure_int_as_bin(BasePoint), ensure_int_as_bin(Order), ensure_int_as_bin(CoFactor)};
+ {term_to_nif_prime(PrimeField),
+ term_to_nif_curve(Curve),
+ ensure_int_as_bin(BasePoint),
+ ensure_int_as_bin(Order),
+ ensure_int_as_bin(CoFactor)};
nif_curve_params(Curve) when is_atom(Curve) ->
%% named curve
case Curve of
@@ -1203,6 +1977,7 @@ int_to_bin_neg(-1, Ds=[MSB|_]) when MSB >= 16#80 ->
int_to_bin_neg(X,Ds) ->
int_to_bin_neg(X bsr 8, [(X band 255)|Ds]).
+-spec bytes_to_integer(binary()) -> integer() .
bytes_to_integer(Bin) ->
bin_to_int(Bin).
@@ -1250,9 +2025,6 @@ format_pwd(M) -> M.
%%--------------------------------------------------------------------
%%
--type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'.
-
-pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_stub.
%% large integer in a binary with 32bit length
%% MP representaion (SSH2)
@@ -1314,6 +2086,7 @@ engine_unregister_nif(_Engine, _EngineMethod) -> ?nif_stub.
engine_get_first_nif() -> ?nif_stub.
engine_get_next_nif(_Engine) -> ?nif_stub.
engine_get_id_nif(_Engine) -> ?nif_stub.
+engine_get_name_nif(_Engine) -> ?nif_stub.
engine_get_all_methods_nif() -> ?nif_stub.
%%--------------------------------------------------------------------
@@ -1371,7 +2144,7 @@ get_test_engine() ->
Type = erlang:system_info(system_architecture),
LibDir = filename:join([code:priv_dir(crypto), "lib"]),
ArchDir = filename:join([LibDir, Type]),
- case filelib:is_dir(ArchDir) of
+ case filelib:is_dir(ArchDir) of
true -> check_otp_test_engine(ArchDir);
false -> check_otp_test_engine(LibDir)
end.
@@ -1380,7 +2153,7 @@ check_otp_test_engine(LibDir) ->
case filelib:wildcard("otp_test_engine*", LibDir) of
[] ->
{error, notexist};
- [LibName] ->
+ [LibName|_] -> % In case of Valgrind there could be more than one
LibPath = filename:join(LibDir,LibName),
case filelib:is_file(LibPath) of
true ->
@@ -1389,4 +2162,3 @@ check_otp_test_engine(LibDir) ->
{error, notexist}
end
end.
-
diff --git a/lib/crypto/src/crypto_ec_curves.erl b/lib/crypto/src/crypto_ec_curves.erl
index 9602a7e24b..a0a2f99601 100644
--- a/lib/crypto/src/crypto_ec_curves.erl
+++ b/lib/crypto/src/crypto_ec_curves.erl
@@ -3,41 +3,7 @@
-export([curve/1, curves/0]).
curves() ->
- CryptoSupport = crypto:supports(),
- PubKeys = proplists:get_value(public_keys, CryptoSupport),
- HasEC = proplists:get_bool(ecdh, PubKeys),
- HasGF2m = proplists:get_bool(ec_gf2m, PubKeys),
- FIPSMode = crypto:info_fips() == enabled,
- prime_curves(HasEC, FIPSMode) ++ characteristic_two_curves(HasGF2m, FIPSMode).
-
-
-prime_curves(true, true) ->
- [secp160k1,secp160r1,secp160r2,
- secp192r1,secp192k1,secp224k1,secp224r1,secp256k1,secp256r1,secp384r1,
- secp521r1,prime192v1,prime192v2,prime192v3,prime239v1,prime239v2,prime239v3,
- prime256v1,wtls7,wtls9,wtls12,
- brainpoolP160r1,brainpoolP160t1,brainpoolP192r1,brainpoolP192t1,
- brainpoolP224r1,brainpoolP224t1,brainpoolP256r1,brainpoolP256t1,
- brainpoolP320r1,brainpoolP320t1,brainpoolP384r1,brainpoolP384t1,
- brainpoolP512r1,brainpoolP512t1];
-prime_curves(true, false) ->
- [secp112r1,secp112r2,secp128r1,secp128r2,wtls6,wtls8]
- ++ prime_curves(true, true);
-prime_curves(_, _) ->
- [].
-
-characteristic_two_curves(true, true) ->
- [sect163k1,sect163r1,
- sect163r2,sect193r1,sect193r2,sect233k1,sect233r1,sect239k1,sect283k1,
- sect283r1,sect409k1,sect409r1,sect571k1,sect571r1,c2pnb163v1,c2pnb163v2,
- c2pnb163v3,c2pnb176v1,c2tnb191v1,c2tnb191v2,c2tnb191v3,c2pnb208w1,c2tnb239v1,
- c2tnb239v2,c2tnb239v3,c2pnb272w1,c2pnb304w1,c2tnb359v1,c2pnb368w1,c2tnb431r1,
- wtls3,wtls5,wtls10,wtls11];
-characteristic_two_curves(true, _) ->
- [sect113r1,sect113r2,sect131r1,sect131r2,wtls1,wtls4,ipsec3,ipsec4]
- ++ characteristic_two_curves(true, true);
-characteristic_two_curves(_, _) ->
- [].
+ proplists:get_value(curves, crypto:supports()) -- [x25519,x448].
curve(secp112r1) ->
{
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index ebb55c4a34..0b878f2e5c 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -31,6 +31,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app,
+ {group, api_errors},
appup,
{group, fips},
{group, non_fips},
@@ -50,6 +51,10 @@ groups() ->
{group, sha256},
{group, sha384},
{group, sha512},
+ {group, sha3_224},
+ {group, sha3_256},
+ {group, sha3_384},
+ {group, sha3_512},
{group, rsa},
{group, dss},
{group, ecdsa},
@@ -74,8 +79,11 @@ groups() ->
{group, rc2_cbc},
{group, rc4},
{group, aes_ctr},
+ {group, aes_ccm},
{group, aes_gcm},
{group, chacha20_poly1305},
+ {group, chacha20},
+ {group, poly1305},
{group, aes_cbc}]},
{fips, [], [{group, no_md4},
{group, no_md5},
@@ -109,8 +117,10 @@ groups() ->
{group, no_rc2_cbc},
{group, no_rc4},
{group, aes_ctr},
+ {group, aes_ccm},
{group, aes_gcm},
{group, no_chacha20_poly1305},
+ {group, no_chacha20},
{group, aes_cbc}]},
{md4, [], [hash]},
{md5, [], [hash, hmac]},
@@ -120,6 +130,10 @@ groups() ->
{sha256, [], [hash, hmac]},
{sha384, [], [hash, hmac]},
{sha512, [], [hash, hmac]},
+ {sha3_224, [], [hash, hmac]},
+ {sha3_256, [], [hash, hmac]},
+ {sha3_384, [], [hash, hmac]},
+ {sha3_512, [], [hash, hmac]},
{rsa, [], [sign_verify,
public_encrypt,
private_encrypt,
@@ -133,7 +147,7 @@ groups() ->
]},
{dh, [], [generate_compute,
compute_bug]},
- {ecdh, [], [compute, generate]},
+ {ecdh, [], [generate_all_supported, compute, generate]},
{srp, [], [generate_compute]},
{des_cbc, [], [block]},
{des_cfb, [], [block]},
@@ -154,8 +168,11 @@ groups() ->
{blowfish_ofb64,[], [block]},
{rc4, [], [stream]},
{aes_ctr, [], [stream]},
+ {aes_ccm, [], [aead]},
{aes_gcm, [], [aead]},
{chacha20_poly1305, [], [aead]},
+ {chacha20, [], [stream]},
+ {poly1305, [], [poly1305]},
{aes_cbc, [], [block]},
{no_md4, [], [no_support, no_hash]},
{no_md5, [], [no_support, no_hash, no_hmac]},
@@ -169,8 +186,10 @@ groups() ->
{no_blowfish_ofb64, [], [no_support, no_block]},
{no_aes_ige256, [], [no_support, no_block]},
{no_chacha20_poly1305, [], [no_support, no_aead]},
+ {no_chacha20, [], [no_support, no_stream_ivec]},
{no_rc2_cbc, [], [no_support, no_block]},
- {no_rc4, [], [no_support, no_stream]}
+ {no_rc4, [], [no_support, no_stream]},
+ {api_errors, [], [api_errors_ecdh]}
].
%%-------------------------------------------------------------------
@@ -205,7 +224,7 @@ init_per_suite(Config) ->
Config
end
catch _:_ ->
- {skip, "Crypto did not start"}
+ {fail, "Crypto did not start"}
end.
end_per_suite(_Config) ->
@@ -238,6 +257,8 @@ init_per_group(non_fips, Config) ->
_NotEnabled ->
NonFIPSConfig
end;
+init_per_group(api_errors, Config) ->
+ Config;
init_per_group(GroupName, Config) ->
case atom_to_list(GroupName) of
"no_" ++ TypeStr ->
@@ -352,6 +373,20 @@ cmac(Config) when is_list(Config) ->
lists:foreach(fun cmac_check/1, Pairs),
lists:foreach(fun cmac_check/1, cmac_iolistify(Pairs)).
%%--------------------------------------------------------------------
+poly1305() ->
+ [{doc, "Test poly1305 function"}].
+poly1305(Config) ->
+ lists:foreach(
+ fun({Key, Txt, Expect}) ->
+ case crypto:poly1305(Key,Txt) of
+ Expect ->
+ ok;
+ Other ->
+ ct:fail({{crypto, poly1305, [Key, Txt]}, {expected, Expect}, {got, Other}})
+ end
+ end, proplists:get_value(poly1305, Config)).
+
+%%--------------------------------------------------------------------
block() ->
[{doc, "Test block ciphers"}].
block(Config) when is_list(Config) ->
@@ -393,12 +428,18 @@ no_block(Config) when is_list(Config) ->
no_aead() ->
[{doc, "Test disabled aead ciphers"}].
no_aead(Config) when is_list(Config) ->
- [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag} | _] =
- lazy_eval(proplists:get_value(aead, Config)),
- EncryptArgs = [Type, Key, Nonce, {AAD, PlainText}],
+ EncArg4 =
+ case lazy_eval(proplists:get_value(aead, Config)) of
+ [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, TagLen, _Info} | _] ->
+ {AAD, PlainText, TagLen};
+ [{Type, Key, PlainText, Nonce, AAD, CipherText, CipherTag, _Info} | _] ->
+ {AAD, PlainText}
+ end,
+ EncryptArgs = [Type, Key, Nonce, EncArg4],
DecryptArgs = [Type, Key, Nonce, {AAD, CipherText, CipherTag}],
notsup(fun crypto:block_encrypt/4, EncryptArgs),
notsup(fun crypto:block_decrypt/4, DecryptArgs).
+
%%--------------------------------------------------------------------
stream() ->
[{doc, "Test stream ciphers"}].
@@ -416,6 +457,13 @@ no_stream(Config) when is_list(Config) ->
notsup(fun crypto:stream_init/2, [Type, <<"Key">>]).
%%--------------------------------------------------------------------
+no_stream_ivec() ->
+ [{doc, "Test disabled stream ciphers that uses ivec"}].
+no_stream_ivec(Config) when is_list(Config) ->
+ Type = ?config(type, Config),
+ notsup(fun crypto:stream_init/3, [Type, <<"Key">>, <<"Ivec">>]).
+
+%%--------------------------------------------------------------------
aead() ->
[{doc, "Test AEAD ciphers"}].
aead(Config) when is_list(Config) ->
@@ -447,14 +495,14 @@ sign_verify(Config) when is_list(Config) ->
public_encrypt() ->
[{doc, "Test public_encrypt/decrypt "}].
public_encrypt(Config) when is_list(Config) ->
- Params = proplists:get_value(pub_priv_encrypt, Config),
+ Params = proplists:get_value(pub_pub_encrypt, Config, []),
lists:foreach(fun do_public_encrypt/1, Params).
%%--------------------------------------------------------------------
private_encrypt() ->
[{doc, "Test private_encrypt/decrypt functions. "}].
private_encrypt(Config) when is_list(Config) ->
- Params = proplists:get_value(pub_priv_encrypt, Config),
+ Params = proplists:get_value(pub_priv_encrypt, Config, []),
lists:foreach(fun do_private_encrypt/1, Params).
%%--------------------------------------------------------------------
@@ -466,7 +514,7 @@ generate_compute(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
compute_bug() ->
[{doc, "Test that it works even if the Secret is smaller than expected"}].
-compute_bug(Config) ->
+compute_bug(_Config) ->
ExpectedSecret = <<118,89,171,16,156,18,156,103,189,134,130,49,28,144,111,241,247,82,79,32,228,11,209,141,119,176,251,80,105,143,235,251,203,121,223,211,129,3,233,133,45,2,31,157,24,111,5,75,153,66,135,185,128,115,229,178,216,39,73,52,80,151,8,241,34,52,226,71,137,167,53,48,59,224,175,154,89,110,76,83,24,117,149,21,72,6,186,78,149,74,188,56,98,244,30,77,108,248,88,194,195,237,23,51,20,242,254,123,21,12,209,74,217,168,230,65,7,60,211,139,128,239,234,153,22,229,180,59,159,121,41,156,121,200,177,130,163,162,54,224,93,1,94,11,177,254,118,28,156,26,116,10,207,145,219,166,214,189,214,230,221,170,228,15,69,88,31,68,94,255,113,58,49,82,86,192,248,176,131,133,39,186,194,172,206,84,184,16,66,68,153,128,178,227,27,118,52,130,122,92,24,222,102,195,221,207,255,13,152,175,65,32,167,84,54,244,243,109,244,18,234,16,159,224,188,2,106,123,27,17,131,171,226,34,111,251,62,119,155,124,221,124,254,62,97,167,1,105,116,98,98,19,197,30,72,180,79,221,100,134,120,117,124,85,73,132,224,223,222,41,155,137,218,130,238,237,157,161,134,150,69,206,91,141,17,89,120,218,235,229,37,150,76,197,7,157,56,144,42,203,137,100,200,72,141,194,239,1,67,236,238,183,48,214,75,76,108,235,3,237,67,40,137,45,182,236,246,37,116,103,144,237,142,211,88,233,11,24,21,218,41,245,250,51,130,250,104,74,189,17,69,145,70,50,50,215,253,155,10,128,41,114,185,211,82,164,72,92,17,145,104,66,6,140,226,80,43,62,1,166,216,153,118,96,15,147,126,137,118,191,192,75,149,241,206,18,92,17,154,215,219,18,6,139,190,103,210,156,184,29,224,213,157,60,112,189,104,220,125,40,186,50,119,17,143,136,149,38,74,107,21,192,59,61,59,42,231,144,59,175,3,176,87,23,16,122,54,31,82,34,230,211,44,81,41,47,86,37,228,175,130,148,88,136,131,254,241,202,99,199,175,1,141,215,124,155,120,43,141,89,11,140,120,141,29,35,82,219,155,204,75,12,66,241,253,33,250,84,24,85,68,13,80,85,142,227,34,139,26,146,24>>,
OthersPublicKey = 635619632099733175381667940709387641100492974601603060984753028943194386334921787463327680809776598322996634648015962954045728174069768874873236397421720142610982770302060309928552098274817978606093380781524199673890631795310930242601197479471368910519338301177304682162189801040921618559902948819107531088646753320486728060005223263561551402855338732899079439899705951063999951507319258050864346087428042978411873495523439615429804957374639092580169417598963105885529553632847023899713490485619763926900318508906706745060947269748612049634207985438016935262521715769812475329234748426647554362991758104620357149045960316987533503707855364806010494793980069245562784050236811004893018183726397041999426883788660276453352521120006817370050691205529335316794439089316232980047277245051173281601960196573681285904611182521967067911862467395705665888521948321299521549941618586026714676885890192323289343756440666276226084448279082483536164085883288884231665240707495770544705648564889889198060417915693315346959170105413290799314390963124178046425737828369059171472978294050322371452255088799865552038756937873388385970088906560408959959429398326288750834357514847891423941047433478384621074116184703014798814515161475596555032391555842,
MyPrivateKey = 387759582879975726965038486537011291913744975764132199838375902680222019267527675651273586836110220500657652661706223760165097275862806031329642160439090779625708664007910974206651834216043397115514725827856461492311499129200688538220719685637154290305617686974719521885238198226075381217068175824097878445476010193039590876624464274744156624589136789060427283492343902761765833713520850870233407503430180028104167029073459918756981323130062648615262139444306321256382009848217866984408901761817655567071716275177768316006340055589170095799943481591033461616307776069027985761229636731465482676467627154100912586936231051371168178564599296638350391246393336702334311781595616786107810962134407697848002331639021101685320844880636050048769216986088652236979636019052557155807310341483407890060105599892252118584570558049301477535792498672552850760356632076013402382600669875697284264329434950712239302528367835155163504374877787288116104285944993818319105835423479332617802010952731990182088670508346704423006877514817882782443833997288652405892920173712497948376815825396272381214976859009518623799156300136570204539240675245115597412280078940442452936425561984312708387584800789375684525365060589104566195610526570099527133097201479,
@@ -506,6 +554,33 @@ compute(Config) when is_list(Config) ->
Gen = proplists:get_value(compute, Config),
lists:foreach(fun do_compute/1, Gen).
%%--------------------------------------------------------------------
+generate_all_supported() ->
+ [{doc, " Test that all curves from crypto:ec_curves/0 returns two binaries"}].
+generate_all_supported(_Config) ->
+ Results =
+ [try
+ crypto:generate_key(ecdh, C)
+ of
+ {B1,B2} when is_binary(B1) and is_binary(B2) ->
+ %% That is, seems like it works as expected.
+ {ok,C};
+ Err ->
+ ct:log("ERROR: Curve ~p generated ~p", [C,Err]),
+ {error,{C,Err}}
+ catch
+ Cls:Err:Stack ->
+ ct:log("ERROR: Curve ~p exception ~p:~p~n~p", [C,Cls,Err,Stack]),
+ {error,{C,{Cls,Err}}}
+ end
+ || C <- crypto:ec_curves()
+ ],
+ OK = [C || {ok,C} <- Results],
+ ct:log("Ok (len=~p): ~p", [length(OK), OK]),
+ false = lists:any(fun({error,_}) -> true;
+ (_) -> false
+ end, Results).
+
+%%--------------------------------------------------------------------
generate() ->
[{doc, " Test crypto:generate_key"}].
generate(Config) when is_list(Config) ->
@@ -571,31 +646,29 @@ hash_increment(State0, [Increment | Rest]) ->
hmac(_, [],[],[]) ->
ok;
hmac(sha = Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data, 20) of
- Expected ->
- ok;
- Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
+ call_crypto_hmac([Type, Key, Data, 20], Type, Expected),
hmac(Type, Keys, Rest, Expects);
-
hmac(Type, [Key | Keys], [ <<"Test With Truncation">> = Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data, 16) of
- Expected ->
- ok;
- Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
+ call_crypto_hmac([Type, Key, Data, 16], Type, Expected),
hmac(Type, Keys, Rest, Expects);
-
hmac(Type, [Key | Keys], [Data| Rest], [Expected | Expects]) ->
- case crypto:hmac(Type, Key, Data) of
+ call_crypto_hmac([Type, Key, Data], Type, Expected),
+ hmac(Type, Keys, Rest, Expects).
+
+call_crypto_hmac(Args, Type, Expected) ->
+ try apply(crypto, hmac, Args)
+ of
Expected ->
ok;
Other ->
- ct:fail({{crypto, hmac, [Type, Key, Data]}, {expected, Expected}, {got, Other}})
- end,
- hmac(Type, Keys, Rest, Expects).
+ ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,Other}})
+ catch
+ error:notsup ->
+ ct:fail("HMAC ~p not supported", [Type]);
+ Class:Cause ->
+ ct:fail({{crypto,hmac,Args}, {expected,Expected}, {got,{Class,Cause}}})
+ end.
+
hmac_increment(Type) ->
Key = hmac_key(Type),
@@ -726,16 +799,33 @@ stream_cipher({Type, Key, IV, PlainText}) ->
ok;
Other ->
ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other}})
+ end;
+stream_cipher({Type, Key, IV, PlainText, CipherText}) ->
+ Plain = iolist_to_binary(PlainText),
+ State = crypto:stream_init(Type, Key, IV),
+ case crypto:stream_encrypt(State, PlainText) of
+ {_, CipherText} ->
+ ok;
+ {_, Other0} ->
+ ct:fail({{crypto, stream_encrypt, [State, Type, Key, IV, Plain]}, {expected, CipherText}, {got, Other0}})
+ end,
+ case crypto:stream_decrypt(State, CipherText) of
+ {_, Plain} ->
+ ok;
+ Other1 ->
+ ct:fail({{crypto, stream_decrypt, [State, CipherText]}, {expected, PlainText}, {got, Other1}})
end.
stream_cipher_incment({Type, Key, PlainTexts}) ->
State = crypto:stream_init(Type, Key),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+ stream_cipher_incment_loop(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
stream_cipher_incment({Type, Key, IV, PlainTexts}) ->
State = crypto:stream_init(Type, Key, IV),
- stream_cipher_incment(State, State, PlainTexts, [], iolist_to_binary(PlainTexts)).
+ stream_cipher_incment_loop(State, State, PlainTexts, [], iolist_to_binary(PlainTexts));
+stream_cipher_incment({Type, Key, IV, PlainTexts, _CipherText}) ->
+ stream_cipher_incment({Type, Key, IV, PlainTexts}).
-stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
+stream_cipher_incment_loop(_State, OrigState, [], Acc, Plain) ->
CipherText = iolist_to_binary(lists:reverse(Acc)),
case crypto:stream_decrypt(OrigState, CipherText) of
{_, Plain} ->
@@ -743,38 +833,55 @@ stream_cipher_incment(_State, OrigState, [], Acc, Plain) ->
Other ->
ct:fail({{crypto, stream_decrypt, [OrigState, CipherText]}, {expected, Plain}, {got, Other}})
end;
-stream_cipher_incment(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
+stream_cipher_incment_loop(State0, OrigState, [PlainText | PlainTexts], Acc, Plain) ->
{State, CipherText} = crypto:stream_encrypt(State0, PlainText),
- stream_cipher_incment(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
+ stream_cipher_incment_loop(State, OrigState, PlainTexts, [CipherText | Acc], Plain).
-aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag}) ->
+aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, Info}) ->
Plain = iolist_to_binary(PlainText),
case crypto:block_encrypt(Type, Key, IV, {AAD, Plain}) of
{CipherText, CipherTag} ->
ok;
Other0 ->
- ct:fail({{crypto, block_encrypt, [Plain, PlainText]}, {expected, {CipherText, CipherTag}}, {got, Other0}})
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, {CipherText, CipherTag}},
+ {got, Other0}})
end,
case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, CipherTag}) of
Plain ->
ok;
Other1 ->
- ct:fail({{crypto, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}})
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
end;
-aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen}) ->
+aead_cipher({Type, Key, PlainText, IV, AAD, CipherText, CipherTag, TagLen, Info}) ->
<<TruncatedCipherTag:TagLen/binary, _/binary>> = CipherTag,
Plain = iolist_to_binary(PlainText),
case crypto:block_encrypt(Type, Key, IV, {AAD, Plain, TagLen}) of
{CipherText, TruncatedCipherTag} ->
ok;
Other0 ->
- ct:fail({{crypto, block_encrypt, [Plain, PlainText]}, {expected, {CipherText, TruncatedCipherTag}}, {got, Other0}})
+ ct:fail({{crypto,
+ block_encrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag}, {taglen,TagLen}]},
+ {expected, {CipherText, TruncatedCipherTag}},
+ {got, Other0}})
end,
case crypto:block_decrypt(Type, Key, IV, {AAD, CipherText, TruncatedCipherTag}) of
Plain ->
ok;
Other1 ->
- ct:fail({{crypto, block_decrypt, [CipherText]}, {expected, Plain}, {got, Other1}})
+ ct:fail({{crypto,
+ block_decrypt,
+ [{info,Info}, {key,Key}, {pt,PlainText}, {iv,IV}, {aad,AAD}, {ct,CipherText}, {tag,CipherTag},
+ {truncated,TruncatedCipherTag}]},
+ {expected, Plain},
+ {got, Other1}})
end.
do_sign_verify({Type, Hash, Public, Private, Msg}) ->
@@ -811,7 +918,7 @@ do_sign_verify({Type, Hash, Public, Private, Msg, Options}) ->
error:notsup when NotSupLow == true,
is_integer(LibVer),
LibVer < 16#10001000 ->
- %% Thoose opts where introduced in 1.0.1
+ %% Those opts where introduced in 1.0.1
ct:log("notsup but OK in old cryptolib crypto:sign(~p, ~p, ..., ..., ..., ~p)",
[Type,Hash,Options]),
true;
@@ -837,25 +944,48 @@ negative_verify(Type, Hash, Msg, Signature, Public, Options) ->
end.
do_public_encrypt({Type, Public, Private, Msg, Padding}) ->
- PublicEcn = (catch crypto:public_encrypt(Type, Msg, Public, Padding)),
- case crypto:private_decrypt(Type, PublicEcn, Private, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:public_encrypt(Type, Msg, Public, Padding)
+ of
+ PublicEcn ->
+ try
+ crypto:private_decrypt(Type, PublicEcn, Private, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ CC:EE ->
+ ct:fail({{crypto, private_decrypt, [Type, PublicEcn, Private, Padding]}, {expected, Msg}, {got, {CC,EE}}})
+ end
+ catch
+ CC:EE ->
+ ct:fail({{crypto, public_encrypt, [Type, Msg, Public, Padding]}, {got, {CC,EE}}})
end.
-do_private_encrypt({_Type, _Public, _Private, _Msg, rsa_pkcs1_oaep_padding}) ->
- ok; %% Not supported by openssl
+
do_private_encrypt({Type, Public, Private, Msg, Padding}) ->
- PrivEcn = (catch crypto:private_encrypt(Type, Msg, Private, Padding)),
- case crypto:public_decrypt(Type, PrivEcn, Public, Padding) of
- Msg ->
- ok;
- Other ->
- ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ try
+ crypto:private_encrypt(Type, Msg, Private, Padding)
+ of
+ PrivEcn ->
+ try
+ crypto:public_decrypt(Type, PrivEcn, Public, Padding)
+ of
+ Msg ->
+ ok;
+ Other ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, Other}})
+ catch
+ CC:EE ->
+ ct:fail({{crypto, public_decrypt, [Type, PrivEcn, Public, Padding]}, {expected, Msg}, {got, {CC,EE}}})
+ end
+ catch
+ CC:EE ->
+ ct:fail({{crypto, private_encrypt, [Type, Msg, Private, Padding]}, {got, {CC,EE}}})
end.
-
+
do_generate_compute({srp = Type, UserPrivate, UserGenParams, UserComParams,
HostPublic, HostPrivate, HostGenParams, HostComParam, SessionKey}) ->
{UserPublic, UserPrivate} = crypto:generate_key(Type, UserGenParams, UserPrivate),
@@ -924,6 +1054,8 @@ hexstr2bin(S) when is_binary(S) ->
hexstr2bin(S) ->
list_to_binary(hexstr2list(S)).
+hexstr2list([$ |T]) ->
+ hexstr2list(T);
hexstr2list([X,Y|T]) ->
[mkint(X)*16 + mkint(Y) | hexstr2list(T)];
hexstr2list([]) ->
@@ -935,6 +1067,14 @@ mkint(C) when $A =< C, C =< $F ->
mkint(C) when $a =< C, C =< $f ->
C - $a + 10.
+bin2hexstr(B) when is_binary(B) ->
+ io_lib:format("~.16b",[crypto:bytes_to_integer(B)]).
+
+decstr2int(S) when is_binary(S) ->
+ list_to_integer(binary:bin_to_list(S));
+decstr2int(S) ->
+ list_to_integer(S).
+
is_supported(Group) ->
lists:member(Group, lists:append([Algo || {_, Algo} <- crypto:supports()])).
@@ -953,7 +1093,9 @@ do_cmac_iolistify({Type, Key, Text, Size, CMac}) ->
do_stream_iolistify({Type, Key, PlainText}) ->
{Type, iolistify(Key), iolistify(PlainText)};
do_stream_iolistify({Type, Key, IV, PlainText}) ->
- {Type, iolistify(Key), IV, iolistify(PlainText)}.
+ {Type, iolistify(Key), IV, iolistify(PlainText)};
+do_stream_iolistify({Type, Key, IV, PlainText, CipherText}) ->
+ {Type, iolistify(Key), IV, iolistify(PlainText), CipherText}.
do_block_iolistify({des_cbc = Type, Key, IV, PlainText}) ->
{Type, Key, IV, des_iolistify(PlainText)};
@@ -1199,7 +1341,7 @@ group_config(sha224 = Type, Config) ->
Keys = rfc_4231_keys(),
Data = rfc_4231_msgs(),
Hmac = rfc4231_hmac_sha224(),
- [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
+ [{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
group_config(sha256 = Type, Config) ->
Msgs = [rfc_4634_test1(), rfc_4634_test2_1(), long_msg()],
Digests = rfc_4634_sha256_digests() ++ [long_sha256_digest()],
@@ -1221,31 +1363,54 @@ group_config(sha512 = Type, Config) ->
Data = rfc_4231_msgs() ++ [long_msg()],
Hmac = rfc4231_hmac_sha512() ++ [long_hmac(sha512)],
[{hash, {Type, Msgs, Digests}}, {hmac, {Type, Keys, Data, Hmac}} | Config];
-group_config(rsa = Type, Config) ->
+group_config(sha3_224 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_256 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_384 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(sha3_512 = Type, Config) ->
+ {Msgs,Digests} = sha3_test_vectors(Type),
+ [{hash, {Type, Msgs, Digests}}, {hmac, hmac_sha3(Type)} | Config];
+group_config(rsa, Config) ->
Msg = rsa_plain(),
Public = rsa_public(),
Private = rsa_private(),
PublicS = rsa_public_stronger(),
PrivateS = rsa_private_stronger(),
- SignVerify =
- case ?config(fips, Config) of
- true ->
- %% Use only the strong keys in FIPS mode
- sign_verify_tests(Type, Msg,
- PublicS, PrivateS,
- PublicS, PrivateS);
- false ->
- sign_verify_tests(Type, Msg,
- Public, Private,
- PublicS, PrivateS)
- end,
MsgPubEnc = <<"7896345786348 Asldi">>,
- PubPrivEnc = [{rsa, PublicS, PrivateS, MsgPubEnc, rsa_pkcs1_padding},
- rsa_oaep(),
- no_padding()
+ SignVerify_OptsToTry = [[{rsa_padding, rsa_x931_padding}],
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, -2}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 5}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_mgf1_md,sha}],
+ [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_mgf1_md,sha}, {rsa_pss_saltlen, 5}]
+ ],
+ PrivEnc_OptsToTry = [rsa_pkcs1_padding, % Compatibility
+ [{rsa_pad, rsa_pkcs1_padding}], % Compatibility
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding,rsa_x931_padding}]
+ ],
+ PubEnc_OptsToTry = [rsa_pkcs1_padding, % Compatibility
+ [{rsa_pad, rsa_pkcs1_padding}], % Compatibility
+ [{rsa_padding, rsa_pkcs1_padding}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_md,sha}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_oaep_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}],
+ [{rsa_padding,rsa_pkcs1_oaep_padding}, {rsa_mgf1_md,sha}, {rsa_oaep_md,sha}, {rsa_oaep_label, <<"Hej hopp">>}]
],
- Generate = [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}],
- [{sign_verify, SignVerify}, {pub_priv_encrypt, PubPrivEnc}, {generate, Generate} | Config];
+ [{sign_verify, rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, SignVerify_OptsToTry)},
+ {pub_priv_encrypt, gen_rsa_pub_priv_tests(PublicS, PrivateS, MsgPubEnc, PrivEnc_OptsToTry)},
+ {pub_pub_encrypt, gen_rsa_pub_priv_tests(PublicS, PrivateS, MsgPubEnc, PubEnc_OptsToTry)},
+ {generate, [{rsa, 1024, 3}, {rsa, 2048, 17}, {rsa, 3072, 65537}]}
+ | Config];
group_config(dss = Type, Config) ->
Msg = dss_plain(),
Public = dss_params() ++ [dss_public()],
@@ -1347,52 +1512,101 @@ group_config(rc4, Config) ->
group_config(aes_ctr, Config) ->
Stream = aes_ctr(),
[{stream, Stream} | Config];
+group_config(aes_ccm, Config) ->
+ AEAD = fun() -> aes_ccm(Config) end,
+ [{aead, AEAD} | Config];
group_config(aes_gcm, Config) ->
AEAD = fun() -> aes_gcm(Config) end,
[{aead, AEAD} | Config];
group_config(chacha20_poly1305, Config) ->
AEAD = chacha20_poly1305(),
[{aead, AEAD} | Config];
+group_config(chacha20, Config) ->
+ Stream = chacha20(),
+ [{stream, Stream} | Config];
+group_config(poly1305, Config) ->
+ V = [%% {Key, Txt, Expect}
+ {%% RFC7539 2.5.2
+ crypto_SUITE:hexstr2bin("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"),
+ <<"Cryptographic Forum Research Group">>,
+ crypto_SUITE:hexstr2bin("a8061dc1305136c6c22b8baf0c0127a9")
+ }
+ ],
+ [{poly1305,V} | Config];
group_config(aes_cbc, Config) ->
Block = aes_cbc(Config),
[{block, Block} | Config];
group_config(_, Config) ->
Config.
-sign_verify_tests(Type, Msg, Public, Private, PublicS, PrivateS) ->
- gen_sign_verify_tests(Type, [md5, ripemd160, sha, sha224, sha256], Msg, Public, Private,
- [undefined,
- [{rsa_padding, rsa_pkcs1_pss_padding}],
- [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 0}],
- [{rsa_padding, rsa_x931_padding}]
- ]) ++
- gen_sign_verify_tests(Type, [sha384, sha512], Msg, PublicS, PrivateS,
- [undefined,
- [{rsa_padding, rsa_pkcs1_pss_padding}],
- [{rsa_padding, rsa_pkcs1_pss_padding}, {rsa_pss_saltlen, 0}],
- [{rsa_padding, rsa_x931_padding}]
- ]).
-
-gen_sign_verify_tests(Type, Hashs, Msg, Public, Private, Opts) ->
+rsa_sign_verify_tests(Config, Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
+ case ?config(fips, Config) of
+ true ->
+ %% Use only the strong keys in FIPS mode
+ rsa_sign_verify_tests(Msg,
+ PublicS, PrivateS,
+ PublicS, PrivateS,
+ OptsToTry);
+ false ->
+ rsa_sign_verify_tests(Msg,
+ Public, Private,
+ PublicS, PrivateS,
+ OptsToTry)
+ end.
+
+rsa_sign_verify_tests(Msg, Public, Private, PublicS, PrivateS, OptsToTry) ->
+ gen_rsa_sign_verify_tests([md5, ripemd160, sha, sha224, sha256], Msg, Public, Private,
+ [undefined | OptsToTry]) ++
+ gen_rsa_sign_verify_tests([sha384, sha512], Msg, PublicS, PrivateS,
+ [undefined | OptsToTry]).
+
+gen_rsa_sign_verify_tests(Hashs, Msg, Public, Private, Opts) ->
+ SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []),
lists:foldr(fun(Hash, Acc0) ->
case is_supported(Hash) of
true ->
lists:foldr(fun
(undefined, Acc1) ->
- [{Type, Hash, Public, Private, Msg} | Acc1];
+ [{rsa, Hash, Public, Private, Msg} | Acc1];
([{rsa_padding, rsa_x931_padding} | _], Acc1)
when Hash =:= md5
orelse Hash =:= ripemd160
orelse Hash =:= sha224 ->
Acc1;
(Opt, Acc1) ->
- [{Type, Hash, Public, Private, Msg, Opt} | Acc1]
+ case rsa_opt_is_supported(Opt, SupOpts) of
+ true ->
+ [{rsa, Hash, Public, Private, Msg, Opt} | Acc1];
+ false ->
+ Acc1
+ end
end, Acc0, Opts);
false ->
Acc0
end
end, [], Hashs).
+
+gen_rsa_pub_priv_tests(Public, Private, Msg, OptsToTry) ->
+ SupOpts = proplists:get_value(rsa_opts, crypto:supports(), []),
+ lists:foldr(fun(Opt, Acc) ->
+ case rsa_opt_is_supported(Opt, SupOpts) of
+ true ->
+ [{rsa, Public, Private, Msg, Opt} | Acc];
+ false ->
+ Acc
+ end
+ end, [], OptsToTry).
+
+
+rsa_opt_is_supported([_|_]=Opt, Sup) ->
+ lists:all(fun(O) -> rsa_opt_is_supported(O,Sup) end, Opt);
+rsa_opt_is_supported({A,B}, Sup) ->
+ rsa_opt_is_supported(A,Sup) orelse rsa_opt_is_supported(B,Sup);
+rsa_opt_is_supported(Opt, Sup) ->
+ lists:member(Opt, Sup).
+
+
rfc_1321_msgs() ->
[<<"">>,
<<"a">>,
@@ -1421,6 +1635,160 @@ rfc_1321_md5_digests() ->
hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f"),
hexstr2bin("57edf4a22be3c955ac49da2e2107b67a")].
+%%% https://www.di-mgt.com.au/sha_testvectors.html
+sha3_msgs() ->
+ ["abc",
+ "",
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", % length 448 bits
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", % length 896 bits
+ lists:duplicate(1000000,$a)
+ ].
+
+sha3_test_vectors(sha3_224) ->
+ {sha3_msgs(),
+ [hexstr2bin("e642824c3f8cf24a d09234ee7d3c766f c9a3a5168d0c94ad 73b46fdf"),
+ hexstr2bin("6b4e03423667dbb7 3b6e15454f0eb1ab d4597f9a1b078e3f 5b5a6bc7"),
+ hexstr2bin("8a24108b154ada21 c9fd5574494479ba 5c7e7ab76ef264ea d0fcce33"),
+ hexstr2bin("543e6868e1666c1a 643630df77367ae5 a62a85070a51c14c bf665cbc"),
+ hexstr2bin("d69335b93325192e 516a912e6d19a15c b51c6ed5c15243e7 a7fd653c")
+ ]
+ };
+sha3_test_vectors(sha3_256) ->
+ {sha3_msgs(),
+ [hexstr2bin("3a985da74fe225b2 045c172d6bd390bd 855f086e3e9d525b 46bfe24511431532"),
+ hexstr2bin("a7ffc6f8bf1ed766 51c14756a061d662 f580ff4de43b49fa 82d80a4b80f8434a"),
+ hexstr2bin("41c0dba2a9d62408 49100376a8235e2c 82e1b9998a999e21 db32dd97496d3376"),
+ hexstr2bin("916f6061fe879741 ca6469b43971dfdb 28b1a32dc36cb325 4e812be27aad1d18"),
+ hexstr2bin("5c8875ae474a3634 ba4fd55ec85bffd6 61f32aca75c6d699 d0cdcb6c115891c1")
+ ]
+ };
+sha3_test_vectors(sha3_384) ->
+ {sha3_msgs(),
+ [hexstr2bin("ec01498288516fc9 26459f58e2c6ad8d f9b473cb0fc08c25 96da7cf0e49be4b2 98d88cea927ac7f5 39f1edf228376d25"),
+ hexstr2bin("0c63a75b845e4f7d 01107d852e4c2485 c51a50aaaa94fc61 995e71bbee983a2a c3713831264adb47 fb6bd1e058d5f004"),
+ hexstr2bin("991c665755eb3a4b 6bbdfb75c78a492e 8c56a22c5c4d7e42 9bfdbc32b9d4ad5a a04a1f076e62fea1 9eef51acd0657c22"),
+ hexstr2bin("79407d3b5916b59c 3e30b09822974791 c313fb9ecc849e40 6f23592d04f625dc 8c709b98b43b3852 b337216179aa7fc7"),
+ hexstr2bin("eee9e24d78c18553 37983451df97c8ad 9eedf256c6334f8e 948d252d5e0e7684 7aa0774ddb90a842 190d2c558b4b8340")
+ ]
+ };
+sha3_test_vectors(sha3_512) ->
+ {sha3_msgs(),
+ [hexstr2bin("b751850b1a57168a 5693cd924b6b096e 08f621827444f70d 884f5d0240d2712e 10e116e9192af3c9 1a7ec57647e39340 57340b4cf408d5a5 6592f8274eec53f0"),
+ hexstr2bin("a69f73cca23a9ac5 c8b567dc185a756e 97c982164fe25859 e0d1dcc1475c80a6 15b2123af1f5f94c 11e3e9402c3ac558 f500199d95b6d3e3 01758586281dcd26"),
+ hexstr2bin("04a371e84ecfb5b8 b77cb48610fca818 2dd457ce6f326a0f d3d7ec2f1e91636d ee691fbe0c985302 ba1b0d8dc78c0863 46b533b49c030d99 a27daf1139d6e75e"),
+ hexstr2bin("afebb2ef542e6579 c50cad06d2e578f9 f8dd6881d7dc824d 26360feebf18a4fa 73e3261122948efc fd492e74e82e2189 ed0fb440d187f382 270cb455f21dd185"),
+ hexstr2bin("3c3a876da14034ab 60627c077bb98f7e 120a2a5370212dff b3385a18d4f38859 ed311d0a9d5141ce 9cc5c66ee689b266 a8aa18ace8282a0e 0db596c90b0a7b87")
+ ]
+ }.
+
+
+
+%%% http://www.wolfgang-ehrhardt.de/hmac-sha3-testvectors.html
+
+hmac_sha3(Type) ->
+ N = case Type of
+ sha3_224 -> 1;
+ sha3_256 -> 2;
+ sha3_384 -> 3;
+ sha3_512 -> 4
+ end,
+ {Keys, Datas, Hmacs} =
+ lists:unzip3(
+ [{hexstr2bin(Key), hexstr2bin(Data), hexstr2bin(element(N,Hmacs))}
+ || {Key,Data,Hmacs} <- hmac_sha3_data()]),
+ {Type, Keys, Datas, Hmacs}.
+
+
+hmac_sha3_data() ->
+ [
+ {"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b 0b0b0b0b",
+ "4869205468657265",
+ {"3b16546bbc7be2706a031dcafd56373d 9884367641d8c59af3c860f7",
+ "ba85192310dffa96e2a3a40e69774351 140bb7185e1202cdcc917589f95e16bb",
+ "68d2dcf7fd4ddd0a2240c8a437305f61 fb7334cfb5d0226e1bc27dc10a2e723a 20d370b47743130e26ac7e3d532886bd",
+ "eb3fbd4b2eaab8f5c504bd3a41465aac ec15770a7cabac531e482f860b5ec7ba 47ccb2c6f2afce8f88d22b6dc61380f2 3a668fd3888bb80537c0a0b86407689e"
+ }},
+
+ {"4a656665",
+ "7768617420646f2079612077616e7420 666f72206e6f7468696e673f",
+ {"7fdb8dd88bd2f60d1b798634ad386811 c2cfc85bfaf5d52bbace5e66",
+ "c7d4072e788877ae3596bbb0da73b887 c9171f93095b294ae857fbe2645e1ba5",
+ "f1101f8cbf9766fd6764d2ed61903f21 ca9b18f57cf3e1a23ca13508a93243ce 48c045dc007f26a21b3f5e0e9df4c20a",
+ "5a4bfeab6166427c7a3647b747292b83 84537cdb89afb3bf5665e4c5e709350b 287baec921fd7ca0ee7a0c31d022a95e 1fc92ba9d77df883960275beb4e62024"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddddddddddddddddddddddddddddddd dddd",
+ {"676cfc7d16153638780390692be142d2 df7ce924b909c0c08dbfdc1a",
+ "84ec79124a27107865cedd8bd82da996 5e5ed8c37b0ac98005a7f39ed58a4207",
+ "275cd0e661bb8b151c64d288f1f782fb 91a8abd56858d72babb2d476f0458373 b41b6ab5bf174bec422e53fc3135ac6e",
+ "309e99f9ec075ec6c6d475eda1180687 fcf1531195802a99b5677449a8625182 851cb332afb6a89c411325fbcbcd42af cb7b6e5aab7ea42c660f97fd8584bf03"
+ }},
+
+ {"0102030405060708090a0b0c0d0e0f10 111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd cdcd",
+ {"a9d7685a19c4e0dbd9df2556cc8a7d2a 7733b67625ce594c78270eeb",
+ "57366a45e2305321a4bc5aa5fe2ef8a9 21f6af8273d7fe7be6cfedb3f0aea6d7",
+ "3a5d7a879702c086bc96d1dd8aa15d9c 46446b95521311c606fdc4e308f4b984 da2d0f9449b3ba8425ec7fb8c31bc136",
+ "b27eab1d6e8d87461c29f7f5739dd58e 98aa35f8e823ad38c5492a2088fa0281 993bbfff9a0e9c6bf121ae9ec9bb09d8 4a5ebac817182ea974673fb133ca0d1d"
+ }},
+
+ %% {"0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c 0c0c0c0c",
+ %% "546573742057697468205472756e6361 74696f6e",
+ %% {"49fdd3abd005ebb8ae63fea946d1883c",
+ %% "6e02c64537fb118057abb7fb66a23b3c",
+ %% "47c51ace1ffacffd7494724682615783",
+ %% "0fa7475948f43f48ca0516671e18978c"
+ %% }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374",
+ {"b4a1f04c00287a9b7f6075b313d279b8 33bc8f75124352d05fb9995f",
+ "ed73a374b96c005235f948032f09674a 58c0ce555cfc1f223b02356560312c3b",
+ "0fc19513bf6bd878037016706a0e57bc 528139836b9a42c3d419e498e0e1fb96 16fd669138d33a1105e07c72b6953bcc",
+ "00f751a9e50695b090ed6911a4b65524 951cdc15a73a5d58bb55215ea2cd839a c79d2b44a39bafab27e83fde9e11f634 0b11d991b1b91bf2eee7fc872426c3a4"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54657374205573696e67204c61726765 72205468616e20426c6f636b2d53697a 65204b6579202d2048617368204b6579 204669727374",
+ {
+ "b96d730c148c2daad8649d83defaa371 9738d34775397b7571c38515",
+ "a6072f86de52b38bb349fe84cd6d97fb 6a37c4c0f62aae93981193a7229d3467",
+ "713dff0302c85086ec5ad0768dd65a13 ddd79068d8d4c6212b712e4164944911 1480230044185a99103ed82004ddbfcc",
+ "b14835c819a290efb010ace6d8568dc6 b84de60bc49b004c3b13eda763589451 e5dd74292884d1bdce64e6b919dd61dc 9c56a282a81c0bd14f1f365b49b83a5b"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e",
+ {
+ "05d8cd6d00faea8d1eb68ade28730bbd 3cbab6929f0a086b29cd62a0",
+ "65c5b06d4c3de32a7aef8763261e49ad b6e2293ec8e7c61e8de61701fc63e123",
+ "026fdf6b50741e373899c9f7d5406d4e b09fc6665636fc1a530029ddf5cf3ca5 a900edce01f5f61e2f408cdf2fd3e7e8",
+ "38a456a004bd10d32c9ab83366841128 62c3db61adcca31829355eaf46fd5c73 d06a1f0d13fec9a652fb3811b577b1b1 d1b9789f97ae5b83c6f44dfcf1d67eba"
+ }},
+
+ {"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaa",
+ "54686973206973206120746573742075 73696e672061206c6172676572207468 616e20626c6f636b2d73697a65206b65 7920616e642061206c61726765722074 68616e20626c6f636b2d73697a652064 6174612e20546865206b6579206e6565 647320746f2062652068617368656420 6265666f7265206265696e6720757365 642062792074686520484d414320616c 676f726974686d2e",
+ {
+ "c79c9b093424e588a9878bbcb089e018 270096e9b4b1a9e8220c866a",
+ "e6a36d9b915f86a093cac7d110e9e04c f1d6100d30475509c2475f571b758b5a",
+ "cad18a8ff6c4cc3ad487b95f9769e9b6 1c062aefd6952569e6e6421897054cfc 70b5fdc6605c18457112fc6aaad45585",
+ "dc030ee7887034f32cf402df34622f31 1f3e6cf04860c6bbd7fa488674782b46 59fdbdf3fd877852885cfe6e22185fe7 b2ee952043629bc9d5f3298a41d02c66"
+ }}
+ %%,
+
+ %% {"4a656665",
+ %% "'11001' or LSB 13 or MSB c8",
+ %% {
+ %% "5f8c0ea7fafecd0c3463aad09742cece b142fe0ab6f4539438c59de8",
+ %% "ec8222773fac68b3d3dcb182aec8b050 7ace4448d20a1147e682118da4e3f44c",
+ %% "21fbd3bf3ebba3cfc9ef64c0591c92c5 acb265e92d8761d1f91a52a103a6c796 94cfd67a9a2ac1324f02fea63b81effc",
+ %% "27f9388c1567ef4ef200602a6cf871d6 8a6fb048d4737ac4418a2f021289d13d 1fd1120fecb9cf964c5b117ab5b11c61 4b2da39dadd51f2f5e22aaccec7d576e"
+ %% }}
+ ].
+
+
+
rfc_4634_test1() ->
<<"abc">>.
rfc_4634_test2_1() ->
@@ -1990,6 +2358,13 @@ aes_gcm(Config) ->
"gcmEncryptExtIV192.rsp",
"gcmEncryptExtIV256.rsp"]).
+aes_ccm(Config) ->
+ read_rsp(Config, aes_ccm,
+ ["VADT128.rsp", "VADT192.rsp", "VADT256.rsp",
+ "VNT128.rsp", "VNT192.rsp", "VNT256.rsp",
+ "VPT128.rsp", "VPT192.rsp", "VPT256.rsp"
+ ]).
+
%% https://tools.ietf.org/html/rfc7539#appendix-A.5
chacha20_poly1305() ->
[
@@ -2032,9 +2407,108 @@ chacha20_poly1305() ->
"49e617d91d361094fa68f0ff77987130"
"305beaba2eda04df997b714d6c6f2c29"
"a6ad5cb4022b02709b"),
- hexstr2bin("eead9d67890cbb22392336fea1851f38")} %% CipherTag
+ hexstr2bin("eead9d67890cbb22392336fea1851f38"), %% CipherTag
+ no_info
+ }
+ ].
+
+
+chacha20() ->
+%%% chacha20 (no mode) test vectors from RFC 7539 A.2
+ [
+ %% Test Vector #1:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000000"), %% Key
+ hexstr2bin("00000000" % Initial counter = 0, little-endian
+ "000000000000000000000000"), %% IV
+ hexstr2bin("00000000000000000000000000000000" %% PlainText
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"
+ "00000000000000000000000000000000"),
+ hexstr2bin("76b8e0ada0f13d90405d6ae55386bd28" %% CipherText
+ "bdd219b8a08ded1aa836efcc8b770dc7"
+ "da41597c5157488d7724e03fb8d84a37"
+ "6a43b8f41518a11cc387b669b2ee6586")},
+ %% Test Vector #2:
+ {chacha20,
+ hexstr2bin("00000000000000000000000000000000"
+ "00000000000000000000000000000001"), %% Key
+ hexstr2bin("01000000" % Initial counter = 1, little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("416e79207375626d697373696f6e2074" %% PlainText
+ "6f20746865204945544620696e74656e"
+ "6465642062792074686520436f6e7472"
+ "696275746f7220666f72207075626c69"
+ "636174696f6e20617320616c6c206f72"
+ "2070617274206f6620616e2049455446"
+ "20496e7465726e65742d447261667420"
+ "6f722052464320616e6420616e792073"
+ "746174656d656e74206d616465207769"
+ "7468696e2074686520636f6e74657874"
+ "206f6620616e20494554462061637469"
+ "7669747920697320636f6e7369646572"
+ "656420616e20224945544620436f6e74"
+ "7269627574696f6e222e205375636820"
+ "73746174656d656e747320696e636c75"
+ "6465206f72616c2073746174656d656e"
+ "747320696e2049455446207365737369"
+ "6f6e732c2061732077656c6c20617320"
+ "7772697474656e20616e6420656c6563"
+ "74726f6e696320636f6d6d756e696361"
+ "74696f6e73206d61646520617420616e"
+ "792074696d65206f7220706c6163652c"
+ "20776869636820617265206164647265"
+ "7373656420746f"),
+ hexstr2bin("a3fbf07df3fa2fde4f376ca23e827370" %% CipherText
+ "41605d9f4f4f57bd8cff2c1d4b7955ec"
+ "2a97948bd3722915c8f3d337f7d37005"
+ "0e9e96d647b7c39f56e031ca5eb6250d"
+ "4042e02785ececfa4b4bb5e8ead0440e"
+ "20b6e8db09d881a7c6132f420e527950"
+ "42bdfa7773d8a9051447b3291ce1411c"
+ "680465552aa6c405b7764d5e87bea85a"
+ "d00f8449ed8f72d0d662ab052691ca66"
+ "424bc86d2df80ea41f43abf937d3259d"
+ "c4b2d0dfb48a6c9139ddd7f76966e928"
+ "e635553ba76c5c879d7b35d49eb2e62b"
+ "0871cdac638939e25e8a1e0ef9d5280f"
+ "a8ca328b351c3c765989cbcf3daa8b6c"
+ "cc3aaf9f3979c92b3720fc88dc95ed84"
+ "a1be059c6499b9fda236e7e818b04b0b"
+ "c39c1e876b193bfe5569753f88128cc0"
+ "8aaa9b63d1a16f80ef2554d7189c411f"
+ "5869ca52c5b83fa36ff216b9c1d30062"
+ "bebcfd2dc5bce0911934fda79a86f6e6"
+ "98ced759c3ff9b6477338f3da4f9cd85"
+ "14ea9982ccafb341b2384dd902f3d1ab"
+ "7ac61dd29c6f21ba5b862f3730e37cfd"
+ "c4fd806c22f221")},
+ %%Test Vector #3:
+ {chacha20,
+ hexstr2bin("1c9240a5eb55d38af333888604f6b5f0"
+ "473917c1402b80099dca5cbc207075c0"), %% Key
+ hexstr2bin("2a000000" % Initial counter = 42 (decimal), little-endian
+ "000000000000000000000002"), %% IV
+ hexstr2bin("2754776173206272696c6c69672c2061" %% PlainText
+ "6e642074686520736c6974687920746f"
+ "7665730a446964206779726520616e64"
+ "2067696d626c6520696e207468652077"
+ "6162653a0a416c6c206d696d73792077"
+ "6572652074686520626f726f676f7665"
+ "732c0a416e6420746865206d6f6d6520"
+ "7261746873206f757467726162652e"),
+ hexstr2bin("62e6347f95ed87a45ffae7426f27a1df" %% CipherText
+ "5fb69110044c0d73118effa95b01e5cf"
+ "166d3df2d721caf9b21e5fb14c616871"
+ "fd84c54f9d65b283196c7fe4f60553eb"
+ "f39c6402c42234e32a356b3e764312a6"
+ "1a5532055716ead6962568f87d3f3f77"
+ "04c6a8d1bcd1bf4d50d6154b6da731b1"
+ "87b58dfd728afa36757a797ac188d1")}
].
+
rsa_plain() ->
<<"7896345786348756234 Hejsan Svejsan, erlang crypto debugger"
"09812312908312378623487263487623412039812 huagasd">>.
@@ -2230,7 +2704,9 @@ srp(ClientPrivate, Generator, Prime, Version, Verifier, ServerPublic, ServerPriv
SessionKey}.
ecdh() ->
%% http://csrc.nist.gov/groups/STM/cavp/
- Curves = crypto:ec_curves(),
+ Curves = crypto:ec_curves() ++
+ [X || X <- proplists:get_value(curves, crypto:supports(), []),
+ lists:member(X, [x25519,x448])],
TestCases =
[{ecdh, hexstr2point("42ea6dd9969dd2a61fea1aac7f8e98edcc896c6e55857cc0", "dfbe5d7c61fac88b11811bde328e8a0d12bf01a9d204b523"),
hexstr2bin("f17d3fea367b74d340851ca4270dcb24c271f445bed9d527"),
@@ -2313,7 +2789,32 @@ ecdh() ->
"2FDC313095BCDD5FB3A91636F07A959C8E86B5636A1E930E8396049CB481961D365CC11453A06C719835475B12CB52FC3C383BCE35E27EF194512B71876285FA"),
hexstr2bin("16302FF0DBBB5A8D733DAB7141C1B45ACBC8715939677F6A56850A38BD87BD59B09E80279609FF333EB9D4C061231FB26F92EEB04982A5F1D1764CAD57665422"),
brainpoolP512r1,
- hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")}],
+ hexstr2bin("A7927098655F1F9976FA50A9D566865DC530331846381C87256BAF3226244B76D36403C024D7BBF0AA0803EAFF405D3D24F11A9B5C0BEF679FE1454B21C4CD1F")},
+
+ %% RFC 7748, 6.1
+ {ecdh,
+ 16#8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a,
+ 16#5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb,
+ x25519,
+ hexstr2bin("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")},
+ {ecdh,
+ 16#de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f,
+ 16#77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a,
+ x25519,
+ hexstr2bin("4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742")},
+
+ %% RFC 7748, 6.2
+ {ecdh,
+ 16#9b08f7cc31b7e3e67d22d5aea121074a273bd2b83de09c63faa73d2c22c5d9bbc836647241d953d40c5b12da88120d53177f80e532c41fa0,
+ 16#1c306a7ac2a0e2e0990b294470cba339e6453772b075811d8fad0d1d6927c120bb5ee8972b0d3e21374c9c921b09d1b0366f10b65173992d,
+ x448,
+ hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d")},
+ {ecdh,
+ 16#3eb7a829b0cd20f5bcfc0b599b6feccf6da4627107bdb0d4f345b43027d8b972fc3e34fb4232a13ca706dcb57aec3dae07bdc1c67bf33609,
+ 16#9a8f4925d1519f5775cf46b04b5800d4ee9ee8bae8bc5565d498c28dd9c9baf574a9419744897391006382a6f127ab1d9ac2d8c0a598726b,
+ x448,
+ hexstr2bin("07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d")}
+ ],
lists:filter(fun ({_Type, _Pub, _Priv, Curve, _SharedSecret}) ->
lists:member(Curve, Curves)
end,
@@ -2322,6 +2823,8 @@ ecdh() ->
dh() ->
{dh, 90970053988169282502023478715631717259407236400413906591937635666709823903223997309250405131675572047545403771567755831138144089197560332757755059848492919215391041119286178688014693040542889497092308638580104031455627238700168892909539193174537248629499995652186913900511641708112112482297874449292467498403, 2}.
+
+
rsa_oaep() ->
%% ftp://ftp.rsa.com/pub/rsalabs/tmp/pkcs1v15crypt-vectors.txt
Public = [hexstr2bin("010001"),
@@ -2334,7 +2837,32 @@ rsa_oaep() ->
hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
%%Msg = hexstr2bin("6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"),
Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
- {rsa, Public, Private, Msg, rsa_pkcs1_oaep_padding}.
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}]}.
+
+rsa_oaep_label() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ Lbl = hexstr2bin("1332a67ca7088f75c9b8fb5e3d072882"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_label, Lbl}]}.
+
+rsa_oaep256() ->
+ Public = [hexstr2bin("010001"),
+ hexstr2bin("a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb")],
+ Private = Public ++ [hexstr2bin("53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1"),
+ hexstr2bin("d32737e7267ffe1341b2d5c0d150a81b586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1c11c520c2f26a471dcad212eac7ca39d"),
+ hexstr2bin("cc8853d1d54da630fac004f471f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0dd852be2419b2af72bfe9a030e860b0288b5d77"),
+ hexstr2bin("0e12bf1718e9cef5599ba1c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2d76819967d4671acc6431e4037968db37878e695c1"),
+ hexstr2bin("95297b0f95a2fa67d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda866efef13c459e1a631386b7e354c899f5f112ca85d71583"),
+ hexstr2bin("4f456c502493bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbefd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1")],
+ Msg = hexstr2bin("750c4047f547e8e41411856523298ac9bae245efaf1397fbe56f9dd5"),
+ {rsa, Public, Private, Msg, [{rsa_padding, rsa_pkcs1_oaep_padding}, {rsa_oaep_md, sha256}]}.
ecc() ->
%% http://point-at-infinity.org/ecc/nisttv
@@ -2371,13 +2899,6 @@ cmac_nist(Config, aes_cbc256 = Type) ->
read_rsp(Config, Type,
["CMACGenAES256.rsp", "CMACVerAES256.rsp"]).
-no_padding() ->
- Public = [_, Mod] = rsa_public_stronger(),
- Private = rsa_private_stronger(),
- MsgLen = erlang:byte_size(int_to_bin(Mod)),
- Msg = list_to_binary(lists:duplicate(MsgLen, $X)),
- {rsa, Public, Private, Msg, rsa_no_padding}.
-
int_to_bin(X) when X < 0 -> int_to_bin_neg(X, []);
int_to_bin(X) -> int_to_bin_pos(X, []).
@@ -2419,29 +2940,36 @@ read_rsp(Config, Type, Files) ->
Tests =
lists:foldl(
fun(FileName, Acc) ->
- read_rsp_file(filename:join(datadir(Config), FileName),
- Type, Acc)
+ NewAcc = read_rsp_file(filename:join(datadir(Config), FileName),
+ Type, Acc),
+ ct:log("~p: ~p tests read.~n",[FileName,length(NewAcc)-length(Acc)]),
+ NewAcc
end, [], Files),
log_rsp_size(Type, Tests),
Tests.
read_rsp_file(FileName, Type, Acc) ->
- {ok, Raw} = file:read_file(FileName),
- Split = binary:split(Raw, [<<"\r">>, <<"\n">>], [global, trim_all]),
- parse_rsp(Type, Split, Acc).
+ case file:read_file(FileName) of
+ {ok, Raw} ->
+ Split = binary:split(Raw, [<<"\r">>, <<"\n">>], [global, trim_all]),
+ parse_rsp(Type, Split, #{file => FileName}, Acc);
+ Other ->
+ ct:fail("~p ~p",[FileName, Other])
+ end.
-parse_rsp(_Type, [], Acc) ->
+parse_rsp(_Type, [], _State, Acc) ->
Acc;
-parse_rsp(_Type, [<<"DECRYPT">>|_], Acc) ->
+parse_rsp(_Type, [<<"DECRYPT">>|_], _State, Acc) ->
Acc;
%% AES format
parse_rsp(Type, [<<"COUNT = ", _/binary>>,
<<"KEY = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"PLAINTEXT = ", PlainText/binary>>,
- <<"CIPHERTEXT = ", CipherText/binary>>|Next], Acc) ->
- parse_rsp(Type, Next, [{Type, hexstr2bin(Key), hexstr2bin(IV),
- hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
+ <<"CIPHERTEXT = ", CipherText/binary>>|Next], State, Acc) ->
+ parse_rsp(Type, Next, State,
+ [{Type, hexstr2bin(Key), hexstr2bin(IV),
+ hexstr2bin(PlainText), hexstr2bin(CipherText)}|Acc]);
%% CMAC format
parse_rsp(Type, [<<"Count = ", _/binary>>,
<<"Klen = ", _/binary>>,
@@ -2449,23 +2977,23 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
<<"Tlen = ", Tlen/binary>>,
<<"Key = ", Key/binary>>,
<<"Msg = ", Msg/binary>>,
- <<"Mac = ", MAC/binary>>|Rest], Acc) ->
+ <<"Mac = ", MAC/binary>>|Rest], State, Acc) ->
case Rest of
[<<"Result = P">>|Next] ->
- parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Next, Acc);
+ parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Next, State, Acc);
[<<"Result = ", _/binary>>|Next] ->
- parse_rsp(Type, Next, Acc);
+ parse_rsp(Type, Next, State, Acc);
_ ->
- parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Rest, Acc)
+ parse_rsp_cmac(Type, Key, Msg, Mlen, Tlen, MAC, Rest, State, Acc)
end;
%% GCM format decode format
-parse_rsp(Type, [<<"Count = ", _/binary>>,
+parse_rsp(Type, [<<"Count = ", Count/binary>>,
<<"Key = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"CT = ", CipherText/binary>>,
<<"AAD = ", AAD/binary>>,
<<"Tag = ", CipherTag0/binary>>,
- <<"PT = ", PlainText/binary>>|Next], Acc) ->
+ <<"PT = ", PlainText/binary>>|Next], #{file:=File}=State, Acc) ->
CipherTag = hexstr2bin(CipherTag0),
TestCase = {Type,
hexstr2bin(Key),
@@ -2474,16 +3002,17 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
hexstr2bin(AAD),
hexstr2bin(CipherText),
CipherTag,
- size(CipherTag)},
- parse_rsp(Type, Next, [TestCase|Acc]);
+ size(CipherTag),
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
%% GCM format encode format
-parse_rsp(Type, [<<"Count = ", _/binary>>,
+parse_rsp(Type, [<<"Count = ", Count/binary>>,
<<"Key = ", Key/binary>>,
<<"IV = ", IV/binary>>,
<<"PT = ", PlainText/binary>>,
<<"AAD = ", AAD/binary>>,
<<"CT = ", CipherText/binary>>,
- <<"Tag = ", CipherTag0/binary>>|Next], Acc) ->
+ <<"Tag = ", CipherTag0/binary>>|Next], #{file:=File}=State, Acc) ->
CipherTag = hexstr2bin(CipherTag0),
TestCase = {Type,
hexstr2bin(Key),
@@ -2492,13 +3021,88 @@ parse_rsp(Type, [<<"Count = ", _/binary>>,
hexstr2bin(AAD),
hexstr2bin(CipherText),
CipherTag,
- size(CipherTag)},
- parse_rsp(Type, Next, [TestCase|Acc]);
+ size(CipherTag),
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
+%% CCM-VADT format
+parse_rsp(Type, [<<"[Alen = ", AlenB0/binary>>|Next], State0, Acc) ->
+ AlenSize = size(AlenB0) - 1, % remove closing ']'
+ Alen = decstr2int(<<AlenB0:AlenSize/binary>>),
+ State = State0#{alen => Alen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Nlen = ", NlenB0/binary>>|Next], State0, Acc) ->
+ NlenSize = size(NlenB0) - 1, % remove closing ']'
+ Nlen = decstr2int(<<NlenB0:NlenSize/binary>>),
+ State = State0#{nlen => Nlen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Plen = ", PlenB0/binary>>|Next], State0, Acc) ->
+ PlenSize = size(PlenB0) - 1, % remove closing ']'
+ Plen = decstr2int(<<PlenB0:PlenSize/binary>>),
+ State = State0#{plen => Plen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"[Tlen = ", TlenB0/binary>>|Next], State0, Acc) ->
+ TlenSize = size(TlenB0) - 1, % remove closing ']'
+ Tlen = decstr2int(<<TlenB0:TlenSize/binary>>),
+ State = State0#{tlen => Tlen},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Alen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{alen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Plen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{plen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Count = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{count => B},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Nlen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{nlen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Tlen = ", B/binary>>|Next], State0, Acc) ->
+ State = State0#{tlen => decstr2int(B)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Key = ",Key/binary>>|Next], State0, Acc) ->
+ State = State0#{key => hexstr2bin(Key)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Nonce = ",Nonce/binary>>|Next], State0, Acc) ->
+ State = State0#{nonce => hexstr2bin(Nonce)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Adata = ",Adata/binary>>|Next], State0, Acc) ->
+ State = State0#{adata => hexstr2bin(Adata)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type, [<<"Payload = ",Payload/binary>>|Next], State0, Acc) ->
+ State = State0#{payload => hexstr2bin(Payload)},
+ parse_rsp(Type, Next, State, Acc);
+parse_rsp(Type,
+ [<<"CT = ", CT/binary>>|Next],
+ #{count := Count,
+ file := File,
+ alen := Alen,
+ plen := Plen,
+ nlen := _Nlen,
+ tlen := Tlen,
+ key := Key,
+ nonce := IV,
+ adata := Adata,
+ payload := Payload
+ } = State, Acc) ->
+ AAD = <<Adata:Alen/binary>>,
+ PlainText = <<Payload:Plen/binary>>,
+ <<CipherText:Plen/binary, CipherTag:Tlen/binary>> = hexstr2bin(CT),
+ TestCase = {Type,
+ Key,
+ PlainText,
+ IV,
+ AAD,
+ CipherText,
+ CipherTag,
+ Tlen,
+ {File,decstr2int(Count)}},
+ parse_rsp(Type, Next, State, [TestCase|Acc]);
+parse_rsp(Type, [_|Next], State, Acc) ->
+ parse_rsp(Type, Next, State, Acc).
-parse_rsp(Type, [_|Next], Acc) ->
- parse_rsp(Type, Next, Acc).
-parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, Acc) ->
+parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, State, Acc) ->
Key = hexstr2bin(Key0),
Mlen = binary_to_integer(Mlen0),
<<Msg:Mlen/bytes, _/binary>> = hexstr2bin(Msg0),
@@ -2506,7 +3110,18 @@ parse_rsp_cmac(Type, Key0, Msg0, Mlen0, Tlen, MAC0, Next, Acc) ->
case binary_to_integer(Tlen) of
0 ->
- parse_rsp(Type, Next, [{Type, Key, Msg, MAC}|Acc]);
+ parse_rsp(Type, Next, State, [{Type, Key, Msg, MAC}|Acc]);
I ->
- parse_rsp(Type, Next, [{Type, Key, Msg, I, MAC}|Acc])
+ parse_rsp(Type, Next, State, [{Type, Key, Msg, I, MAC}|Acc])
end.
+
+api_errors_ecdh(Config) when is_list(Config) ->
+ %% Check that we don't segfault when fed garbage.
+ Test = fun(Others, Curve) ->
+ {_Pub, Priv} = crypto:generate_key(ecdh, Curve),
+ crypto:compute_key(ecdh, Others, Priv, Curve)
+ end,
+ Others = [gurka, 0, <<0>>],
+ Curves = [gaffel, 0, sect571r1],
+ [_= (catch Test(O, C)) || O <- Others, C <- Curves],
+ ok.
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT128.rsp b/lib/crypto/test/crypto_SUITE_data/VADT128.rsp
new file mode 100644
index 0000000000..a4fe9130a0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT128.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = d24a3d3dde8c84830280cb87abad0bb3
+Nonce = f1100035bb24a8d26004e0e24b
+
+Count = 0
+Adata = 00
+Payload = 7c86135ed9c2a515aaae0e9a208133897269220f30870006
+CT = 1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab1123301219c70599b7c373ad4b3ad67b
+
+Count = 1
+Adata = 00
+Payload = 48df73208cdc63d716752df7794807b1b2a80794a2433455
+CT = 2bf7d09079bc0b904c711a0b0e4a70ca8ea892d9566f03f8b77a140819f39ef045103e785e1df8c2
+
+Count = 2
+Adata = 00
+Payload = b99de8168e8c13ea4aef66bdb93133dff5d57e9837ff6ccb
+CT = dab54ba67bec7bad10eb5141ce3344a4c9d5ebd5c3d35b664b01098842a618390619b86e00850b2e
+
+Count = 3
+Adata = 00
+Payload = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce
+CT = 6ad4821cbf7f2b9973662b5084aff39b69c6276d8636c0638bd518724ab84fb814fe7b5570769f7f
+
+Count = 4
+Adata = 00
+Payload = cb43320d7488dfd6eed9efd88f440ea3f6f77a0df09d0727
+CT = a86b91bd81e8b791b4ddd824f84679d8caf7ef4004b1308a7229cbcecef221570cee8345b38cd6ec
+
+Count = 5
+Adata = 00
+Payload = a350ed58c04473e113b9088b1fb9dad92807f6b63b0d690c
+CT = c0784ee835241ba649bd3f7768bbada2140763fbcf215ea1fee47fec27d7764e5e2819c850088bac
+
+Count = 6
+Adata = 00
+Payload = 0709e691faf41383fab5d1848a8eee77101d1c99e526a264
+CT = 642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d610bc1ab4bc9a8a28c7306f7c539e
+
+Count = 7
+Adata = 00
+Payload = e7b913c2f0630562eb1c16b3b1ed84090c011a15c09e5471
+CT = 8491b07205036d25b118214fc6eff37230018f5834b263dc2e31657ecc51f5ec8590482fc053230d
+
+Count = 8
+Adata = 00
+Payload = 6b909697074900d41ce8c7d559b229af11fb3cec334784d4
+CT = 08b83527f229689346ecf0292eb05ed42dfba9a1c76bb379d500827f2081b00397102f90fc9ccd88
+
+Count = 9
+Adata = 00
+Payload = 495ff03335bcb39a317b9ea3f8bb6306fa771f3c55adebce
+CT = 2a775383c0dcdbdd6b7fa95f8fb9147dc6778a71a181dc63e2e7997803029476598c0e8d4fc63857
+
+[Alen = 1]
+
+Key = 08b0da255d2083808a1b4d367090bacc
+Nonce = 777828b13679a9e2ca89568233
+
+Count = 10
+Adata = dd
+Payload = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0
+CT = e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6282283e16602331bcca9d51ce76
+
+Count = 11
+Adata = c5
+Payload = 032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead
+CT = f0828917020651c085e42459c544ec52e99372005362baf308ebeed45f67ef8733737c9c6f82daad
+
+Count = 12
+Adata = 68
+Payload = 9c4cd65b92070bc382fd18146611defb4204acddfdf6b276
+CT = 6fe1b1d12ffd9676197322ab732e80b1183032b65be00628f9b477e3a23bfdfdb619c7bc531fbcce
+
+Count = 13
+Adata = be
+Payload = 2ff93ef2fc5fe2c297ace05f3f7585aed75ef90ade3acf89
+CT = dc54597841a57f770c22dae02a4adbe48d6a6761782c7bd7aa82130f5a86c0cd0433585e5c208cf7
+
+Count = 14
+Adata = 7a
+Payload = 62766e9acd41285eeed9b4007340dbb611699624274ad117
+CT = 91db091070bbb5eb75578ebf667f85fc4b5d084f815c65499d60012a2f25463e036ceecea57b3c97
+
+Count = 15
+Adata = 13
+Payload = ea689c268a04912d0527b16d9d9406df38302fb11cb64a99
+CT = 19c5fbac37fe0c989ea98bd288ab58956204b1dabaa0fec7e337897c90eb260729a729aed1c8a244
+
+Count = 16
+Adata = e5
+Payload = f31e35953beb211efcce487ba8c0cd1a8446343d5851b9fd
+CT = 00b3521f8611bcab674072c4bdff9350de72aa56fe470da373dc2911c75b37cd995481d42b04524a
+
+Count = 17
+Adata = e3
+Payload = c4ac3c645387584c2a95b1f16b8317730592924dd831a388
+CT = 37015beeee7dc5f9b11b8b4e7ebc49395fa60c267e2717d684f76ecf3dc5f3307ce982f185321248
+
+Count = 18
+Adata = d5
+Payload = 81af394c2ea3a85e1ea954596e3772f01635d007794c0b19
+CT = 72025ec6935935eb85276ee67b082cba4c014e6cdf5abf472c38d0fe4e4eba054c1420c39a3dcc61
+
+Count = 19
+Adata = ed
+Payload = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304
+CT = 13bec5676842f61e167bf32b183552cc1e4c5fc6e470375a7cfa6c9945f5aee3c799eee37b0605db
+
+[Alen = 2]
+
+Key = 1538cc03b60880bf3e7d388e29f27739
+Nonce = 9e734de325026b5d7128193973
+
+Count = 20
+Adata = c93c
+Payload = e7b819a853ffe79baaa72097ff0d04f02640ae62bcfd3da5
+CT = 1d8f42f9730424fa27240bd6277f4882604f440324b11b003ca01d874439b4e1f79a26d8c6dc433a
+
+Count = 21
+Adata = 4cf9
+Payload = dc6cf325ed6d968efba9f57e48a58f4578cc3540fe121ba2
+CT = 265ba874cd9655ef762ade3f90d7c3373ec3df21665e3d07b40653cd23afc7cc7a31fa13ba8f4e49
+
+Count = 22
+Adata = b469
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = d89c315c8f6ef204502b4f8d3699345c6153e166b2a1f421c8c10aaf90b1116be216f912c82ca96a
+
+Count = 23
+Adata = cf6b
+Payload = a35f62a431fee63468dc02fdf7bef78d3a5937de56151939
+CT = 596839f511052555e55f29bc2fccbbff7c56ddbfce593f9c2f568ef41324189fb3644edcd76dc19c
+
+Count = 24
+Adata = af7c
+Payload = 548840cb0400824af809fb68447500b77e977128200d3b81
+CT = aebf1b9a24fb412b758ad0299c074cc538989b49b8411d242548c244a875d3681d715db3da19962f
+
+Count = 25
+Adata = 61dc
+Payload = 440b6095c77495e73fff54c785b7ceb5eb358731c213ffcd
+CT = be3c3bc4e78f5686b27c7f865dc582c7ad3a6d505a5fd968b599bc8927ad8d43067807f4b858f854
+
+Count = 26
+Adata = b97e
+Payload = 50c59ca54eb64575b82b13c6dac96488af369e9f5f86cdf2
+CT = aaf2c7f46e4d861435a8388702bb28fae93974fec7caeb577454774ee78f76e555cf743df340381e
+
+Count = 27
+Adata = 57ab
+Payload = 21b8eb1f0bda26ca36167ce7bc2e796818bf11fc8c192885
+CT = db8fb04e2b21e5abbb9557a6645c351a5eb0fb9d14550e20e0a22a5ee031978271c7dd2a0d4e7018
+
+Count = 28
+Adata = 5f9c
+Payload = b4d84fb1e81e18c89391a7a59fc05fedaf160e0d0d027a7c
+CT = 4eef14e0c8e5dba91e128ce447b2139fe919e46c954e5cd99a242ebae5c6da57ee38e5c227c46b32
+
+Count = 29
+Adata = e0c4
+Payload = 54dc5a0e1b67577cda4e7dbd48b769c120c1d13dd567cfad
+CT = aeeb015f3b9c941d57cd56fc90c525b366ce3b5c4d2be908a5f8a92f4201c4658289307167cee810
+
+[Alen = 3]
+
+Key = f149e41d848f59276cfddd743bafa9a9
+Nonce = 14b756d66fc51134e203d1c6f9
+
+Count = 30
+Adata = f5827e
+Payload = 9759e6f21f5a588010f57e6d6eae178d8b20ab59cda66f42
+CT = f634bf00f1f9f1f93f41049d7f3797b05e805f0b14850f4e78e2a23411147a6187da6818506232ee
+
+Count = 31
+Adata = e9699b
+Payload = 1555bc87d6c688fd221a2c75cd1e4dd1c1693207ac421d24
+CT = 7438e575386521840dae5685dc87cdec14c9c65575617d28f10835db9897b7528e3204fe3a81424f
+
+Count = 32
+Adata = 972896
+Payload = b72b2a080d92f3f3bb7d96222982de82a28c9eebaddba247
+CT = d64673fae3315a8a94c9ecd2381b5ebf772c6ab974f8c24b3efa05ba4a73ec2234461d459f54acd2
+
+Count = 33
+Adata = 3053f3
+Payload = b5417ed6933ffe2b57ea601d77e97eb12fa1fb8fdc06c86f
+CT = d42c27247d9c5752785e1aed6670fe8cfa010fdd0525a863b557537c6525e827750917a1ed49602f
+
+Count = 34
+Adata = 24db75
+Payload = 4e7f42666035a00e62783283c54b027603917685d27326bc
+CT = 2f121b948e9609774dcc4873d4d2824bd63182d70b5046b0dfd06b037e9094f120eb3d8649d48918
+
+Count = 35
+Adata = ff27a4
+Payload = 7bf180699c294421ad9565cacc27227a4b3a7cf9637290c6
+CT = 1a9cd99b728aed5882211f3addbea2479e9a88abba51f0cabfa8cfabbd79b3e3210482e6f3822fee
+
+Count = 36
+Adata = 77ec24
+Payload = 3d47071c13f994cb42fb2887e5c6e53a542be7ddad9779e0
+CT = 5c2a5eeefd5a3db26d4f5277f45f6507818b138f74b419ec3b9575e347051e98d0c8646ad46318e6
+
+Count = 37
+Adata = 6d7748
+Payload = 317d5da0a2ec12c3b96c83dd61cc955242a9c1c640e2b92f
+CT = 501004524c4fbbba96d8f92d7055156f9709359499c1d92378e7af65eb0388ae7a52f58f6ba32109
+
+Count = 38
+Adata = 029674
+Payload = c9bb21306ee1b4a6c4fa5443af2e181716993cbb374e177c
+CT = a8d678c280421ddfeb4e2eb3beb7982ac339c8e9ee6d77708019fa97ff70d4d21c0bd83caa434b3a
+
+Count = 39
+Adata = 60dfe8
+Payload = 44eb7edd6bee501ad97873aa7ecbf7ed8b613760d7c95e15
+CT = 2586272f854df963f6cc095a6f5277d05ec1c3320eea3e191814ed48a21d97ea02e86d7e6e8834cb
+
+[Alen = 4]
+
+Key = 9a57a22c7f26feff8ca6cceff214e4c2
+Nonce = 88f30fd2b04fb8ddbce8fc26e6
+
+Count = 40
+Adata = a95bdff6
+Payload = 035c516776c706a7dd5f181fa6aa891b04dd423042ea0667
+CT = b92f7ec2ebecebdbd2977b3874e61bf496a382153b2529fc9b6443a35f329b2068916fb6ab8227eb
+
+Count = 41
+Adata = d2672cbb
+Payload = 3ba306bcec94615c347f990b62841a16df7b321f113f1714
+CT = 81d0291971bf8c203bb7fa2cb0c888f94d05f23a68f0388f19e2aa492ce9ddfb6de0ab7a447f5351
+
+Count = 42
+Adata = 737f4d00
+Payload = 68313a29ace3efe521c3ca1e5bac8e98d6b4434c80a7dc74
+CT = d242158c31c802992e0ba93989e01c7744ca8369f968f3ef2bf683b1209f104e82ba39f7c62cd666
+
+Count = 43
+Adata = 3610b1ae
+Payload = 963bfe556138317bebe3936b18a2c1dd100dc73be6fde556
+CT = 2c48d1f0fc13dc07e42bf04ccaee53328273071e9f32cacd4fc7d5cac043f182edbe5c2658f73092
+
+Count = 44
+Adata = f1aa7f72
+Payload = 52d5c53ee4f23cb050a95db54112b44033c34ac31de96be8
+CT = e8a6ea9b79d9d1cc5f613e92935e26afa1bd8ae664264473b8234f3fbaca3dc2c497418219151b05
+
+Count = 45
+Adata = 6b1013aa
+Payload = a302aebc0f8fd61badc8371991beacf5933de46effacb8ce
+CT = 1971811992a43b67a200543e43f23e1a0143244b866397558fa5f9539e0500f139016e4a4337d86b
+
+Count = 46
+Adata = 33028129
+Payload = f7d653c23254875625b20e1ef60ae92847046d84bb4ce857
+CT = 4da57c67af7f6a2a2a7a6d3924467bc7d57aada1c283c7ccfa2379fde155e64b5b84e336056445c3
+
+Count = 47
+Adata = 2cab4a09
+Payload = 872a3f7230e626abff519e5aeecc93897249405daeaffc98
+CT = 3d5910d7adcdcbd7f099fd7d3c800166e0378078d760d30358208335cb81e4fb10923fca4ddb9ff9
+
+Count = 48
+Adata = 73142ba7
+Payload = 766f94e7d9b1ce74bbaf2c99d215350f060122767fc1953f
+CT = cc1cbb42449a2308b4674fbe0059a7e0947fe253060ebaa42d6ecfb49ac8983415503efef1e21950
+
+Count = 49
+Adata = bc9f967e
+Payload = 5f089ed9267363bc23c6c7b8f73208a36f61fa8ea8084ff7
+CT = e57bb17cbb588ec02c0ea49f257e9a4cfd1f3aabd1c7606c1978a62d15430fc20b87940292b49641
+
+[Alen = 5]
+
+Key = 54caf96ef6d448734700aadab50faf7a
+Nonce = a3803e752ae849c910d8da36af
+
+Count = 50
+Adata = 5f476348dd
+Payload = c69f7c5a50f3e72123371bbfd6bdf532b99ef78500508dfe
+CT = 20c43ad83610880249f1632dd418ec9a5ed333b50e996d1a4e5a32fbe7961b832b722bc07a18595b
+
+Count = 51
+Adata = 07db8aada5
+Payload = 9cf8b638f2b295b85cf782fabab11153dc091b4afcd761a9
+CT = 7aa3f0ba9451fa9b3631fa68b81408fb3b44df7af21e814d401a2222443696021b5faa520129b563
+
+Count = 52
+Adata = 31ef6561ff
+Payload = 62b8263dc015ef873cd16272e4da89799b910f2b04204420
+CT = 84e360bfa6f680a456171ae0e67f90d17cdccb1b0ae9a4c4f842681d2e90da5718234ed893197662
+
+Count = 53
+Adata = e97dfcbafb
+Payload = 810bed3a2bc0f9d75389155b7a39d9d014c08646814f9718
+CT = 6750abb84d2396f4394f6dc9789cc078f38d42768f8677fc33a08eb30ee154f71279682ab02eff27
+
+Count = 54
+Adata = 4981c51fcc
+Payload = 063d23fc3ec344c1ba3486802e01e55617455d5cfbfb5279
+CT = e066657e58202be2d0f2fe122ca4fcfef008996cf532b29d8d3071c79f0cf86fe4148cb5e8ace0ce
+
+Count = 55
+Adata = c8437dba76
+Payload = 41db5b245ea0fab985b93e7fc0a00cd3cca5bdbb642b7ebf
+CT = a7801da63843959aef7f46edc205157b2be8798b6ae29e5b842700619dc1599603f3f3f6cfdf5e0b
+
+Count = 56
+Adata = 6f65a24344
+Payload = b0e36734b2ba871d59df0b029c7f32af68e003a689ac4911
+CT = 56b821b6d459e83e331973909eda2b078fadc7968765a9f539a0cd8d8bbf211b907f34411f868c79
+
+Count = 57
+Adata = cd62d6d203
+Payload = 747e53e627eabde0cd77d78d1bd720bea518f8a2f76e57a2
+CT = 922515644109d2c3a7b1af1f1972391642553c92f9a7b746c4a90e5fc11266bab77eea1d24fbdbb9
+
+Count = 58
+Adata = 9663b3c8e6
+Payload = c70c92ec4c518802662fa4c41a6a33a22599f79f8f7264b3
+CT = 2157d46e2ab2e7210ce9dc5618cf2a0ac2d433af81bb8457b3c1246f7dd6462ce757db82db45f36e
+
+Count = 59
+Adata = 35c4720d3c
+Payload = a26835605b66fc08abdbb5dc77e39783d60b8e8f2314e95f
+CT = 443373e23d85932bc11dcd4e75468e2b31464abf2ddd09bbd472c06a5f4c04f97d06ec401d3e7fd9
+
+[Alen = 6]
+
+Key = cc0c084d7de011e2f031616a302e7a31
+Nonce = f0b4522847f6f8336fe534a4e7
+
+Count = 60
+Adata = da853a27aee2
+Payload = 15b369889699b6de1fa3ee73e5fe19814e46f129074c965b
+CT = f39755d160a64611368a8eccf6fcbc45ef7f1f56240eb19a2e3ca4ec3c776ab58843f617d605fd72
+
+Count = 61
+Adata = d4ed4584678e
+Payload = a18c0460b56a5bcd5bf6842cec6ed44d90b2bfa968a6a7e7
+CT = 47a838394355ab0272dfe493ff6c7189318b51d64be48026327804c44c8f17a4446a3d5ba85f9c7f
+
+Count = 62
+Adata = 590a27721a36
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = a7eadcb559a39501de6924b5e07bf12be89c6b08be689c0bbcd00e9cb726d75e4283820ee81d933a
+
+Count = 63
+Adata = 58830fb0b1f3
+Payload = dce983e4e3734a9bd8848dba0d744d07bbeba602f4006025
+CT = 3acdbfbd154cba54f1aded051e76e8c31ad2487dd74247e4d5d71a1f0f1b6518c35f0632a30931fd
+
+Count = 64
+Adata = eedd0d767a25
+Payload = 4653b3e879ab18b65c5c3706a5139698262cb830a22d943b
+CT = a0778fb18f94e879757557b9b611335c8715564f816fb3fa3ad112899e9ba442660eb5dfe33b2f96
+
+Count = 65
+Adata = 618bcf2e3e79
+Payload = 8586383281925363ac15fb19c26d64c639c75920c792dc2c
+CT = 63a2046b77ada3ac853c9ba6d16fc10298feb75fe4d0fbed54fba446028919342b2fe86ee67efcc7
+
+Count = 66
+Adata = 549c9b84c7f7
+Payload = 95c25ae4445cd8c4d267df82687484667e309992fcf1e737
+CT = 73e666bdb263280bfb4ebf3d7b7621a2df0977eddfb3c0f69fc23013142f62881ccfa3037067e1ef
+
+Count = 67
+Adata = 92d7fa6a8135
+Payload = e58034bbb0e6f5e724e32ee56896dadae25c2a3efb8c6f2f
+CT = 03a408e246d905280dca4e5a7b947f1e4365c441d8ce48ee8263568d56fae8bf35b2f2cdecbffe0a
+
+Count = 68
+Adata = f43e126c0f83
+Payload = d98f0dddfe9cb3cae1336970d5efb55316a65e2c51e316f4
+CT = 3fab318408a34305c81a09cfc6ed1097b79fb05372a13135de2c2fbfdddc7dd6672714af174c5121
+
+Count = 69
+Adata = f02074812dde
+Payload = 548747b1669c6383b793054d93957f9e99d605761c6c23b5
+CT = b2a37be890a3934c9eba65f28097da5a38efeb093f2e04743704560ff23ce0000fba8812c45940ad
+
+[Alen = 7]
+
+Key = d7572ed0e37261efa02f8c83e695efdc
+Nonce = f4f96d7b4384a3930b3d830f82
+
+Count = 70
+Adata = 922340ec94861f
+Payload = 1edef80c57d17f969f8bde10ab38a1a8811a124de72c526e
+CT = de14558cc686e1836f1f121ea1b941a9ebd4f0fb916dc870fd541b988a801cb5751c7faaf5b0c164
+
+Count = 71
+Adata = 4eb379f21b1531
+Payload = ddd5282a207c1dcb03c1c3bbc9eb12a7bd28534118db2735
+CT = 1d1f85aab12b83def3550fb5c36af2a6d7e6b1f76e9abd2bc068bd1b1c309dfbd52d9a24be07c630
+
+Count = 72
+Adata = 7fa89e9d6e3fec
+Payload = c5b7c462eb166f48bb59c8102ee7b3dc67a28e5de7570c51
+CT = 057d69e27a41f15d4bcd041e246653dd0d6c6ceb9116964f2d114d6ab082738d05d60acca8e8ccfb
+
+Count = 73
+Adata = fda8665f87c618
+Payload = af793815e147e3180f5146aa6a582e343dc479f26b4226b2
+CT = 6fb3959570107d0dffc58aa460d9ce35570a9b441d03bcac1cc84bd77fe00e1a13433f2c10e3b799
+
+Count = 74
+Adata = 46bde207491ebd
+Payload = 47c76a0bbd5b1616b278089d41a050c509c7a1c280574bf7
+CT = 870dc78b2c0c880342ecc4934b21b0c463094374f616d1e9990c81f1bae32c953bf02ddbde047632
+
+Count = 75
+Adata = a799f5f895fd7a
+Payload = d554806ffc3900a0952a3c094c745808950697a6e5d62c1d
+CT = 159e2def6d6e9eb565bef00746f5b809ffc875109397b6031af19f1f080dd1dd2da799059755e49f
+
+Count = 76
+Adata = 20225831a9ee06
+Payload = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b
+CT = 7a8f4c050fad7d7754decd18abcfa88ac9a738da00820b2523d3b9a0060834ac4860dae0eac570ef
+
+Count = 77
+Adata = 785360916464eb
+Payload = 57bc338946ff78cf76adf5021e2e44e34e687fb68ad703f3
+CT = 97769e09d7a8e6da8639390c14afa4e224a69d00fc9699edff96e7cf841a66c50bbb6fb2bac7ef51
+
+Count = 78
+Adata = 57b946369226db
+Payload = 9ac5be9929c4fe5a9992749a38dc69874866db3d4747da97
+CT = 5a0f1319b893604f6906b894325d898622a8398b3106408986e1c33a45f9d52755c374650635bef6
+
+Count = 79
+Adata = 73e4da8973c1e3
+Payload = 5a05410aa3a71f5f1a253b8576eba269c06a4c30591144cc
+CT = 9acfec8a32f0814aeab1f78b7c6a4268aaa4ae862f50ded2d78592c2d89c15edc5bb7486aa93f896
+
+[Alen = 8]
+
+Key = 98a42d7a0c5917deaf3b4de3f0cbe0a1
+Nonce = 03d33ab0c2df7bfce88b5ee4c4
+
+Count = 80
+Adata = 2d5438b728b950d9
+Payload = 9aa9c8358117564371366beeec923051ef433252197aaad5
+CT = 9ff942baa60f440c17a78e9581216b9a947a67f04d54911feecfff971fdfaa856310b014aa59c978
+
+Count = 81
+Adata = 6e430b497a16e7f5
+Payload = 5758a500978c71a9b90f6e5beae9d96ef05a41486b10ea2e
+CT = 52082f8fb09463e6df9e8b20875a82a58b6314ea3f3ed1e46a4d7b4b4df6c831ee32116ee4dad98c
+
+Count = 82
+Adata = e12f98507d6514c3
+Payload = 49efe18c76a8355127d914a3a830c1c6ff2a163d728526e1
+CT = 4cbf6b0351b0271e4148f1d8c5839a0d8413439f26ab1d2b3243fc75cd1624e152f451678edcac87
+
+Count = 83
+Adata = eecf8d641ee0bee9
+Payload = 49ae2309fbe6ce4e9421516b8f79ae64b1316cb849eaf638
+CT = 4cfea986dcfedc01f2b0b410e2caf5afca08391a1dc4cdf2dd6d8ca57da1880e1baff43736b3da34
+
+Count = 84
+Adata = 9066367c784de0a4
+Payload = b1bda5fa4242aa6aad0f5a5b1d31d86b8d4a97588b3e315d
+CT = b4ed2f75655ab825cb9ebf20708283a0f673c2fadf100a97f05439a661001513a96b896de46b7081
+
+Count = 85
+Adata = edf848b2510f7803
+Payload = eaa8608f6763d968576a7e89056b9828a1686c8441b06377
+CT = eff8ea00407bcb2731fb9bf268d8c3e3da513926159e58bdcf20709b2dc2ff9946094190b5ea09d1
+
+Count = 86
+Adata = 0f49cae81c8628d2
+Payload = f32029cf51609f0df9832ad1b283ea94a5356f70112c1328
+CT = f670a34076788d429f12cfaadf30b15fde0c3ad2450228e2a5bb6b4f87b9b198665203e4fdf9e7f7
+
+Count = 87
+Adata = b0c47e9cce46a276
+Payload = 7a550ef9254a8da6e4fee290a76ea838ffb61d3533d4d31f
+CT = 7f05847602529fe9826f07ebcaddf3f3848f489767fae8d529f416f89f1a34bbbf2ce40d943c6d8b
+
+Count = 88
+Adata = a6fe7c9ce2d49f85
+Payload = e67c486dd7ba9a9061844b9354f55890321ae626efaa28cc
+CT = e32cc2e2f0a288df0715aee83946035b4923b384bb8413067eb95550b91b955d5c2d72d5c189b704
+
+Count = 89
+Adata = eb1d11cc4876f58f
+Payload = 35f2c810091e930a52e4a3f28c9c8184967f1554c2675eb5
+CT = 30a2429f2e06814534754689e12fda4fed4640f69649657f0e8e8a5a7e0ea6860bab4a4320f03ae5
+
+[Alen = 9]
+
+Key = 2a68e3fe746f593c1b97cb637079c3e5
+Nonce = cd62d0f27b7f4864dc7c343acd
+
+Count = 90
+Adata = abe4f1d3812bfe3ccf
+Payload = 13b4a874888db0e5d8fd814b5e7e04f7fdfbc1601ccc02bc
+CT = 032835a3dbf688d09cf2a32a92b101959d33ff47500f92f4fd49840440f866d1a22b0854996111d8
+
+Count = 91
+Adata = 2e21f466814d3d6340
+Payload = 08b5c773364cded74d7b308984313c17ff90eed496a27a2b
+CT = 18295aa46537e6e2097412e848fe39759f58d0f3da61ea63de2f5c335df537fbbc6ae59cd562732f
+
+Count = 92
+Adata = dba22aabcea0e694fc
+Payload = bbac1790abb7aafe272ec472c897e6363e335b3c4126c762
+CT = ab308a47f8cc92cb6321e6130458e3545efb651b0de5572acc5ed6e4a907ff4742ab6c835a427f92
+
+Count = 93
+Adata = 97e9d16bd757395ec1
+Payload = 7249612dc09809bbca9dd311e720f7da2cb54ce33e3eb9c3
+CT = 62d5fcfa93e3318e8e92f1702beff2b84c7d72c472fd298b1714b5a3df454f3bc35869da75adc882
+
+Count = 94
+Adata = 866cf710470cac74d3
+Payload = 060ae0ab9857324a3b2ac79f3b6e6f90f5de884ce9c7b930
+CT = 16967d7ccb2c0a7f7f25e5fef7a16af29516b66ba5042978aa33dffe2596832f98a9c8413bd898b9
+
+Count = 95
+Adata = 2dd7a7f832b29ccce2
+Payload = f77a9fd5363836deefd34e1bea0882484a7ab746b4495d59
+CT = e7e6020265430eebabdc6c7a26c7872a2ab28961f88acd11dd5049f7c53d6a7fe5d7f959689ee960
+
+Count = 96
+Adata = 502349a60e897356b5
+Payload = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34
+CT = 868d1068b64f0cedead7a50869faee6eeb9077fbed0b8c7ced9c3a0d0de8788471c5f6c2f9638b7c
+
+Count = 97
+Adata = debed45c9acf129268
+Payload = df5a47d3eb5c0b6cabb6711a45400602d205b82ecae9e849
+CT = cfc6da04b8273359efb9537b898f0360b2cd8609862a7801d49b4b9bead1b7de2021cff280d6f93b
+
+Count = 98
+Adata = 2726702dd62a6e5344
+Payload = 5a7649cb001fbb6f653cbca17756c5c1a078c2e240d92085
+CT = 4aead41c5364835a21339ec0bb99c0a3c0b0fcc50c1ab0cd69df31aba209d87ee22bd6a1dcadb168
+
+Count = 99
+Adata = e8006cfb0536696ac7
+Payload = 95186d41f927cdbef42157f21d966e88061b6558b5ec932f
+CT = 8584f096aa5cf58bb02e7593d1596bea66d35b7ff92f03677cc5b60c881fe834a789d28447d8fb54
+
+[Alen = 10]
+
+Key = 46b067cf9b1a28cf187002e90b14e130
+Nonce = bad8c03292bf01cfd8d34f860c
+
+Count = 100
+Adata = 8d65880eddb9fd96d276
+Payload = cc0915194218d4536e467433cd6d79ff1d9eb9ff160ab684
+CT = bd56edc015692c6ab9bec493a9893863598414a3d11a6a0f27ecdcb257d0d30491e5bf1aa8f90958
+
+Count = 101
+Adata = 8a65cde13149d9d54a5b
+Payload = 28257133b1d8b0b2be4faecd6e819ac783707a5c5f50c302
+CT = 597a89eae6a9488b69b71e6d0a65db5bc76ad70098401f89b10f9fc201e4128696dcd899dd2e24ea
+
+Count = 102
+Adata = e999ec3e1bfb25b5877c
+Payload = 96ab0cfc204bafc4f5851d6c682d631d0c5ad03ac925a943
+CT = e7f4f425773a57fd227dadcc0cc9228148407d660e3575c8c522e5ba5adbc6a639cbd06f103ebc9e
+
+Count = 103
+Adata = a8554441e073d6065dce
+Payload = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+CT = 21cda08aff3bcbc6eed9e44483d3ae5dc9d564d38a42e922e1a4e0f7ebc3cff3915d27971cce7e91
+
+Count = 104
+Adata = 838f0be8d04d28d77549
+Payload = d0700658d5f4010ff21091f3d119c99645e339198029c3a9
+CT = a12ffe818285f93625e82153b5fd880a01f9944547391f22c215c88d80bffc881aff10ba40f11976
+
+Count = 105
+Adata = 20f014d928d5b25fbaf4
+Payload = 4bdf28748a0c281dd49c7294ae8e55fe7a52d45ff6384db3
+CT = 3a80d0addd7dd0240364c234ca6a14623e487903312891382cc9391bc06aa6ca9d486a4e2a218c54
+
+Count = 106
+Adata = 56c026b8a71974ff7ecd
+Payload = f75db057f0276fff85014f54ecdec8f90b96a2a982db14cb
+CT = 8602488ea75697c652f9fff4883a89654f8c0ff545cbc840778b05c6c582a0bb7d1d9dcf6a46b9f6
+
+Count = 107
+Adata = 75c3b9e52648a4f9aca9
+Payload = c15c554169dbb9b08494afaa44819a10dc9ddad54199ab54
+CT = b003ad983eaa4189536c1f0a2065db8c98877789868977dff47d9ebbd3cff14623b10cecc94b53d6
+
+Count = 108
+Adata = 1c76c3014a14b7fa1ca8
+Payload = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032
+CT = 68b10e2ecf8d9031bd55ac7a099d37518bfc15f3b3495cb9d2b74b84dc170c00dce85b56e346a976
+
+Count = 109
+Adata = a4eb60d4eb7ead1bd0e6
+Payload = e06e5dba5ac35cfd07949e5cc12ad70507d4a86a952ecca3
+CT = 9131a5630db2a4c4d06c2efca5ce969943ce0536523e1028d92e19fd8b5c1fcbff36adaa5e47ae84
+
+[Alen = 11]
+
+Key = e94dac9c90984790a7c0c867536615ff
+Nonce = c19f06f91e645d4199365f18c0
+
+Count = 110
+Adata = 537038b5357e358a930bd6
+Payload = 4d64461c55eb16bf7b9120f22be349598f2f394da8460dc6
+CT = e9fc5004c2359724e1e4411ae6f834ef6bea046d549753c88790c1648f461a31c84e62ea8592a074
+
+Count = 111
+Adata = 7e3d7b3eada988668f3784
+Payload = eab7d5dbd91d4cbbac8d79fadd70b5dcb3baadac5cb713a3
+CT = 4e2fc3c34ec3cd2036f81812106bc86a577f908ca0664dadacb1d1c9231d2c22ecfeed622792dfd0
+
+Count = 112
+Adata = 78b107b29c4878ff18f749
+Payload = 3c6ae2e2578875a1f5611582528e058aece2ddc33a4dde3d
+CT = 98f2f4fac056f43a6f14746a9f95783c0827e0e3c69c8033fffe60299768f048e7098033cde046b0
+
+Count = 113
+Adata = d293908bb516c5f3a411b9
+Payload = d7a46e726ed43f1580eb52141a93390982cc809dc833e3f0
+CT = 733c786af90abe8e1a9e33fcd78844bf6609bdbd34e2bdfe4ee6ebc0d90a0de05b428495c93e1801
+
+Count = 114
+Adata = 33ef208faad4d2948c9e67
+Payload = b1fe5d9d34157193fc0608cd8ecb872e17720f5f6814a466
+CT = 15664b85a3cbf0086673692543d0fa98f3b7327f94c5fa687e7e64cc0fcd6a92c79ceb6ce2abd8ee
+
+Count = 115
+Adata = b7f7ed9ccac3c2b4fbfee0
+Payload = de6bb539fb7a9c87414f62a7cf25a4cfca176509e991af41
+CT = 7af3a3216ca41d1cdb3a034f023ed9792ed258291540f14fb02b53bc779e0976b634b0d1b88fc0a9
+
+Count = 116
+Adata = a6e287383927f76e4927af
+Payload = 8719d20c20c8959068b8adcd65e6f6bc7b3693828f0735a0
+CT = 2381c414b716140bf2cdcc25a8fd8b0a9ff3aea273d66bae3c37fa936243b393f07fcccb0fc13e41
+
+Count = 117
+Adata = 70828be6dd93954f4e7b6b
+Payload = 30b39426831f61c8ba5f2ef5b71f0c4b2f916e3b5a578110
+CT = 942b823e14c1e053202a4f1d7a0471fdcb54531ba686df1e0d7534a489e6d242966ebea4455f8f79
+
+Count = 118
+Adata = 506015fc2831df293f4da0
+Payload = 818d5d810f678629f078723f5c6c3657271077533bfb7c29
+CT = 25154b9998b907b26a0d13d791774be1c3d54a73c72a2227ccbf64f04e95b180d09e843847d22104
+
+Count = 119
+Adata = e9394b0245b379e68e3dea
+Payload = f0613205a7a0822849df9e8a3cf6caf281f3adfa966c5507
+CT = 54f9241d307e03b3d3aaff62f1edb744653690da6abd0b0927b546ef8cd717073832584fb25a0645
+
+[Alen = 12]
+
+Key = f6bb5d59b0fa9de0828b115303bf94aa
+Nonce = 05358f33e1fc6a53ab5a5c98ce
+
+Count = 120
+Adata = 040b25771239cc2a39446e3c
+Payload = 011fc50329bfd63a85ebd4f7693363602f1a4147371270b7
+CT = 4432d7eb42980734d34f19c50cf8abf71ac1b19ed75a727854e5d050a405f755047d09cb0f49546a
+
+Count = 121
+Adata = 50a1d37fa2f3462bd304631b
+Payload = c90e40540d372ab1eb00ea5d5b8de5bf7c94ce4e376d6949
+CT = 8c2352bc6610fbbfbda4276f3e462d28494f3e97d7256b862abee8547ee3f24cfa677468ecc1d121
+
+Count = 122
+Adata = ac3bb872a41df35e415d2b0c
+Payload = 9e7be78c0ab9e6a4c6c257e77c63681bea35d951f168b0c5
+CT = db56f564619e37aa90669ad519a8a08cdfee29881120b20a61cef865ce4080e7c7abfc43f62c03a3
+
+Count = 123
+Adata = e3106ae6456153dd922640a1
+Payload = 00df0c5a5d3eceb2bd293066529799544f846672a9a1d31b
+CT = 45f21eb236191fbceb8dfd54375c51c37a5f96ab49e9d1d4e1d19c321a1e0852adba939b447220ab
+
+Count = 124
+Adata = 297b4498bf5427e6341aa927
+Payload = 14967a0476dbaea03b07fa8d40d344eabaf479be2443243a
+CT = 51bb68ec1dfc7fae6da337bf25188c7d8f2f8967c40b26f579ea5fb65018abdcde1a39f6859ecb56
+
+Count = 125
+Adata = 5de60dc0e3b5bda0b33a9520
+Payload = 2da3716d76d10b6766a1f9cbf9f420316fd5f396e7b9a2ba
+CT = 688e63851df6da69300534f99c3fe8a65a0e034f07f1a075c2629ff871ee15745fd8c1ddbdae4c29
+
+Count = 126
+Adata = 1c9b8541943ad50b4243c179
+Payload = 8c1b3ba18d1f5cff74a457aadd6b3e7d093d06ad2622e6a0
+CT = c9362949e6388df122009a98b8a0f6ea3ce6f674c66ae46f04e198ad16ad1106d3ba6172f4a13a8f
+
+Count = 127
+Adata = 51e926d2542ac8faef61465a
+Payload = 88936e97db070c0ec2aa58d1c6f5b34df3d32ddf7db34a8b
+CT = cdbe7c7fb020dd00940e95e3a33e7bdac608dd069dfb484475981131e3934ec6d41e00d502729799
+
+Count = 128
+Adata = ebefbac97b363e6f32526aac
+Payload = c20742e4b410c5b661da373a905fb0ed55b20e0e879eff5c
+CT = 872a500cdf3714b8377efa08f594787a6069fed767d6fd93e2c005b5bebe07ff578b1b4bc51971cd
+
+Count = 129
+Adata = 1ef059ac7d648e9e32d9b1f2
+Payload = 65c55ca21a89a8325365bf2be861d700559de2eabb41b37f
+CT = 20e84e4a71ae793c05c172198daa1f97604612335b09b1b021a25f15b5b4229a872a9199972c85b3
+
+[Alen = 13]
+
+Key = d1da2e961e78063af8de41865b226873
+Nonce = 03739f5474857006340cce554d
+
+Count = 130
+Adata = e3afd091d2b588465872a6300f
+Payload = 8e5fa1a6662a8378cda15697e926841594f2f394fa5a34ab
+CT = ca0d95e3ff186ad6b88d45fc4079e6b7b4a615e7e8dd5f4742d522cc9dc19c47a4fa0b1528069cf8
+
+Count = 131
+Adata = ce3186bb737753b59ee76b748c
+Payload = 311ebc5ff2f625944562ea699b2690df3e6e64a17c62bd3a
+CT = 754c881a6bc4cc3a304ef9023279f27d1e3a82d26ee5d6d659b26510b8f25610799e011d7c850ecd
+
+Count = 132
+Adata = bfd636989dfbcb0edc9f014cc8
+Payload = c96cee5ba7b799f16254a17b1870cdb85fe0ef3f42110c13
+CT = 8d3eda1e3e85705f1778b210b12faf1a7fb4094c509667ff52942aa0d39649f3d9ed535bebc2b603
+
+Count = 133
+Adata = 4812b092aa59d57451bfd812c3
+Payload = 13b1b4404dc5735655139414fcbd02c5327ae9fb148bd324
+CT = 57e38005d4f79af8203f877f55e26067122e0f88060cb8c8c1e61efb9c1d84ddac2d24f43531f569
+
+Count = 134
+Adata = f6ef9ac4f4c9ce1e4309c64fa8
+Payload = 6c5b59319e2710f5d63407f85b424d1860425ef8ce0cfe53
+CT = 28096d740715f95ba3181493f21d2fba4016b88bdc8b95bf13350de0ef34df12fb945b0ae0a0d9bd
+
+Count = 135
+Adata = 9bf12168bb3d79ebd25262f2b4
+Payload = 968e1d78008da78611e82985c4028e86770858cfe61c3723
+CT = d2dc293d99bf4e2864c43aee6d5dec24575cbebcf49b5ccfa0734563638598d8c4bf1fcd94009925
+
+Count = 136
+Adata = 7d870d7e52d3053c65eefad477
+Payload = 6a1306d911434cc7400d2f9a95e36aedceddca2b3d583f51
+CT = 2e41329c8871a56935213cf13cbc084fee892c582fdf54bda1f5fc53b08aca82bccfba6fbcb27e69
+
+Count = 137
+Adata = e95099f04371e445e5eaa1d80e
+Payload = b9197eb50c8168d16b8a12bd261d553ffcc521d979b26fee
+CT = fd4b4af095b3817f1ea601d68f42379ddc91c7aa6b3504027d1a922953facbd630d7fea6b63594ec
+
+Count = 138
+Adata = 3e80eb03db6545204ef4241ad6
+Payload = 95f59e36eac8eb3b51709d635b07fa2da0976ea20e25807f
+CT = d1a7aa7373fa0295245c8e08f258988f80c388d11ca2eb9383fa000d10078256b71249d9d1f1846c
+
+Count = 139
+Adata = 9748798c0f3cc766795c8ce0e4
+Payload = a48db9add9ecdeb49e51d3ab7bb2075202ed2aa50c0195b1
+CT = e0df8de840de371aeb7dc0c0d2ed65f022b9ccd61e86fe5d2773c2f55b752477c489facee812c614
+
+[Alen = 14]
+
+Key = 1eee667267ef10b03624cf9c341e3f75
+Nonce = 0630a3eae27e505c61c56e6560
+
+Count = 140
+Adata = d24651ef0561282d3e20e834960c
+Payload = 798e31cce0a83702a95171fb1162a17b9ce00ec3592ce262
+CT = f3c3e52f1a1ff528a8d3783ee4e75f114e3e6416334815d2d9236d5c5c9319092078411b72c51ba8
+
+Count = 141
+Adata = c527d309ab29ee91c5fc53117e71
+Payload = d79cd4c8891ec4ce2c51136712d23b32266b2b73768aeb1e
+CT = 5dd1002b73a906e42dd31aa2e757c558f4b541a61cee1caed8ad2a48cb734e3f93e602c15c7c775e
+
+Count = 142
+Adata = a93dfc3944514ddfc5acdd89fab7
+Payload = d7fa81c949f1f2af29dbd56529b307e3b348e996d0936455
+CT = 5db7552ab34630852859dca0dc36f98961968343baf793e5f34b297f3f106a9cdae255f7634fbd0f
+
+Count = 143
+Adata = e502abe21c7b22120693a08ef3e6
+Payload = 6330caaeddf0473d564d175b9408c6f12e6d3cd4ee2c423f
+CT = e97d1e4d2747851757cf1e9e618d389bfcb356018448b58f4f5d9c3dbfe3e2fe03a002e55039ebe6
+
+Count = 144
+Adata = a49b34dfad43333fb2ffd701a2d6
+Payload = 45671482c390e65f75de15ca91b93596e9bf3d6fc9178bcb
+CT = cf2ac06139272475745c1c0f643ccbfc3b6157baa3737c7b6f7bb0749c99d75740f2d193fef36c60
+
+Count = 145
+Adata = 9e4d8aa3dbdc4d4b4b8d72734f52
+Payload = c8f34bea8bdc403a48d8ed9268429141cd03c29558050ef4
+CT = 42be9f09716b8210495ae4579dc76f2b1fdda8403261f944ceec82fc674da9efa6926e8641729ed8
+
+Count = 146
+Adata = 052327ad59cc791259817fd0ed96
+Payload = d8d1c57b16c23894b66023c29f8648ce4a6074647e1f5f69
+CT = 529c1198ec75fabeb7e22a076a03b6a498be1eb1147ba8d92ff19e93f60c8f3a511300fddc38ee59
+
+Count = 147
+Adata = 14bc3c44c001ccb261a2a0526523
+Payload = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b78
+CT = fb8c9e93cbb4ff9b5a7c2a72aa6863c55a58b7c4534efcc87fa00fb244eda0d77cf6c05c8fd590af
+
+Count = 148
+Adata = 3477384c396a9e9efb3e169722cb
+Payload = afa795f836763a1210bb36fef167864f73ba3b6abc593537
+CT = 25ea411bccc1f83811393f3b04e27825a16451bfd63dc287bae19612657c87d3bb73cfb8cee7c8a8
+
+Count = 149
+Adata = 0c3b9a6924ad506038cb2d6590c9
+Payload = ca4a186f116a179579e3d327aec3f5be358bc7094f853bc3
+CT = 4007cc8cebddd5bf7861dae25b460bd4e755addc25e1cc733d9713d2e916c23ac3039de34c295fc4
+
+[Alen = 15]
+
+Key = dbbd26f5d9e970e4e384b2273961be5a
+Nonce = 0b1eabe504ef4822542e397fec
+
+Count = 150
+Adata = 477937301c83ba02d50760b603e0ea
+Payload = 553714e17a208a2eceb847a4a2d95088388b1ac8d8ca43e0
+CT = 1c80213268bad5402c4dc9b5d836ab7499810d0d8a974716df9a0e986ab2890736423bb3772cec3e
+
+Count = 151
+Adata = c91eb5a07ff19c044023e5cf339203
+Payload = c94d0b9e728413c58202cb3f6b82dba7aa9e3ca0a72c40c7
+CT = 80fa3e4d601e4cab60f7452e116d205b0b942b65f571443139f907a92cb01215e3cda84ae13af48b
+
+Count = 152
+Adata = 38c71a8e9b279c605c7f0418a0afc1
+Payload = b4e8c4fd5ad98a1be8b5a11677c57ca1c1694e3528092aa9
+CT = fd5ff12e4843d5750a402f070d2a875d606359f07a542e5f3dbd8dbf7485106cdf9ea0e7088a5650
+
+Count = 153
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe8
+Payload = 578ce26cdb5ba2e8798e23588e5cd04ef782820b80e49a42
+CT = 1e3bd7bfc9c1fd869b7bad49f4b32bb2568895ced2b99eb4853fde6f4dca88ff11bbce20ed9e5012
+
+Count = 154
+Adata = 36004342dd74e7966692a848b2c11e
+Payload = 78733c635d4d4e8b0729732f1e174dfcec4e020a7ac3870d
+CT = 31c409b04fd711e5e5dcfd3e64f8b6004d4415cf289e83fbd94e979108fcecbd32f6bdf72f0ccb4d
+
+Count = 155
+Adata = db92bc3fe5d4141aeb39baea6f114c
+Payload = c7aafe7760945e45703c1e19f1032dfd56ddc216c3b03826
+CT = 8e1dcba4720e012b92c990088becd601f7d7d5d391ed3cd0229c8f9d4e39fc16cbdb44236ef125c7
+
+Count = 156
+Adata = 34ec2d5b6f0d950509b47a0637d74c
+Payload = 2345e36a63be0b78df95e60907c78da0e48e61e70685a1f3
+CT = 6af2d6b9712454163d6068187d28765c4584762254d8a5051c9ab7cb0a779c3fa78c9ee12603802b
+
+Count = 157
+Adata = 6ab658d177c2dd87c9b8787cd70182
+Payload = b0725f735543eb0c0ec88ae69b140f5787d28ef4a2e36d57
+CT = f9c56aa047d9b462ec3d04f7e1fbf4ab26d89931f0be69a1648c6307ec5ea304045a7cdc93f36b9d
+
+Count = 158
+Adata = 483f135c61250fa610b4d14b99ecf0
+Payload = 315a947bf5291278d446d332ee5ca0def7655d5c957a8fb4
+CT = 78eda1a8e7b34d1636b35d2394b35b22566f4a99c7278b42364ff3b1ad915347b1c7f062b10d3da4
+
+Count = 159
+Adata = bb022aed60819ef84ae83ce27db9d0
+Payload = f78d00755bcb45e6822121fe7cb03c8e627c9f548ccd7e7c
+CT = be3a35a649511a8860d4afef065fc772c3768891de907a8a7569808dab58d42181543b2e2d05992c
+
+[Alen = 16]
+
+Key = 10a7720f2e18f739c26924925af6b670
+Nonce = 8c4e7813ab9bce9dafee01c628
+
+Count = 160
+Adata = a209941fab710fda38d11c68b13d930f
+Payload = e59782a9aea45f467b90e51a0fdf166baba05663def2d8b6
+CT = e357b1ccdaca6f3506dc45279c2e4c59f5307a5fd6a99cd72341ea8c0785569973f90ee9ee645acc
+
+Count = 161
+Adata = 2e2f6f9755a492ee54df77b2ecab9808
+Payload = 042a072f6ebf11f79fcb4f5a64f7946dc837d9d2355785ea
+CT = 02ea344a1ad12184e287ef67f706ce5f96a7f5ee3d0cc18b703eb81224cdb1fd2e1cfb2fbfe1e402
+
+Count = 162
+Adata = 99e98c9983c85d1f49ae43ebad67a652
+Payload = 5db6bda27910e7b8b61ac476c6532570b71b3932bd6a698c
+CT = 5b768ec70d7ed7cbcb56644b55a27f42e98b150eb5312ded64c4aea7f17f18f068897557c93ffaaa
+
+Count = 163
+Adata = 37a837d73fa15793f6f823fb99c2ea74
+Payload = 8cac261a461c3ddd2642b8e4e5c3389e491fcb2ff8356412
+CT = 8a6c157f32720dae5b0e18d9763262ac178fe713f06e20736f3b2e70e6e2dc7acc74a823a7f49722
+
+Count = 164
+Adata = 11119a4e779cfb64c736d425e4ff554d
+Payload = 3429f9b088b501d7944c462694d0799568282e7ce07d3e61
+CT = 32e9cad5fcdb31a4e900e61b072123a736b80240e8267a000dc3b57096f0df1d4eb5328c416921bc
+
+Count = 165
+Adata = 962d7d4305f23d1692747b504960c0a4
+Payload = a46ae4c71d4c9eb72fabfa76b8074aa02e07653eca10eef5
+CT = a2aad7a26922aec452e75a4b2bf6109270974902c24baa94f62ed804e9f2ac0f7001d0f35ea9f3c1
+
+Count = 166
+Adata = bbb1fdfefcf3657ba6cd93ff341a04e1
+Payload = 92f5e3083f57c77ac9553a2024a66489698bd2261f05d415
+CT = 9435d06d4b39f709b4199a1db7573ebb371bfe1a175e9074907dcd7ac1e0bb248d46c3036c39fb02
+
+Count = 167
+Adata = 74be126f7c596642dafa8fe3da904e69
+Payload = 41ecc3aae5cfebfad7921a47a0684601ffe73816380f8716
+CT = 472cf0cf91a1db89aadeba7a33991c33a177142a3054c37787cbb80fd21127feca7e76fd6947d5b7
+
+Count = 168
+Adata = d72cc521c90a468522af8966c24799f3
+Payload = 8850bdda4bd0271e333db344a47b837183eb48269c3dc0b6
+CT = 8e908ebf3fbe176d4e711379378ad943dd7b641a946684d7cdb5d1243b6e73b8e380d8ca041647db
+
+Count = 169
+Adata = 28f427fba8d0bb0380bbe5072ccfa519
+Payload = fdd3ca2f193f93f5a349b50357d26748b767cde6ab5cbfe7
+CT = fb13f94a6d51a386de05153ec4233d7ae9f7e1daa307fb864a0ae8604b103f882f17db893ed5c576
+
+[Alen = 17]
+
+Key = 6bffab1f4f4c1ff66b4a669b515b2f8d
+Nonce = ddb34d5e0140fb96d690e1a2b7
+
+Count = 170
+Adata = 5cbba9ea778e01af00afb2a934f28c7211
+Payload = d91b12e8655dd92b1332fc1d71c391c96a17111562d90ba3
+CT = d302e5b2d5d90433186b804cd7717e2db2f22cdc34fb2942ab30780a2c4f12af8f35350d65284c59
+
+Count = 171
+Adata = 1583138aa307401dddc40804ac0f414d33
+Payload = eeafb08d4a4819f5682a01d44371e34cc5729079e74e73a6
+CT = e4b647d7faccc4ed63737d85e5c30ca81d97adb0b16c514746577901b7f6feb88b8e2b8562f9cb5f
+
+Count = 172
+Adata = 23931c258c84086500c6a3b6eda457e6b5
+Payload = b8737d5bbfc976c2d8d9786148dea664dd83cee98df537b5
+CT = b26a8a010f4dabdad3800430ee6c49800566f320dbd715548735a59390ba7a892741694f3a89b0bf
+
+Count = 173
+Adata = e12f98507d6514c3b551d240595346bc9e
+Payload = eb021b63c61c0b194bd44870608d7ef0b932b6104412d7a9
+CT = e11bec397698d601408d3421c63f911461d78bd91230f548f4f81ed18cc1820375a7bec2318cde1e
+
+Count = 174
+Adata = e14b87d49d231c0199eec627fd7f1b5332
+Payload = 93b42584c4956078359d77e80aef52281b9228a1f66aa36b
+CT = 99add2de7411bd603ec40bb9ac5dbdccc3771568a048818a187b430caa60d98dc3e2aeefe6249b44
+
+Count = 175
+Adata = ca095aec96a8b093e62b10f0950ce35ce7
+Payload = 6a788d8238c7b313b8eba27b210a71c36819d719115b9b76
+CT = 60617ad888436e0bb3b2de2a87b89e27b0fcead04779b9970a77372b727408e1bf5a70790b9eba3a
+
+Count = 176
+Adata = d1cac02b34ad33c0e77a5bda2c3baf5e5d
+Payload = 3bc1ee54d0094603dfc68eee118e547d031fb36e464e776d
+CT = 31d8190e608d9b1bd49ff2bfb73cbb99dbfa8ea7106c558cdc1f5cb4d4fa2204e82eedcb3784443d
+
+Count = 177
+Adata = 065c06b49a49898e20bb679e35edbb1f76
+Payload = 8a12adb8b746216baa8a418725e608e4377f13816a036a10
+CT = 800b5ae207c2fc73a1d33dd68354e700ef9a2e483c2148f12413f9496592a75a1d6e42ee3a258607
+
+Count = 178
+Adata = 98a42d7a0c5917deaf3b4de3f0cbe0a191
+Payload = 30a226c07401d0ae24c73d682e3a6e7e377ec1613bafba17
+CT = 3abbd19ac4850db62f9e41398888819aef9bfca86d8d98f6b571a3150887df1ac5f813676b2eb24f
+
+Count = 179
+Adata = e245a7528931841b52a5f59d861d98d7b7
+Payload = 3d17bcdf30445ebd8a9b6aa2fe11d443c1161bb1ee69ced0
+CT = 370e4b8580c083a581c216f358a33ba719f32678b84bec3131aa5e4657c92e31c69ab18d447d3578
+
+[Alen = 18]
+
+Key = ae6136df9ab43631ef143515dacedbe7
+Nonce = c5c445792208a50c8e93d64aa3
+
+Count = 180
+Adata = e04006b68c83a5dd4ceac3cde238e48895ae
+Payload = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731
+CT = c7584c0203c2535c5702c6ae93b7cbfb066f4a055c627a180d6d676d11fce907b5c93fa1ed7bff2b
+
+Count = 181
+Adata = 5da64e368f45153ea5b7ddca966b6c5b699a
+Payload = 15e0c672c6764f3699d9d3e7120f8ce5daab166f08fdd074
+CT = b8f1b62e36c280a68fdacefb6a8ea6fb67012bca0351ad5d2cd45f211b1a1364c91ad07959bf0ee5
+
+Count = 182
+Adata = 1b315d024bb5d1e03d7510e61f37d8adb10a
+Payload = de907d58cd8f5a72acaa1d329b937dfbbfed65a4e45eb029
+CT = 73810d043d3b95e2baa9002ee31257e502475801eff2cd0018f021a98b2edfb0b7500363099c2a1a
+
+Count = 183
+Adata = 8691ba4f9232ca86f919fe72ddb39c91d707
+Payload = c7fa314d27be79f9d3e2d1e188c1785b0c970f91b8ed4290
+CT = 6aeb4111d70ab669c5e1ccfdf0405245b13d3234b3413fb92ac9aeb018c48f3902276ac759710b6d
+
+Count = 184
+Adata = ff0baf1cbb5884a9290ea7b5ee49915efb4b
+Payload = 33b05b20f3c849fac091a5028cbfa0bc9a1c32514136fee3
+CT = 9ea12b7c037c866ad692b81ef43e8aa227b60ff44a9a83ca7dac49f606dadb9f7034e0a1860d519b
+
+Count = 185
+Adata = 2d118cda20700bc2748ea1753fbca6f74933
+Payload = f43832e420e2eccd5d80502bea2ba1804e17d4433318fc86
+CT = 592942b8d056235d4b834d3792aa8b9ef3bde9e638b481af623ccbab19c1442806e21c5a820945da
+
+Count = 186
+Adata = 0c7a5fd2010c999a8a0efa81f89ff5bfefe0
+Payload = ceb203c842a962183f22e602644fc66e4290b3d5be445fb4
+CT = 63a37394b21dad882921fb1e1cceec70ff3a8e70b5e8229ddbcd18947ac1800856c9c92eb0388c70
+
+Count = 187
+Adata = 73fdddb9e0a64f5671fd70c4ea8443507789
+Payload = d6015b6bd5f5eabb2a649129f8f727c06a3ad59499f21caf
+CT = 7b102b372541252b3c678c3580760dded790e831925e618639c29ea73b0c5aa130d8b14f7b9926a9
+
+Count = 188
+Adata = 82c4484e3a6e18b6bbfd78b69b00c40b30c5
+Payload = c288b810fb533441bd549d02c0b28d5b834293683eaacda2
+CT = 6f99c84c0be7fbd1ab57801eb833a7453ee8aecd3506b08bf0a0f148ae138c2ea02538c8fd7ac76c
+
+Count = 189
+Adata = 267d8385b14721eded743cffd69e4d595f7e
+Payload = 667cc47d13c34923be2441300066a6c150b24d66c947ca7b
+CT = cb6db421e37786b3a8275c2c78e78cdfed1870c3c2ebb75285eb537e7583f04e040a0ddc41106213
+
+[Alen = 19]
+
+Key = f1908328edf2996ebfc9655472ca5ad0
+Nonce = 4c693364546930b6c5250e2699
+
+Count = 190
+Adata = 4a3634e5028df97fbe00eb016e8ea4f1918faa
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 90c850790b0b380f5aeb2488fdf43c9d5ef1759861e86f6e52570e769629dcc2e568737ba53a1195
+
+Count = 191
+Adata = 041b93e3fc059fa44aa755e88df277b9b6e499
+Payload = e61ca7310172eec16745a73e34516f65844eecd0dbc5566a
+CT = 980af6f885e3e6f2e2ba4a2bb3e020d1a87976ba1bf63feff1d82ec19a2e3ec43bbdb34e10999d90
+
+Count = 192
+Adata = d1be393376cb5d23cf8139da0fd92f3d520ae9
+Payload = ea887edee68ad5fa6bae928aa480dda898037f820700ec52
+CT = 949e2f17621bddc9ee517f9f2331921cb434e5e8c73385d7f2abb0ce4de9eeb5e8af9cdf3391d3cc
+
+Count = 193
+Adata = f3e551b34d2db1286a9f41085e4dda95ec3f75
+Payload = 71fe1ba5d299495d2a56039c64032ec6263d437f55e3f5be
+CT = 0fe84a6c5608416eafa9ee89e3b261720a0ad91595d09c3b239c73b01ba49a8498b5ff4833851069
+
+Count = 194
+Adata = a69ddc66e63a3415f21009d53adcf26bc1a9a5
+Payload = bd04d854216740a6ceb9827cbddd83761d19feb2a21d78ef
+CT = c312899da5f648954b466f693a6cccc2312e64d8622e116a2248dacd3903c26a2dc5ae649566ad67
+
+Count = 195
+Adata = 5735d6f5882d8f27155eb4cc285a65138ad64a
+Payload = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda
+CT = 4da219ba2330ed8378449366c0d371fb8dfb435d3e81065fd4156cf7d97b2e744351b6960a807cf8
+
+Count = 196
+Adata = 5d94ed976ab2063512690ae704c3b115519742
+Payload = d3909d577a4e89642227cc6fc146b61bc18392175e342898
+CT = ad86cc9efedf8157a7d8217a46f7f9afedb4087d9e07411d5a50086b6711ac72533c3c5717f6892c
+
+Count = 197
+Adata = db20b384620ab8691aed2fed14a745188d94c0
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c56699029
+CT = c41147fcdb6eb0dc1182c7006ce978ee33c69226965af9ac54fb74ecb9a5163b01b9dbf97ff2f999
+
+Count = 198
+Adata = 94897cdd04e0c8480b2ef7b5201dda37558ba9
+Payload = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9cc
+CT = 215d1e5e323b409e36cc81509d1d78cbf27d452d494cb049d2a81702f665ff5c54f586defd268c94
+
+Count = 199
+Adata = 95c44e1e5ad256b3ce1cc1d87137a1e09f1fd4
+Payload = 598e91d39c414496fd5e69f2cf80826b4e7d59ba28e0a0d8
+CT = 2798c01a18d04ca578a184e74831cddf624ac3d0e8d3c95dfa641889723e163825ab65727e8a5343
+
+[Alen = 20]
+
+Key = 61cb8eb792e95d099a1455fb789d8d16
+Nonce = 1f37b3e59137f2a60dc09d16ac
+
+Count = 200
+Adata = 09db3efac9473f713da630ae92c2c8604c61c51e
+Payload = 6ad541695a37c32d73ff6d5f870abd5b0f362a8968c4fce0
+CT = e65fcc975865c1499b088b58ba163283085d8ca68dc3b235d89756e5d78753ef22c012ae34b39a20
+
+Count = 201
+Adata = b6d07035aed9c141c713cc3bce60f7ba8ac2545f
+Payload = 9cce4c82fe9d38ef64ac8abdf0619f201a25ce6903675627
+CT = 1044c17cfccf3a8b8c5b6cbacd7d10f81d4e6846e66018f2fc78ebae9c143a7283b0641e1f83f5a0
+
+Count = 202
+Adata = 80a5ab693378af29cd5a33555cb3579f9ae540aa
+Payload = 7295a7aed3e987baef19ad68c33ba5a5dcbff27875ff5236
+CT = fe1f2a50d1bb85de07ee4b6ffe272a7ddbd4545790f81ce35a7e44348d2b3085348f787128a4e96a
+
+Count = 203
+Adata = 220817144a15a0a654fc1beaabce60270aa72df8
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 67ab73defe1d9021c3d1f8ab3067ffd9681fcf803af0ed2024dfc096cd8a09d2d81f6146fb54082a
+
+Count = 204
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01
+Payload = 23bf80f51dfd83f63986910e69d54a315c2bfb43f432b7de
+CT = af350d0b1faf8192d171770954c9c5e95b405d6c1135f90b5da82204f4dd8f535cb2fec2f133d882
+
+Count = 205
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe88436fdc216
+Payload = fc3a50cc8a68778327923ea697f5388da4c814381e29c5e4
+CT = 70b0dd32883a75e7cf65d8a1aae9b755a3a3b217fb2e8b31108630135498ba409f4b6c8caee8a85b
+
+Count = 206
+Adata = b40c8c1d2cee490653105ca2443356cdb63e4fd0
+Payload = 465e41c69928d08c33e063ea119595a04d0de6bffd17bba5
+CT = cad4cc389b7ad2e8db1785ed2c891a784a6640901810f570f89c515837d129ba41f9c24b0229ddcf
+
+Count = 207
+Adata = 6ebfa1e8f80b3cdb1bedf2e3c7e74f30f55c38e1
+Payload = 3f98ee3922f8f1086e3135ae66c5465426b13c8794954880
+CT = b31263c720aaf36c86c6d3a95bd9c98c21da9aa871920655a352fa6b9c4e40733ddcd3fcdaf9ae63
+
+Count = 208
+Adata = 6d0159861031c1a5f01aab35927fe2ab28154d19
+Payload = 5b43067a5ab3a9f9e633fdc084c44ffa7f11edd12ea5873d
+CT = d7c98b8458e1ab9d0ec41bc7b9d8c022787a4bfecba2c9e82c1aa13f062c0f1f5008e27ff2191942
+
+Count = 209
+Adata = 15e5ade017b30ab41878a2747e93aa91c61c2908
+Payload = e40b7e9e46e339e64891526e730b3bf6562fa37acefce307
+CT = 6881f36044b13b82a066b4694e17b42e514405552bfbadd2e149dd02bc7face0c4dfe4e501c2ac2a
+
+[Alen = 21]
+
+Key = be1ed49e2cb0caf6b6a0940c58453b93
+Nonce = b78ad129457681fa7346435b97
+
+Count = 210
+Adata = 161d92c7df1ebb0924719e066e08b95eb4914a5eda
+Payload = a9eec383f63892521e4616fcbadc5485942ffaf4669c43a7
+CT = 949be340720c4fdc4adc05cb777dd81a2549628d33fba07e62d2b338a7b34ebd9d85c244c952d681
+
+Count = 211
+Adata = 6b1d94bc0c6e45fc905c509ea667853e4b2c5a8848
+Payload = 7b44a093162bfc8b4d65f1031d890a6b08a3705b142c0c26
+CT = 46318050921f210519ffe234d02886f4b9c5e822414befff8a4defafeb3d61dad8c007b68d8fb9b3
+
+Count = 212
+Adata = 868dd3e241f60f097a7a2fe571307ee5eb961218ca
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447cad9d5
+CT = 15b1f61dba183895d001006a515cbc1b41858d2d12ad3a0c57cbab553b511d68a4f41db211d0a2fc
+
+Count = 213
+Adata = 3776f37fbf8803bdfd246ffaff2e59658a6c3f0ebb
+Payload = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+CT = 2ba665a3ee05875c14f0a8fc8e6c0034582e8802f3b699ab0290fd7dbf0afa3e597274e3c9fe170b
+
+Count = 214
+Adata = d0f2769eba9b8e618f00eed6b34c261c59322a253b
+Payload = fcbbcdd9599a86e7c8ccb9347065789a9728ca1220fa51ca
+CT = c1ceed1addae5b699c56aa03bdc4f405264e526b759db2139c7dec3960e6aba3174d793b4e08f449
+
+Count = 215
+Adata = 2be180892faed0bb75887668d187807666d3c66c68
+Payload = 8d145b1f792cc31a2e5b86216609bb018e7aea3012ff70a5
+CT = b0617bdcfd181e947ac19516aba8379e3f1c72494798937c7057b9e2d844e86ee5c3ecfb3270804e
+
+Count = 216
+Adata = 52859849a5b7c1d432c3bfb35271cd8141db2ec774
+Payload = 741db990b43ef34993c33d1c4953b67b128b9299dfe86d74
+CT = 49689953300a2ec7c7592e2b84f23ae4a3ed0ae08a8f8ead1150fa899152eef7a30ae0f20986818e
+
+Count = 217
+Adata = aa192759625f4e42d1d1fa73dc0f62199142155615
+Payload = 51dca5c0f8e5d49596f32d3eb87437bcae866640310ce1e3
+CT = 6ca985037cd1091bc2693e0975d5bb231fe0fe39646b023aba7ff9203608089558698ec29472dda7
+
+Count = 218
+Adata = 6de564226884188ec7bea3894535a875cff2a42fdb
+Payload = dfaa7aa8b28626210d5c24e2ddfe516189be05aabe26f3b2
+CT = e2df5a6b36b2fbaf59c637d5105fddfe38d89dd3eb41106b85bd0a5074ef852575baf5f12c22663e
+
+Count = 219
+Adata = f245f2ee23755df863dee55d7ef0c3c09a0b6f0b0c
+Payload = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc57
+CT = d3aa206931d9325331d3c04919e2d47ead3e145da4263f8e9eb617436bae012331daf020fce24e47
+
+[Alen = 22]
+
+Key = 34ab6fd7f54a2e0276fcb7cf1e203aba
+Nonce = 6091afb62c1a8eed4da5624dd7
+
+Count = 220
+Adata = 1ab5cc3d7b01dc74e6cf838bb565fea3187d33d552a2
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 0d30ab07153b5153637969e6bd3539448c541e42b3d432fd7ef14622a9b621d1721b944c60f7fd67
+
+Count = 221
+Adata = 1f1ac4674b272bc7a4ee9f4eae33e969b16fa90a69ba
+Payload = 14e99a2ef0de650adbd785c692342cdb765e6d20d5fca09a
+CT = 94cf7e706b44755193be855740cdcde455605601adf35bb6dfa4ec2c92671c64ee07946527be67f0
+
+Count = 222
+Adata = 43ee77f12ea42e82a02275a68aa95cbd1bb440442bcf
+Payload = 383242c709fe5f2ce782bf8c83b645d171f2bd238abc655d
+CT = b814a69992644f77afebbf1d514fa4ee52cc8602f2b39e71173572fbf3d9495760aae4347397b110
+
+Count = 223
+Adata = ae2ff288199be25bf640811541394ad7e1dd0dc0d24d
+Payload = 9c16a5b638c35c97c5c981c1b8dbcba11aec30e72e45a936
+CT = 1c3041e8a3594ccc8da081506a222a9e39d20bc6564a521a4d2327956e030b9df753e063b5b71201
+
+Count = 224
+Adata = 4ccfb4281852b5ca7e787723d689384a68ff9437db31
+Payload = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878
+CT = 6cbb6a8169cc55094068b67903b3cefc92ade051adea1354e4dac0c9130f5641afd035dd884b6271
+
+Count = 225
+Adata = d3a2fffc798fd9cc2f409471faf18caa2ff3dcf4e652
+Payload = 0db33eda4188a9165147e24e40f79fee1985eb68d5162728
+CT = 8d95da84da12b94d192ee2df920e7ed13abbd049ad19dc0448807dd50a9cf41651083c49c7493ceb
+
+Count = 226
+Adata = 7b5121aa4d1e314f209ffe3e92cd26ee4f74d91e27f2
+Payload = e0d3ea4308376423c4322503f56e427a64e2e6d8b4f5e668
+CT = 60f50e1d93ad74788c5b25922797a34547dcddf9ccfa1d448ea0da53046733f522ded40a09c6d7a6
+
+Count = 227
+Adata = 6e12c112720ef346bbbe7d1c19483721b1c52c438dad
+Payload = 491f2bca585d6b5fdf38d18890e4d1bc923fe26930b3d2f1
+CT = c939cf94c3c77b049751d119421d3083b101d94848bc29dd345cb5a968f39654b994686699d532c2
+
+Count = 228
+Adata = 20433402a2d869c95ac4a070c7a3da838c928a385f89
+Payload = f45908d691ddaf89c0bc129ffada94c3ceda5f47d63ef76a
+CT = 747fec880a47bfd288d5120e282375fcede46466ae310c46cce85eb55339b886b7121b306fccc0b2
+
+Count = 229
+Adata = 42f944c21cc221beaacb288115ac628346b8a1d94bd5
+Payload = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b
+CT = 63261824c00c9038caaa5a64603b09dd40bc4e3a210ef667a37ca5ce12aa6f0659467642deb8bfcd
+
+[Alen = 23]
+
+Key = ea96f90fbae12a857f5c97e0cba57943
+Nonce = 21cc46d9ced1539b0ad946e600
+
+Count = 230
+Adata = 105258d2f25f62675aee975cfdb668aff833f05b61eb2a
+Payload = 49db80f22bc267a70e5636dfbc8a21c83d9691fe4b9c3051
+CT = d2fcc8b7809b5fc07e44083e437d8180157f1782a9ce9f65c7fa9ee2e7cdc1b755258f2212a8a8f4
+
+Count = 231
+Adata = 0f5938540651fa4ca03867e67518eb2b73f60dd8750fa0
+Payload = 26618e21099a79d6c517335389551323065ad89c8848ea12
+CT = bd46c664a2c341b1b5050db276a2b36b2eb35ee06a1a4526bfdb9bfcd3b969fb2e41221eb92b0147
+
+Count = 232
+Adata = d6b228960fcbcf07c7bede616139db62b3808718a5b511
+Payload = 4de1d6d57144896ddea1c30f49afecd27bdf4840ed9928b5
+CT = d6c69e90da1db10aaeb3fdeeb6584c9a5336ce3c0fcb8781f8beea22cba93203c912209c78c03aa1
+
+Count = 233
+Adata = 75f8f071e229355e286882917ce5dd4f1db591fee51b6c
+Payload = 785359b1dc754a1e1b6d8731bd2d917ce3e91507401310e8
+CT = e37411f4772c72796b7fb9d042da3134cb00937ba241bfdc69a2e3ea4a40f7c491912c1a0778ebde
+
+Count = 234
+Adata = 4afb62aa8648ac7474dd16fcc376f8909c69e1ce36e6d1
+Payload = ab627aac1496d011ed2edcb2fc6b2afbcc394654f56124f6
+CT = 304532e9bfcfe8769d3ce253039c8ab3e4d0c02817338bc2a75c7ba2a769c27903e99b72639b0841
+
+Count = 235
+Adata = 736fdf94db820a2efe89e7fc9dcfe7c23d5754ac2bcc7c
+Payload = 40722cffb37f1455c2618408e777ed0f4b1bd039952730cc
+CT = db5564ba18262c32b273bae918804d4763f2564577759ff8f84f4ca4a69fde75d7207e50494819b6
+
+Count = 236
+Adata = 8a9a0367137c28db4c4e78d9cd9a68cde0d1b4583532ae
+Payload = dcaabf7a061502618541c09ea59dbbbd52b2692fd0064747
+CT = 478df73fad4c3a06f553fe7f5a6a1bf57a5bef533254e873a0c34a24d3ee0946034c71fba4dbb333
+
+Count = 237
+Adata = 34dbbff560ef04ea731b8979aef2ae50972f4db3efe14a
+Payload = dd641a893b16e0e173ea2eda20638bb01849ac11e64e8ddb
+CT = 464352cc904fd88603f8103bdf942bf830a02a6d041c22ef0f5e24a435a39a716c39f43dabdc4281
+
+Count = 238
+Adata = f3d1fcd912252431db9d8ccfc3e203d5b34d537468b4c6
+Payload = 9aa3e8ad92777dfeb121a646ce2e918d1e12b30754bc0947
+CT = 0184a0e8392e4599c13398a731d931c536fb357bb6eea673f623d59f66764d859a772bb50ec91fc3
+
+Count = 239
+Adata = 513b4cdc551c203ed5f1e659813584862023911590b672
+Payload = c8f44ae4b02fffdbce0df773c24075f877945fc7a86be460
+CT = 53d302a11b76c7bcbe1fc9923db7d5b05f7dd9bb4a394b543b6549eb16fba96318afb3df51f4675f
+
+[Alen = 24]
+
+Key = 35b403a15212097085d6e2b77ec3d4f2
+Nonce = daa423bf9256c3fcc347a293aa
+
+Count = 240
+Adata = d3c0ed74e5f25e4c1e479e1a51182bb018698ec267269149
+Payload = 7dd7396db6613eb80909a3b8c0029b624912aabedda0659b
+CT = 5b00cf8a66baa7fe22502ed6f4861af71fa64b550d643f95eee82c19ecba34280604b58d92dacd3f
+
+Count = 241
+Adata = 62f4fe53e99a9b0c51e9561d910d7e2ffe19a5176c9dec06
+Payload = 897f0dfd90213f64a9277a0eda4f134f303fa89f56ca54fb
+CT = afa8fb1a40faa622827ef760eecb92da668b4974860e0ef5ab4999e9689d52b8afeb87923efa3b48
+
+Count = 242
+Adata = 191c4dfa653c20292657f7694c6b6a4a410c49a879abd217
+Payload = 2b7cf9e6e2d6abcd7775f8a6eb6294e822041c4c45f09c3c
+CT = 0dab0f01320d328b5c2c75c8dfe6157d74b0fda79534c632cdc71e556c34fd4e1b5ebc50d38da8b3
+
+Count = 243
+Adata = ba34741f8edb51470eb20f891869aabeab562d92571ac943
+Payload = dccb9a4625512496b372a2b8b768f75741d8c2e30e57d638
+CT = fa1c6ca1f58abdd0982b2fd683ec76c2176c2308de938c3646223d381090661c2ee2370d29a572a9
+
+Count = 244
+Adata = 8b922aca6125722ec490b134a45864397f4e2c281d6e2089
+Payload = e0e452c990665465160b02cad6367ca89723613488d8efbf
+CT = c633a42e40bdcd233d528fa4e2b2fd3dc19780df581cb5b1f78af50466646b7c7e652f787afe5357
+
+Count = 245
+Adata = afb9fd78e3f8eaf4e8c91da62b2da534508e54f7dfa214fc
+Payload = b536fdb8839f87080ae65ec35da347e792622ffe18a61d46
+CT = 93e10b5f53441e4e21bfd3ad6927c672c4d6ce15c8624748cc9d9a1270f78648a6b66cb8c0f2471b
+
+Count = 246
+Adata = ecf942ccee7396cb3ee177eadd4d96a4af1d90afdce97376
+Payload = c81233826e5125e1f31fe275184ccba8f1a743e58e146e4d
+CT = eec5c565be8abca7d8466f1b2cc84a3da713a20e5ed03443b17d3d6f1fc4f530841b749d9f3a0a7a
+
+Count = 247
+Adata = 16fea92ffcaad563792aa924bffe7ef690edc90ea4e29cc0
+Payload = 24ab253b5b06552665c3c810254c0ed15e68a783180d7eee
+CT = 027cd3dc8bddcc604e9a457e11c88f4408dc4668c8c924e05852ed48cf88d9ab2326aa46b6541b60
+
+Count = 248
+Adata = 76f110eecd369d79e21fb208058359d3a2f37581d1f7f691
+Payload = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4a
+CT = 598e9d2078ce4845c6c6e0aa1c328fe7f8192a7852088444c62dff6bcade5ac2edb8ec9797ce433e
+
+Count = 249
+Adata = 8834c776a3237f060ae0ab9857324a3b2ac79f3b6e6f90f5
+Payload = 11cbfb3d348c7abef99f562607e289de34a2bb379a5dfe50
+CT = 371c0ddae457e3f8d2c6db483366084b62165adc4a99a45eb936ac4764575f85352c24ab23209d42
+
+[Alen = 25]
+
+Key = 7a459aadb48f1a528edae71fcf698b84
+Nonce = fa4616b715ea898772b0e89dd4
+
+Count = 250
+Adata = 0c0b4a45df5c3919c1e1669c5af5d398d9545e44307d95c481
+Payload = 0b3d947de8632dc8ff752f619ba7c84716fac7a23e101641
+CT = 7db9f3f7dc26fc2adf58d4525d26d5601e977de5a7c33911a1138cff7b624f9908b5b4d7e90a824a
+
+Count = 251
+Adata = aa27a28a36b5a2cee57ffeca0233feb4bdd4eacb2cae28e98f
+Payload = e6dedce2c278c44e5678d13e7d5b5d3501d61bb0bb6b5558
+CT = 905abb68f63d15ac76552a0dbbda401209bba1f722b87a08e23f92b598f7a248a894e6b8f5691bee
+
+Count = 252
+Adata = 66220aa9b40a1772caba7749a544bff938e804dbc6e556498f
+Payload = a276b0922fbd5094bf89b9329d07341e039d6204397b81c0
+CT = d4f2d7181bf881769fa442015b8629390bf0d843a0a8ae90e94043c0d80fd651469232fe9d47a81f
+
+Count = 253
+Adata = 3d765d20e03a4cebfda50316c4b7d8b6c55078d5b3e9cbc567
+Payload = b99afbc2dbb377350cc58d4bfe8e954cef25d7b27b82fad4
+CT = cf1e9c48eff6a6d72ce87678380f886be7486df5e251d58425088b522fc0731097e729448236b317
+
+Count = 254
+Adata = e91b6265879153e1692b00a112b4205111c8eb1a7b7f2c6898
+Payload = 56114cc783b80ca2dd2881387b6d92a59a237dfc8e976d8b
+CT = 20952b4db7fddd40fd057a0bbdec8f82924ec7bb174442db2208cf07574cc4f3f83ed6301b904404
+
+Count = 255
+Adata = 340b16f352817babb4fb70e9e6e18784b3e67bdd449872158c
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 9da599aac80a43a70b0be59fcbfa6d266719d3e846248ca514b0a900068e55cd24c92bbb78c521ad
+
+Count = 256
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01445be684dc
+Payload = b15083a73607c9d7e197a8cc884ad3be98ac343f6493df67
+CT = c7d4e42d02421835c1ba53ff4ecbce9990c18e78fd40f0373f8ba66d74321c80c057f010078d2f28
+
+Count = 257
+Adata = 5fe8bb27a59a5f4e370adbba96484c2365fc0d8c6e58d7d3e6
+Payload = 07542d18e8f2d3e199fca0f90cabb78b169525fdce81666a
+CT = 71d04a92dcb70203b9d15bcaca2aaaac1ef89fba5752493a0a189319e4f06d53c1405d37b06cc8eb
+
+Count = 258
+Adata = 23e5422e8d7560a9e65642b5e723a47536c16791f3a0cf918d
+Payload = cd574ed56bdfd1408f7831e0b24b4345ee979ac906a7aa22
+CT = bbd3295f5f9a00a2af55cad374ca5e62e6fa208e9f748572dd72f48ae03670249d74f8460b63b1ae
+
+Count = 259
+Adata = fcc9422ba5023a9997baa9c4ee6cb196ffe96e08eb9c2b8a75
+Payload = 8c9abe94beed4c9bd46adb1d04fbfe7016dd50d324525abb
+CT = fa1ed91e8aa89d79f447202ec27ae3571eb0ea94bd8175eb1717c00c93d36a77141b723d573c8c65
+
+[Alen = 26]
+
+Key = ca748225057f735f712ecc64791367f0
+Nonce = 1341a6998eb1f50d4b710a13ac
+
+Count = 260
+Adata = 5fb96b045f494808c02014f06074bd45b8a8ad12b4cb448ec162
+Payload = e92cd0cb97afe4fb00c4f12e9b9abe1d08db98f49a27f461
+CT = 82b666694232e86e82295beae66ae67d56aceb5d6b1484ceb4a6843ec16078038c10afedc41f5362
+
+Count = 261
+Adata = 87db0d9d69bc0cf69cabeb92570e482bbc8ff3e1ba72f12f3225
+Payload = a6dbad96ad23ff61479df39b99f0673a09f2a7eaebbd34b9
+CT = cd411b3478bef3f4c570595fe4003f5a5785d4431a8e4416a7c6566d0b8ff97f946d7c7773a845f2
+
+Count = 262
+Adata = a061a09024f1e03b223695d4703ee202e90e07156b95859a22e3
+Payload = b1dd81cc3b2b0efe540a3194d6fe304cd2de53db7929ebe1
+CT = da47376eeeb6026bd6e79b50ab0e682c8ca92072881a9b4ee1d66a4728b67b42602e23c8500b0115
+
+Count = 263
+Adata = 0dd513c5d8d62b723ab8b0a3aaa477e843d9149dc8a2f878e585
+Payload = fb30c2e98f3d7e4ed7431da285711d3d287884db13a474e7
+CT = 90aa744b5aa072db55aeb766f881455d760ff772e297044803c51e8c59ed13b3e5d9b489d4ea2ccf
+
+Count = 264
+Adata = 3ff59c40bd796048e586eccc23a82e4d09fc5e779f38eb4afbed
+Payload = 886f9f91a6566ceb99c39462ab675a3ae3be98f68787626f
+CT = e3f5293373cb607e1b2e3ea6d697025abdc9eb5f76b412c0f1ec270b43fc5a9811b56ccf033789c6
+
+Count = 265
+Adata = 0df7ef91f7124da867e992bcbc6fb38232ff6d5205f38768da72
+Payload = ed370d1c2d6dc03e4fae4deb9343a7d4339562cffd427587
+CT = 86adbbbef8f0ccabcd43e72feeb3ffb46de211660c710528bb4ed25940d58cba64271fe1d2e8013d
+
+Count = 266
+Adata = 6777de159c34d005b94f67c33ae4a35ebab09d9cb9c56b4c9c81
+Payload = 2f77c2eb07db14bd713c5af10c0760ea3a6ca5ff8d046d36
+CT = 44ed7449d2461828f3d1f03571f7388a641bd6567c371d99392636a5e373c1354ea9b969abb4932a
+
+Count = 267
+Adata = 75559898f4ba03c55afc25ea91aa61a93c2f8270a5fa51b6f6dc
+Payload = 360fb89429dc9b48358097d930c8561b2bd18dc0a470d1d6
+CT = 5d950e36fc4197ddb76d3d1d4d380e7b75a6fe695543a17959a7e8bc0570f19159f91fc14ac6532a
+
+Count = 268
+Adata = 5e03fc430473c5de96d68907fa506f9da353ae48a965445e1f24
+Payload = f2d8d67b9f291c3edc264893922622b2693f3e7231137eba
+CT = 994260d94ab410ab5ecbe257efd67ad237484ddbc0200e1507e559568c27a30b5676f98cc66f57d6
+
+Count = 269
+Adata = 7eee4869e77f6db12c91d1f647cad2340d33a3defaeb362d311d
+Payload = 7fd6fb81c36e44b150af10e04683b1ec9b5dda87c71ff939
+CT = 144c4d2316f34824d242ba243b73e98cc52aa92e362c89964910615920f6f3c3421a9c2bec1bec7e
+
+[Alen = 27]
+
+Key = fdf2b2c7fcb3789b4e90abe607dca2af
+Nonce = a69ddc66e63a3415f21009d53a
+
+Count = 270
+Adata = c76846da496ed87b9c0f65c6266c9a822224acde9775efb186a4a5
+Payload = d7aa4efa5d75195a400018bd38f7d8cd53fdffe88df1837f
+CT = 150d9a8b78d9c04239d66207a1f95021bbb1b7c70d7c354825d05e5a2e76a90f6fe489fd74cab2a3
+
+Count = 271
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d
+Payload = 5f94a2e48d348a1d56c55a659306e319c3d2ad78b9fe43a7
+CT = 9d337695a89853052f1320df0a086bf52b9ee5573973f590be6af49ce97d5e0e77c7fd5d9cc6d932
+
+Count = 272
+Adata = 7631cf7822a545daefa16a5ec43c877d475a82d5aa2d51cec7fbb4
+Payload = a44b010fc1c659eac9241a58b11a73d7ce33156ddfc54c3c
+CT = 66ecd57ee46a80f2b0f260e22814fb3b267f5d425f48fa0b924b268cab915f999aea3e1cc3a88ccd
+
+Count = 273
+Adata = e4da34663edc44370bfd8aa8315945471a893a1cc069628a071ee0
+Payload = 28d157f5741f1be057d5219711414c0638b47d165a905a6a
+CT = ea76838451b3c2f82e035b2d884fc4ead0f83539da1dec5dc368f5af8e311e67209e02dfa2613377
+
+Count = 274
+Adata = 077509eae1dc367540f87832c5780f6c5b29e180bc6c1fee38e826
+Payload = ba7432a8e34bfaa91b35c8dfd822d86850be39e63150257f
+CT = 78d3e6d9c6e723b162e3b265412c5084b8f271c9b1dd9348ad175fcad35d29396380b79a28784cff
+
+Count = 275
+Adata = a513d750ca1e8bf6cb7b8cea5204e064c15c2dc40d742b31cf5459
+Payload = 3f5830b0ce8849a660af7d58a60c19a9824a3033bb5fed43
+CT = fdffe4c1eb2490be197907e23f0291456a06781c3bd25b7493b4b3e33d325359c9c651290ce73bed
+
+Count = 276
+Adata = e439db829c1291df49fc42c2fa1a92118c2665f11e13f28dc6f11a
+Payload = e69b2a243340df5dc70b2cb05be12e5992ee36f7d9f4ca84
+CT = 243cfe5516ec0645bedd560ac2efa6b57aa27ed859797cb371f88ca5857c6d801e726a01c621a0c3
+
+Count = 277
+Adata = a12c690568114fd7a677f49d74e84fc1a6b7f7d2a08693266c0a91
+Payload = 9de35b840a69a84701ffae1b1d2bf13c34b42a57d14c524d
+CT = 5f448ff52fc5715f7829d4a1842579d0dcf8627851c1e47a0592d360fc6a46aa18c4ce5d74fa4532
+
+Count = 278
+Adata = 1813bf176a1127f4d508d7663ae750f9c4bcb84a6e26811ac60d46
+Payload = 9e2fa20bf76768a5a1467d90a048bb503a2c33bbbaa71653
+CT = 5c88767ad2cbb1bdd890072a394633bcd2607b943a2aa0648b772cef893495cf0a94e8ebf06e920b
+
+Count = 279
+Adata = cc6e9cc2699d3ba0e624e715599480d6b7dbc6eeea0d12a9236444
+Payload = 6681b1cbeceea57a828324831407280b00f4917ed52a10df
+CT = a42665bac9427c62fb555e398d09a0e7e8b8d95155a7a6e8b1851d571a1ef8aed565b784dcaaac4e
+
+[Alen = 28]
+
+Key = 7d870d7e52d3053c65eefad47764cfeb
+Nonce = 37d888f4aa452d7bf217f5a529
+
+Count = 280
+Adata = 9610949f6d23d5b1f3989b2f4e524fab4f297a5bec8ddad4f16cb616
+Payload = 109317556c21c969eda65a94176d7a11462c9ae18a865b6d
+CT = 4e6b967b1571c6d7b9e118b112b7ac949a4a175650316a242dd579cb0d201d22c86bbc7fbe47bd0d
+
+Count = 281
+Adata = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34626ac9b9
+Payload = 3e6c914a196e175079315b1c92b2b8a844deb472e249e3d3
+CT = 60941064603e18ee2d76193997686e2d98b839c538fed29af0dd7aef4a609f3587652173446ebd82
+
+Count = 282
+Adata = 21fc96f73975298207f818909088295d6d6861677130ca258c2174f6
+Payload = e0014147d5771b4380dc0192d45f36f7d60776d1ba47374d
+CT = bef9c069ac2714fdd49b43b7d185e0720a61fb6660f0060463e4405d45caf4836467edbf35089d87
+
+Count = 283
+Adata = 72a5151abcb55933ff7c9314f3235eba2a400121454144c2670e8359
+Payload = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a
+CT = 51e4ecd194f980c441d8dee31dfa69374576555d7eac44537441c813e90fac775eddb7290df059d9
+
+Count = 284
+Adata = dbbf192914b1ad73666e9f5e9c22c08ca398f7524af62b1046a863bd
+Payload = c1ddd14e380cc91324cf2a381df1da1ccffd90ae436a373a
+CT = 9f255060415cc6ad7088681d182b0c99139b1d1999dd067334d9316f1f1c3142c1c9b26e5c220a32
+
+Count = 285
+Adata = 28e4b88fbf04e9897057ff5bfde7eb04fa480256817a50fa281030b4
+Payload = d4dae9c4cae92afb80f9a5c99383ff16e23a2ec942eed4d2
+CT = 8a2268eab3b92545d4bee7ec965929933e5ca37e9859e59bc0b188e33bfab29b237d6c6920ce3418
+
+Count = 286
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d7
+Payload = 8a188d40a6e6fbb06a9f06304349a7a808b092cc2fc10b9e
+CT = d4e00c6edfb6f40e3ed844154693712dd4d61f7bf5763ad7fdde04d21b876468bd9184101b5f32d0
+
+Count = 287
+Adata = 34ad69f192ae4dcab771aeeacf01bbd32609bcbbea8ff9df31ded719
+Payload = 590c1aac30ab166b1caff748452fc146765c372e226ffc26
+CT = 07f49b8249fb19d548e8b56d40f517c3aa3aba99f8d8cd6f068c65e9d0e5f1b81c86393900e64c19
+
+Count = 288
+Adata = f5e50ce1f99ed5e9f2baa54b96ae7039234b1131e734ec190695d28d
+Payload = 16d0522b2e691e42bd80ce95e00c8a7a1fc738169e904bdb
+CT = 4828d305573911fce9c78cb0e5d65cffc3a1b5a144277a9206ab3b72c56c8df4a12dba89a2f21276
+
+Count = 289
+Adata = 9b1e7e52ea1a12444d884866e11dcf367b70b816460936fdaebba36d
+Payload = 0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43df
+CT = 5525726c6b4b8d475271c9287ede0999b44840fbf19c72960170ca7b16d23537eeb3034105334699
+
+[Alen = 29]
+
+Key = 8fcac40527c0e7ca8eaff265ca12c053
+Nonce = ae9f012fd9af60a400e20b1690
+
+Count = 290
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154
+Payload = 78d1e96af8cebdcc7e7e2a4ddcfa34f6cf9a24fb85672ad7
+CT = 9adb9a95a9379ad795d8d3ffd4e37a045160d6d727f974a6cb3b5151f327e65447e52c7525562c91
+
+Count = 291
+Adata = e7c78ef4c4b959ee00cb1a09d71221a43892ef8ad705edd27ed85d03a3
+Payload = bc59f18c8473941abc681a92741ab5ee13679829f542b8f4
+CT = 5e538273d58ab30157cee3207c03fb1c8d9d6a0557dce68534e5b08e27d8f5eeef0f064ff620652a
+
+Count = 292
+Adata = f1bce6f2a4bdd3a07ebf5f8d47f931d27e7e63389d70e1059f701216be
+Payload = 5575d950312c14c89ac609dfb0b2fd1af732bb6aae5e8651
+CT = b77faaaf60d533d37160f06db8abb3e869c849460cc0d82044c0a96baae318f4714f0206812516b5
+
+Count = 293
+Adata = 3da3bb091016e54477dae88af1c84c1a51b59c1bb49a05deb6f32064e6
+Payload = df5947d8c6094ccc25816639ec42214b28731bfd7b8312dc
+CT = 3d53342797f06bd7ce279f8be45b6fb9b689e9d1d91d4cad4e7bdce2dc6aae24178aab6984f31028
+
+Count = 294
+Adata = c4cd183071c37a8157c6930a7d4d530cf4b7eb021682327810bd48209e
+Payload = 2fbb6dc235761875411ef59ae06110df8f15f66b721b0fd6
+CT = cdb11e3d648f3f6eaab80c28e8785e2d11ef0447d08551a7f18ece8260bd56ecdee768022d0dd8d1
+
+Count = 295
+Adata = 0e0fece7b6b659b642668e8ba3dca330523e70279155f485f3f6f8041e
+Payload = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e
+CT = 2f1eeee88a5ecb4bebad75e198c85a9be155443c87ae413f6f0fb3b7440b84ddc3cc53819c2e93be
+
+Count = 296
+Adata = a35c6f70f637a9a5e6f215c694fdf65b6fd85f794ed3eaa1bc19abe592
+Payload = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa00
+CT = e109e352e48bd5a6c1ccbde6f5716d9e4f2e977be1b6f47129ca778c51f9320f121dd803ece8d5da
+
+Count = 297
+Adata = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f904398afbec
+Payload = f2d9cf953c8d3a051d9b3eae4307a3cb4fffaa2435b49586
+CT = 10d3bc6a6d741d1ef63dc71c4b1eed39d1055808972acbf79c223a5ad65120bfca4a5992e5ebc6fc
+
+Count = 298
+Adata = c023763a285ea934bc5bc7ddfc2aefe2b3f9eafe7b87c61383dcc07990
+Payload = 4b92e8d2ffaa4af8f3e0ac037a900bd18e195f490a3d71e1
+CT = a9989b2dae536de3184655b17289452310e3ad65a8a32f905c3bc4f618ffb3a159f4e2d0622cea6e
+
+Count = 299
+Adata = 0a39ec0163c7aeb1b4fbe7cb4fa5b0592fade70f430e23730a23ed4160
+Payload = 7c0e6a0d35f8ac854c7245ebc73693731bbbc3e6fab64446
+CT = 9e0419f264018b9ea7d4bc59cf2fdd81854131ca58281a376f099dce6e18435fba4d26c1e93bda0c
+
+[Alen = 30]
+
+Key = ddf9f150cc3f1c15e8e773663c5b061c
+Nonce = 98c5036b7d54da9a1177105600
+
+Count = 300
+Adata = 20c5ab290e6d97f53c74121951f39ba865b3acc465fa3f0fb8a591622277
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d00d29396ffa9e691290d746527777bf96a851f306d4da0b1816df1e0e82bb7bc8105930ad6a2232
+
+Count = 301
+Adata = 0e205a4dc5d5ead0d9ff7f182dc140fc49511c01b0fdbc7e6d6cb5fdf027
+Payload = 88b2572fbe7cf2b46df04db476ffedb41778ae2eb3c3aae4
+CT = 2167fa0c69b415af3383c4e8ae35d41e00b8232e3dbc3cd2df823c8ccd466807f2bd1c4032f0cfeb
+
+Count = 302
+Adata = 48043560d60381e83c11d4bc9d997d3ee2add6b0524b779c62dfaa73ce0a
+Payload = d44bf28b010e076b45db1b053af03db718b60748da51db1f
+CT = 7d9e5fa8d6c6e0701ba89259e23a041d0f768a48542e4d2931f5be8c9965345c760c72cc1b7908d1
+
+Count = 303
+Adata = f0729a8a2fd073699ab87b521cbe0420b43529556a505f5f87874d1a053c
+Payload = eab8cffb512eabe267cd64353552513defe97c2d10f35503
+CT = 436d62d886e64cf939beed69ed986897f829f12d9e8cc335381d94a828a95872ebdfda8a4c6a196b
+
+Count = 304
+Adata = fc2cd69bb61223f713e33a5071d09bf2783640c307c22d836dd94952dd37
+Payload = 001056926546c261fbbdf92b94498e038c2bcfd0b6345497
+CT = a9c5fbb1b28e257aa5ce70774c83b7a99beb42d0384bc2a163931808533f4f70d7a78242ced110eb
+
+Count = 305
+Adata = 8f653c5c003c807d16d17f833eebb97c9c2f0e5aae3780a52ce53a6c33f7
+Payload = 29ffaef9415fd300127ffd26ef324083a9d90e0f60e2ab4f
+CT = 802a03da9697341b4c0c747a37f87929be19830fee9d3d79f34553198f8e40fde6473f9cf04f1de6
+
+Count = 306
+Adata = 8d05e7d3077151c6d9378cb08e049e4d7c28a908f7f7c079c46ff92cd01b
+Payload = 9874dc5ca1b541f7b21c7b3860fa6b0c3ab1b712ab0fca98
+CT = 31a1717f767da6ecec6ff264b83052a62d713a1225705cae0fac20e8d45d2b0771d140b5e4a47c87
+
+Count = 307
+Adata = d4feb3ea76ac2945651f557406f3f38a2d7e9232ed55ff4eaf1201dd8255
+Payload = 1e01c7128c821fb9c971a27fc7c6f9bb902fa735de583b8a
+CT = b7d46a315b4af8a297022b231f0cc01187ef2a355027adbcd3cacfe4281e52d79e60eeb38319bc3a
+
+Count = 308
+Adata = 7cbb4ae995a3367a256cafd11cd6c6cab5bf3252fa97f27a8a1434ca9a27
+Payload = 51cd306fac7d20e3c7043eae3a6dfec046c5c24a666a0723
+CT = f8189d4c7bb5c7f89977b7f2e2a7c76a51054f4ae81591158f0d7646a799b14288bb2f354b5d8847
+
+Count = 309
+Adata = bd40b06a4beded2be3d176266b10772c7fa2949f0a9b20d613af90c2daf5
+Payload = fc5b26befc633a3e8ace011aa7a42bd0258a9f3dc14fc1c8
+CT = 558e8b9d2babdd25d4bd88467f6e127a324a123d4f3057fefd7f95e1d331e700aa9ef83f09b689fd
+
+[Alen = 31]
+
+Key = b1dc81d116d94f5eced526b37c004b95
+Nonce = 97c8f69fb91b17299461fd8d63
+
+Count = 310
+Adata = f8b08aa83bed09ca342249b2cf9e2b45a89dcfb8711a120395e455921af481
+Payload = 54390715b6e7c7bd51a234db059a51ba030cf22ee00b7277
+CT = cb629994c3418a662a8cde1b5f4d99aa7df66e24c53dc6df11297930fd44c63675b7cca70671ef4d
+
+Count = 311
+Adata = 0351c969dd38eeaa4b9b0000e346eeb1a2cd462033c59d9e6e3331822045cd
+Payload = 65b5e856a8cf35dffd42c5ba105cba4c434aa1c2a0390352
+CT = faee76d7dd697804866c2f7a4a8b725c3db03dc8850fb7fa7e77f5566ca2fd9293835bceb461dbaa
+
+Count = 312
+Adata = 5db8b6bc16740680f78fba917733a6899cdba5e4c10a8058963d1265681eaa
+Payload = 9a7685e3daac43ccf22cad0df900ba8acddc5d420846118d
+CT = 052d1b62af0a0e17890247cda3d7729ab326c1482d70a525ec2cf9f5d35521c1c000685e49d2ed42
+
+Count = 313
+Adata = e7d6024611210da0cfb90a9955195aa0a0539280a3a7c792a1540930daae2d
+Payload = c18d9e7971e2ae5fc128777086338fbe194443324e2d2cd1
+CT = 5ed600f80444e384ba069db0dce447ae67bedf386b1b987966f33dfb44ae413283b238616c6b99fb
+
+Count = 314
+Adata = 77a878c9c76f3e6a4ddd330d1d8828949d08e0fedffe0d8e2e557b29e7c78c
+Payload = fcf8982f7342f1b953658453cd5ea413700eff00f1ee7d6f
+CT = 63a306ae06e4bc62284b6e9397896c030ef4630ad4d8c9c731df6fc6b4cf0b6332936ed7cfe9455e
+
+Count = 315
+Adata = aa540554ee80dbffa475f702d862d6b60e0a4090792420a26d02926517723e
+Payload = 0d5690d2a7083ad6daf22b308314b8f5363aca77ca72835e
+CT = 920d0e53d2ae770da1dcc1f0d9c370e548c0567def4437f67c8162a815f2809601ad02595e2e0ff4
+
+Count = 316
+Adata = fae86f95dd06fb7fbae63a646615555aec8153dc328bdf79da5d4cc9677ed6
+Payload = f6e313cc35e8f8812b10a44f8ad00b6893f8084d942effe0
+CT = 69b88d4d404eb55a503e4e8fd007c378ed029447b1184b487fcaa11bdeab86f60f9cd0a2b45cee1a
+
+Count = 317
+Adata = fd525302d2fb246a47cf4e3a27808bda89d8488cf450f1a1c7df6eedd810ee
+Payload = 91e961ea2eb750577c5137c609602dbfcc4c07955ba429ec
+CT = 0eb2ff6b5b111d8c077fdd0653b7e5afb2b69b9f7e929d440a86a810881bd969744ad80f579400f1
+
+Count = 318
+Adata = 767b1bdf9793a512d3a84e99ef77b43011a3bcb8de4cd375dfe47a79293e01
+Payload = 98438c4411bead6f30c89ead762a12bf39391d3652b78b7a
+CT = 071812c56418e0b44be6746d2cfddaaf47c3813c77813fd2250ca00d3231819ecdf501ad39c864f3
+
+Count = 319
+Adata = aac7014f606df6feec415a75e29015891007f07518c955875fbf5619262ff2
+Payload = 540cb00c0eface3d1b2d632d80a642f53c78ff672a1ff6ff
+CT = cb572e8d7b5c83e6600389edda718ae54282636d0f2942571224d1d0294d46981d7dc39114a693d2
+
+[Alen = 32]
+
+Key = 5a33980e71e7d67fd6cf171454dc96e5
+Nonce = 33ae68ebb8010c6b3da6b9cb29
+
+Count = 320
+Adata = eca622a37570df619e10ebb18bebadb2f2b49c4d2b2ff715873bb672e30fc0ff
+Payload = a34dfa24847c365291ce1b54bcf8d9a75d861e5133cc3a74
+CT = 7a60fa7ee8859e283cce378fb6b95522ab8b70efcdb0265f7c4b4fa597666b86dd1353e400f28864
+
+Count = 321
+Adata = 55a62968c222a8501d1ae56a9a815667f8a9554607b7c56e6753f8fa92a4d054
+Payload = 764dbefb42644d18d23e5e4568685d14dbacfa418d36c4ef
+CT = af60bea12e9de5627f3e729e6229d1912da194ff734ad8c4423862a715dda2f63a4197f894515803
+
+Count = 322
+Adata = f8436e35b7a1c810ac6aabe8e2d48a3678d19e1e96337dada514ee5fc075fce4
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 17e3f2110e9ec22c8ebef633023a178021ef45ff5f31cefec200f190bd700f6108f9959f6d12f0f0
+
+Count = 323
+Adata = 548e2152f3a15b8fb81dc01062d99f7b4fc8f074e5cbdc1030c97f8ccc02ec3f
+Payload = 53c164a4990c6e0637267ff2556c1542712fc584f6ff7458
+CT = 8aec64fef5f5c67c9a2653295f2d99c78722ab3a088368733a66ebc4e0777a6fc140a51e04a10f86
+
+Count = 324
+Adata = d100f1d08ef1e3eda4aef22cd970c2b785c4ff9b523c401b4064324aecf7f2d9
+Payload = 15681d2121ac56a63b9d0a38b9c4eccf84fdb746d32c14b4
+CT = cc451d7b4d55fedc969d26e3b385604a72f0d9f82d50089fb810cdc08db0a9966dffeb43ba26446e
+
+Count = 325
+Adata = eece934a807c9f21487cd810f15fd55d7bb4421882333ff2c43b0353de7fc5a6
+Payload = 412a8ef924ca156de860f147575e5731825f0a3759688928
+CT = 98078ea34833bd174560dd9c5d1fdbb474526489a7149503cfc5b397578f8d02a0b936ffac29b99a
+
+Count = 326
+Adata = 86311ff444d9be90459b6ee3652e1705ed0b5cdac3d27293ddea3378fb686ee5
+Payload = 54ba8a020d0876fa369dc32e8627f565ba3dda862ea0bcfe
+CT = 8d978a5861f1de809b9deff58c6679e04c30b438d0dca0d52c3fcd6d618c260d51724126f257534a
+
+Count = 327
+Adata = ab6efbc44a8906d5c067eaed71af467e130aaf170827a58beb03c55069674125
+Payload = 7a15506fd1dae444d77b2a3ae7b57a8d5b4f10e25a9f78e2
+CT = a3385035bd234c3e7a7b06e1edf4f608ad427e5ca4e364c9bf8b2821920640b992b00cd1c9618025
+
+Count = 328
+Adata = ddb640923d083725587aced81ae1d7409983d1f1e3ccc8dcf94376dc1bbcae8b
+Payload = b18a61a89cd698f32e059b7a2a9f62a46be2c248790a9915
+CT = 68a761f2f02f30898305b7a120deee219defacf68776853e4cd52d41a968284af8907ccbb4588cc0
+
+Count = 329
+Adata = d95ec4a6f594be1ba39fa1aa933dc0a5dafff5ce44509577ebb3a3e8084c4401
+Payload = 16ee3bc9ec8b4448e292b8973618e02a99da1c348539d5c7
+CT = cfc33b938072ec324f92944c3c596caf6fd7728a7b45c9ec47449a5cb4943ff2846c589b7c98ef49
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT192.rsp b/lib/crypto/test/crypto_SUITE_data/VADT192.rsp
new file mode 100644
index 0000000000..1a7a5875fe
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT192.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+Nonce = 15b369889699b6de1fa3ee73e5
+
+Count = 0
+Adata = 00
+Payload = 39f08a2af1d8da6212550639b91fb2573e39a8eb5d801de8
+CT = 6342b8700edec97a960eb16e7cb1eb4412fb4e263ddd2206b090155d34a76c8324e5550c3ef426ed
+
+Count = 1
+Adata = 00
+Payload = 296fbda0017351491c2187273fbde2c3a427170e430a703c
+CT = 73dd8ffafe754251987a3070fa13bbd088e5f1c323574fd2167ee33e75d05023a7d63c770cfef2ea
+
+Count = 2
+Adata = 00
+Payload = eb61c284fe009921039ef6a9ce50e702823e44b35357923f
+CT = b1d3f0de01068a3987c541fe0bfebe11aefca27e330aadd170647420f79c0d91cbbd69b806fe96a5
+
+Count = 3
+Adata = 00
+Payload = ffeccc6460d23fdcc387c697e75dbb959b78013a8282eaa4
+CT = a55efe3e9fd42cc447dc71c022f3e286b7bae7f7e2dfd54a8a3ef2324754539ac774872282534386
+
+Count = 4
+Adata = 00
+Payload = 90958d7f458d98c48cbb464c74bf495a49846dd468c514e9
+CT = ca27bf25ba8b8bdc08e0f11bb111104965468b1908982b07e292cd0e32535a848e327bc53cdae94c
+
+Count = 5
+Adata = 00
+Payload = a4fad5205d38206e25097075687ca86032b95b3fe7e82a07
+CT = fe48e77aa23e3376a152c722add2f1731e7bbdf287b515e9bb21701af36936be5f62d02b84df87c3
+
+Count = 6
+Adata = 00
+Payload = b37114c65372b052cbeecf83d05a5da44f7b5bbff7d986b5
+CT = e9c3269cac74a34a4fb578d415f404b763b9bd729784b95b7da7f975367be24341e4af51b8bb156a
+
+Count = 7
+Adata = 00
+Payload = 9c0f0426f171ff18b2a4392f61fb4ee4a44c476fe03dc930
+CT = c6bd367c0e77ec0036ff8e78a45517f7888ea1a28060f6de360c6d50a96f316eda0b216cbb6380ef
+
+Count = 8
+Adata = 00
+Payload = 7b6e0a480a40585545b0e940e8d97c9ec987bd3c0e9c16a8
+CT = 21dc3812f5464b4dc1eb5e172d77258de5455bf16ec1294634cd1bd98e8137b578a174e39efe09b8
+
+Count = 9
+Adata = 00
+Payload = 34dac6dbc28be62332a6935efc122e37b26ee100eb4033f8
+CT = 6e68f4813d8df53bb6fd240939bc77249eac07cd8b1d0c16909a895a3b08b63d7a2a1e75d25e7861
+
+[Alen = 1]
+
+Key = 9748798c0f3cc766795c8ce0e4c979c1930dfe7faefea84a
+Nonce = cdf4ba655acfe8e2134fa0542f
+
+Count = 10
+Adata = 67
+Payload = 100fa71462277d76ca81f2cfdb3d39d3894b0ca28074a0f0
+CT = 36e2415b4f888a6072f260d7e786d803be16f8b9cbee112d7ff74e3b05b7d7c13284573bd3e7e481
+
+Count = 11
+Adata = 17
+Payload = 0217eb6778691f8dfe2d0e5241f05fcbcf97b9171f4de3f0
+CT = 24fa0d2855c6e89b465e9c4a7d4bbe1bf8ca4d0c54d7522d3ee7ce845f85dfc770d96dee9ca54ccd
+
+Count = 12
+Adata = dc
+Payload = a78b7bc6c1a7250c5fc236f2a8343725a9a7bd3ca81b53e4
+CT = 81669d89ec08d21ae7b1a4ea948fd6f59efa4927e381e239dc14ddd8ae0aa5d810040a8d1d4da1e9
+
+Count = 13
+Adata = 0c
+Payload = 390c808d998582793bb10ee60568eb8d975c51d68b4e4da9
+CT = 1fe166c2b42a756f83c29cfe39d30a5da001a5cdc0d4fc746b40dec7e647720f1f5e8474bf570c2f
+
+Count = 14
+Adata = 3e
+Payload = bcd9747fb54184b61b2e9e049caa75e22006e250f3722c0e
+CT = 9a34923098ee73a0a35d0c1ca0119432175b164bb8e89dd3c10c4aac45d90119cce490cc8681a49f
+
+Count = 15
+Adata = 7e
+Payload = d0342e3cd2c1142b642da7297ee3b9978cec405e6810f12f
+CT = f6d9c873ff6ee33ddc5e353142585847bbb1b445238a40f2f9a95091d2cab7d3d9fa3e10d3e67ac9
+
+Count = 16
+Adata = e3
+Payload = 7fab91d1aa072947d22f0dc322355a022fe7f0747f4a184b
+CT = 5946779e87a8de516a5c9fdb1e8ebbd218ba046f34d0a996180f7818c373e89f7ff3003f53260060
+
+Count = 17
+Adata = 3e
+Payload = e487143dc4d98dcc6a2dfe6ee0f85d565d1f46bb0fafe62a
+CT = c26af272e9767adad25e6c76dc43bc866a42b2a0443557f71905f581585e59e3c8c038b5bf966559
+
+Count = 18
+Adata = 3b
+Payload = 976b489244ed6789a34251500057d1d4a3229367a42b9066
+CT = b186aedd6942909f1b31c3483cec3004947f677cefb121bbea56569c34f8d9eea23e85fec18cfc51
+
+Count = 19
+Adata = a5
+Payload = 71efa75961dfd60ad533082a8cfe111214eb02573adc4591
+CT = 570241164c70211c6d409a32b045f0c223b6f64c7146f44c212da23548f2ca4e9a8a07962be6422c
+
+[Alen = 2]
+
+Key = 393dcac5a28d77297946d7ab471ae03bd303ba3499e2ce26
+Nonce = fe7329f343f6e726a90b11ae37
+
+Count = 20
+Adata = 1c8b
+Payload = 262f4ac988812500cb437f52f0c182148e85a0bec67a2736
+CT = e6d43f822ad168aa9c2e29c07f4592d7bbeb0203f418f3020ecdbc200be353112faf20e2be711908
+
+Count = 21
+Adata = 9db5
+Payload = d5982c462ad40458660cd7b120ce07fce9afe812caedcebd
+CT = 1563590d888449f231618123af4a173fdcc14aaff88f1a89015e5cd97b7dd3d981321ae0b2d99e1a
+
+Count = 22
+Adata = 69cf
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = da6e85202048347568befac0731db702e687d5ef51d50402bf3e75863c7acd2699caba3cc301f4b2
+
+Count = 23
+Adata = 6c6e
+Payload = 373c157e59b934a1afb57d4c5dd9ca7fb736b206a6210bef
+CT = f7c76035fbe9790bf8d82bded25ddabc825810bb9443dfdb5d6a8f7a9f52a8038aa9dc1bdc9ed876
+
+Count = 24
+Adata = dafa
+Payload = 26e10a2ed8cc883a6552aee162c5542ff8bb8e758a1975f8
+CT = e61a7f657a9cc590323ff873ed4144eccdd52cc8b87ba1cc8a15603f10cbfdb041f8b2b12cc8f037
+
+Count = 25
+Adata = c8b1
+Payload = dd235b05c15479dfe0326ba206ac784eca50038bbeb35d32
+CT = 1dd82e4e63043475b75f3d308928688dff3ea1368cd189061278bf62ba6a4819513d49fdcdb45480
+
+Count = 26
+Adata = af48
+Payload = a0818342a5cae4a90ef281d3d1289d83f273f418a545fcbf
+CT = 607af609079aa903599fd7415eac8d40c71d56a59727288b8b4d00309b50f9ea72f8105c94475b52
+
+Count = 27
+Adata = b1cd
+Payload = 33c0d06b6583bb4d15b4a07364c4be70ac6e72795c3dae0f
+CT = f33ba520c7d3f6e742d9f6e1eb40aeb39900d0c46e5f7a3b220ba58e97936612c4183ba86705b2f9
+
+Count = 28
+Adata = 649a
+Payload = 3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863bde9
+CT = fb5a67c9744faec46fa7e127d646ed5f8be555566a0169dd87d602dc85bb260fb3df1221e2fbd10c
+
+Count = 29
+Adata = 593c
+Payload = a97faefcae36732fcfe47736c2334ea7d411bf7638b0c019
+CT = 6984dbb70c663e85988921a44db75e64e17f1dcb0ad2142deb3835b7eecad6dac9785ad1d370ede4
+
+[Alen = 3]
+
+Key = a74abc4347e4be0acb0a73bb8f7d25c35bae13b77f80233a
+Nonce = 6a850e94940da8781159ba97ef
+
+Count = 30
+Adata = a4490e
+Payload = 6372824bf416cd072a7ad0ae5f9f596c6127520c1b688ab4
+CT = b14a07bdc119d87611342c4c6935c5786ff1f9ae2eb49e6191c88a3cb4fbafcb8a4a157d587d7e39
+
+Count = 31
+Adata = 5cad2e
+Payload = 295f4f3417a77fcf0bbda17b0fd629ad57a6086573c87eb1
+CT = fb67cac222a86abe30f35d99397cb5b95970a3c746146a64235c34d1390bba5b008c3fb29c2df958
+
+Count = 32
+Adata = ebdf4c
+Payload = 86f354a505de941d34cd98e3af3706d56a938ab9a2797182
+CT = 54cbd15330d1816c0f836401999d9ac16445211b97a565575a733bba0a6992d0664dc77d2b5d194c
+
+Count = 33
+Adata = 7c0d70
+Payload = 88c3bfb546abe2f6bfc92a7c56c627e24ab92a8a87a6b43c
+CT = 5afb3a4373a4f7878487d69e606cbbf6446f8128b27aa0e90902a31b15eed99c2dc4ed1bf11cad96
+
+Count = 34
+Adata = 8fa501
+Payload = 75d4216bad77943bfe82be216157843b0da0fd16eeee8471
+CT = a7eca49d9878814ac5cc42c357fd182f037656b4db3290a42f25595ae00103d4eb20288158132e7d
+
+Count = 35
+Adata = b7aca7
+Payload = bf1401e8dcf6f681ed6dd74c7e23b7e54b384608b0e5ec52
+CT = 6d2c841ee9f9e3f0d6232bae48892bf145eeedaa8539f88760e67693b509ea4795b7da32c5c5d17f
+
+Count = 36
+Adata = 1f283f
+Payload = 7e623e7ef7d0a678b5d22a8402d89220f4f1bf759e3084dd
+CT = ac5abb88c2dfb3098e9cd66634720e34fa2714d7abec900880ef8ea380a1a0a38b2c20288e637a9f
+
+Count = 37
+Adata = e93f31
+Payload = 14f80e7a6298d85d31fb80376a394a8f88b0ae47f00450c7
+CT = c6c08b8c5797cd2c0ab57cd55c93d69b866605e5c5d84412d553aafe8536385d34c412c14d3a1563
+
+Count = 38
+Adata = 27e9a5
+Payload = 3330df12249639961f562a74b34f60b0a8bc7c783f6572fd
+CT = e1085ae411992ce72418d69685e5fca4a66ad7da0ab96628f594d366c8fc826ce58309e9053c27f7
+
+Count = 39
+Adata = 72d566
+Payload = 1a1860ac8c11c5d262f8141738cae8ff91ca05906dc98bb4
+CT = c820e55ab91ed0a359b6e8f50e6074eb9f1cae3258159f61cdd6ac6c42cd3d11e0344a9c1001e253
+
+[Alen = 4]
+
+Key = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb0
+Nonce = ba356d392c3f700f4f2706a4ca
+
+Count = 40
+Adata = 8ffc0e3d
+Payload = e8c1a89228d8212f75c136bab7923a89f9fea18e781cb836
+CT = 66b5d782323925e1bd0a8413a9a5a881356453d5df2cbeb199b2e1e803550dcdde55fd66ecb45edd
+
+Count = 41
+Adata = 2b4f9cfc
+Payload = a12c6324e022affd61b7e0d8cccbeb23e2e6c65355c1d586
+CT = 2f581c34fac3ab33a97c5271d2fc792b2e7c3408f2f1d3019e8fbc507244ba234a0581dc69962a66
+
+Count = 42
+Adata = b4de3039
+Payload = 7cccb26f1dd227bc77458b99fd9e00f8e801adaece7bfcd1
+CT = f2b8cd7f07332372bf8e3930e3a992f0249b5ff5694bfa5628a2857099af20a4ae08e687bdb02c75
+
+Count = 43
+Adata = bc59f18c
+Payload = 692b53c1355475c71ceff0b0952a8b3541b2938270247d44
+CT = e75f2cd12fb57109d42442198b1d193d8d2861d9d7147bc3e33a6416e387d9e571a1954471ec9cc7
+
+Count = 44
+Adata = 4fd9fd39
+Payload = 7e3e755e25bbe78d4a7770f9356ab9f4ff1bbfdba46383f5
+CT = f04a0a4e3f5ae34382bcc2502b5d2bfc33814d8003538572180f9735f994c8335e593f30b331a920
+
+Count = 45
+Adata = 296cd04c
+Payload = 997b712cd9295dc43cc19b40679f218c27af3e8c638d2e5d
+CT = 170f0e3cc3c8590af40a29e979a8b384eb35ccd7c4bd28da91990fa537d2657d01f66872ba9af22f
+
+Count = 46
+Adata = 88037d3e
+Payload = 577981ccb6c893dfe6405075fcb41507de7f9bfda860791f
+CT = d90dfedcac2997112e8be2dce283870f12e569a60f507f984915cb93e84028c7aedce1a2dadbb6bb
+
+Count = 47
+Adata = fc4bb852
+Payload = 37ba9f57ec230675ce060ba3d388095adf15907aa0b0673d
+CT = b9cee047f6c202bb06cdb90acdbf9b52138f6221078061ba25baa6385af8d7b807a2d2ab19aa4999
+
+Count = 48
+Adata = f40ec14f
+Payload = 401e0cdc132a9e4a9b5ceeed3c181f67e5203ea69508deff
+CT = ce6a73cc09cb9a8453975c44222f8d6f29baccfd3238d8786adcdb44870e1105b7318d8bad0af957
+
+Count = 49
+Adata = 90e2c63b
+Payload = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+CT = 8c40a5f5a79be2a2af34beb3212d8b12c1e13ceff68c2dfa8b079fb71d45bd985bffd343c3362653
+
+[Alen = 5]
+
+Key = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+Nonce = d4ef3e9e04f1b7f20ffc5a022e
+
+Count = 50
+Adata = a468f08d07
+Payload = d3bef460223c81e4579c9d1d463ac5e0881685de1420a411
+CT = abb85db49a9b1c8724ecbc734cc8373bd20083cfa4007b1cfe4d3a3bb25f89f692884be230c6035c
+
+Count = 51
+Adata = 4497649a54
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326461ee1
+CT = f9ab96ecd34a5695258f723269aaffc4ddf5c1329666c1ecd05ae56511a230627e02d066c52a919e
+
+Count = 52
+Adata = c30ddd994e
+Payload = 84b88264afec06b370dfcebf5e1d3e2c1f005faf248b3215
+CT = fcbe2bb0174b9bd003afefd154efccf7451659be94abed188ef92fc17dca026f1ac1eaf78a05017c
+
+Count = 53
+Adata = 9573270f7e
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a040
+CT = e64a237d0d2d13c8b62849fcffa6e2dbee2911c810717f4d38eddff1e60e2d9ae74a936364b8df21
+
+Count = 54
+Adata = 40336790fc
+Payload = 260f67122dfbe03365bc9e35e9d4ac4b2eb150eddb30857d
+CT = 5e09cec6955c7d5016ccbf5be3265e9074a756fc6b105a70aa3d464ad89cae59b474d019a5a7605c
+
+Count = 55
+Adata = 0b310c8529
+Payload = 1d55e7352bd895c4ef77389a7225c664f72b38c8de778d57
+CT = 65534ee1937f08a79c0719f478d734bfad3d3ed96e57525abeab0c520e64939c6950c0fa406eafb1
+
+Count = 56
+Adata = 5756b2c681
+Payload = fbd315e1f5bd0f0e60ee6684c88f3543452c62ea0701d11d
+CT = 83d5bc354d1a926d139e47eac27dc7981f3a64fbb7210e10d22d339c382343bf39c239fd64c2a64f
+
+Count = 57
+Adata = 3b919e3665
+Payload = d68d6556c5a5b1f5a123389b3ce966d5837cb8fcf5accfff
+CT = ae8bcc827d022c96d25319f5361b940ed96abeed458c10f2fcd6b562a1b6aa10be92a81f99ed540c
+
+Count = 58
+Adata = 58749b643f
+Payload = 062cb6962fa5b3a6239b95f3a51b478a1f32b081dc538a80
+CT = 7e2a1f4297022ec550ebb49dafe9b5514524b6906c73558d4b853022237d94d253b375bf2150e699
+
+Count = 59
+Adata = a5d50c008b
+Payload = 08c62ff9bd7bcf189f530d5065f8764532d2692f69858483
+CT = 70c0862d05dc527bec232c3e6f0a849e68c46f3ed9a55b8ee7aee0d403b2cf6f8b993eebd6b93615
+
+[Alen = 6]
+
+Key = 1c476cfd7dd300d961fd3f24a6fe0e80742b00851676ca63
+Nonce = e300fc7a5b96806382c35af5b2
+
+Count = 60
+Adata = 28130f938c45
+Payload = 6f3938932b5c1280311e892280d8a822a828a0be7fdb1bcd
+CT = df48662fe134e75a85abc2cece2c3b6236c88a70fa792e9beadc9601adf9fbdf4e3e94b395b0a332
+
+Count = 61
+Adata = f600024a7bf9
+Payload = 0af7345e71f4e8886503395ade0b0296a5856e086638b06a
+CT = ba866ae2bb9c1d52d1b672b690ff91d63b6544c6e39a853c0692a40a6aba8d7c5addae21de90fea9
+
+Count = 62
+Adata = 4eef510d1f48
+Payload = 37f57772f056f45a5ce9f46d27be1858980c8935b9c839b7
+CT = 878429ce3a3e0180e85cbf81694a8b1806eca3fb3c6a0ce122f64becb581070411957e632e19bb8f
+
+Count = 63
+Adata = 4c9c76b6fad5
+Payload = 8bb10c82bcabb7fb2b169252ab443b01df217cf908b8c241
+CT = 3bc0523e76c342219fa3d9bee5b0a84141c156378d1af71708c59f83aa97d069b6d83d9387051f43
+
+Count = 64
+Adata = 5572ecfc7e53
+Payload = d1ccb4654a22b1afe32f3d3035fdccd87e9cbed83c679007
+CT = 61bdead9804a4475579a76dc7b095f98e07c9416b9c5a551f04686ee1d7b985d903f1de6cf78f8f4
+
+Count = 65
+Adata = bffdf9d20d74
+Payload = f990a8f6ba14065d48665db36eb470c49f38e2b6376a9bde
+CT = 49e1f64a707cf387fcd3165f2040e38401d8c878b2c8ae88f8118f1b9f39b51965ae9ef1bdb40111
+
+Count = 66
+Adata = 3f27e678c580
+Payload = f8c7d89639ab742a8bcfffe776e868d671e1fbdd55807a8a
+CT = 48b6862af3c381f03f7ab40b381cfb96ef01d113d0224fdca3236d02f33f49759f281315e449bfef
+
+Count = 67
+Adata = 1294cb9db5f5
+Payload = 8601cfd7d935e8a8487b9c39d55ca27096255f2eb9e009e3
+CT = 3670916b135d1d72fcced7d59ba8313008c575e03c423cb5e74770a07c242c3854ceb242dadc1976
+
+Count = 68
+Adata = cec271332b75
+Payload = 77c85b8022f58337b364142a2474fe5cfddb31cfca48af46
+CT = c7b9053ce89d76ed07d15fc66a806d1c633b1b014fea9a10d6c65f19175cfa49898655ccdddb864a
+
+Count = 69
+Adata = da06bd140502
+Payload = b0f2db802475fa70af02057373844f637a3244cda4b4f93d
+CT = 0083853cee1d0faa1bb74e9f3d70dc23e4d26e032116cc6b458822e49e69031431b3eea872a72eb7
+
+[Alen = 7]
+
+Key = 79d1e38a70df1cf239be168833dcd0570bc8f37b3aa26c37
+Nonce = 8229d6d7e9e21fdc789bff5dcf
+
+Count = 70
+Adata = 076887d2abe900
+Payload = 83c24f3a77b83b4ef45277ba90225f3ba1722312f52b1a07
+CT = 19d880f1d959a68f162de243d4a45747ace704613359b27218d1531a066de60a95d2924a6910e990
+
+Count = 71
+Adata = 7535bcc6fbd1a0
+Payload = 24f85ef683cc521387f484bc0b2ad9172f61884c09a9718c
+CT = bee2913d2d2dcfd2658b11454facd16b22f4af3fcfdbd9f96dbf58406020e6df7b312b6825127f9a
+
+Count = 72
+Adata = f4f96d7b4384a3
+Payload = 212bedfa06b5e1a2c3a2f31f6f791dd9df8ef26077821c0a
+CT = bb312231a8547c6321dd66e62bff15a5d21bd513b1f0b47f64dd755177efc87f8b1daf1fd88e51a6
+
+Count = 73
+Adata = 3b7e3d9c1a7fa2
+Payload = 8b9036914bb0f440c8dbcfde9b9547be5e5ef1f56492c75e
+CT = 118af95ae55169812aa45a27df134fc253cbd686a2e06f2b0be31cab31f1a20805d5c07dc516d707
+
+Count = 74
+Adata = a8c35fae8912d6
+Payload = 50f3f3a91bf6fd9573d5ef54b9bb5805205b2f9865d81fd7
+CT = cae93c62b517605491aa7aadfd3d50792dce08eba3aab7a2399df9a45ad153c0dfb3fec3b9d6f7c5
+
+Count = 75
+Adata = db636541f2429d
+Payload = 6fbda8d435555e735443f1e6bc09e96065092efd89edd64a
+CT = f5a7671f9bb4c3b2b63c641ff88fe11c689c098e4f9f7e3fe20b7da94eac8c7ef8478671165e0d82
+
+Count = 76
+Adata = a8de55170c6dc0
+Payload = 640ef4c246a2c6e16ddc49072a5aeef70319149ffba071ef
+CT = fe143b09e8435b208fa3dcfe6edce68b0e8c33ec3dd2d99a4979c35bdbf9538666b6fa57f0f915d8
+
+Count = 77
+Adata = f8d64ce2aa66e6
+Payload = a14e3910766f31594a28ad2c3678c31d0c3aee88484ca6d6
+CT = 3b54f6dbd88eac98a85738d572fecb6101afc9fb8e3e0ea3752824a691da2e99374ae6c031d74ffb
+
+Count = 78
+Adata = b3c340afdc53a8
+Payload = 1b8e0a09e6364020b4cac704dc19bfa79455295604cf9c9a
+CT = 8194c5c248d7dde156b552fd989fb7db99c00e25c2bd34ef04159a68706faa2e8c3376b4dbeb423a
+
+Count = 79
+Adata = 73824034001519
+Payload = 52c84a0735eea6c5c230644075ebfc5db0c3128056e7a8f4
+CT = c8d285cc9b0f3b04204ff1b9316df421bd5635f390950081e5adc7564721ead2af75cb98e61148b4
+
+[Alen = 8]
+
+Key = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+Nonce = 3820db475c7cb04a0f74d8e449
+
+Count = 80
+Adata = f427c47e10c45bb3
+Payload = 54bc7e3c227df4e83252a5848fea12dfdb2d14b9e67c1629
+CT = 91e7baff2b42af63e26c87ce6991af22422c1f82906858b1721961de5c768f4d19bd3034f44f08d2
+
+Count = 81
+Adata = ca25504f3f5559aa
+Payload = ff4493fea916f49fbb3cae2838bc84e293531092cc0904ab
+CT = 3a1f573da029af146b028c62dec7391f0a521ba9ba1d4a3342968c638ecb8a2b358e8eaefd931efb
+
+Count = 82
+Adata = 8215753d9efc5132
+Payload = af16ab8558269a93d8e8c9e38f12a8768947d8b69be0e259
+CT = 6a4d6f465119c11808d6eba96969158b1046d38dedf4acc1f8ac11752fe51e354f3f8a68815539aa
+
+Count = 83
+Adata = 9e7cdbc6202e6492
+Payload = 744a167ae31a8ca20df82290766429de9ef0b7dfe199a78d
+CT = b111d2b9ea25d729ddc600da901f942307f1bce4978de915489de8e241dcab16bdcbf1a1ff4d8d10
+
+Count = 84
+Adata = b8d511d0ab86a07f
+Payload = eeb39de1fe21b5aba654da45fe1481decb22365fa4cbe49d
+CT = 2be85922f71eee20766af80f186f3c2352233d64d2dfaa053fab212a1b6dc7b953e2bc211be194ae
+
+Count = 85
+Adata = c74a5d4265f9f3d5
+Payload = e95c20e80153bae3fde3c3d82b6b33b35fc1959fa31a5d11
+CT = 2c07e42b086ce1682ddde192cd108e4ec6c09ea4d50e138973918ab70fe048d6c5b63a01725eddfb
+
+Count = 86
+Adata = fd849d3ada03181a
+Payload = 6d00606c72cea3deaea5b51ae09e61924355e167058ef42c
+CT = a85ba4af7bf1f8557e9b975006e5dc6fda54ea5c739abab487089bc20867f474c1127aa1320f0000
+
+Count = 87
+Adata = 56825a68681f498c
+Payload = c47705d897a6c7e7aed710b96e2d8532c23b82090e21b114
+CT = 012cc11b9e999c6c7ee932f3885638cf5b3a89327835ff8c34a23b0b6ac4d297dd7832a5e2102272
+
+Count = 88
+Adata = 72e4da839913a26e
+Payload = c822a1ee581cf85b0482c821473385bd3f28528e5e5760d9
+CT = 0d79652d5123a3d0d4bcea6ba1483840a62959b528432e41dd665766c7af21ff890bd40178f1c660
+
+Count = 89
+Adata = 138457571ee8dafd
+Payload = 3ffb82a83308da66e95ac63ae92931b09ffe0e42afbb4979
+CT = faa0466b3a3781ed3964e4700f528c4d06ff0579d9af07e16a6a58bb772c79481dc26861ffbd68c6
+
+[Alen = 9]
+
+Key = 39c03a0c8634047b1635348f284d3dc1e752ab40548eb337
+Nonce = 9e2ea8eb7f56087ee506925648
+
+Count = 90
+Adata = 28d157f09a71da80dd
+Payload = 0662e63c88e963d3e0cf2c4653515ae4474a2c78ab0394c0
+CT = 01dcd4dd3b8c1369518136ce45e8bb9df565b0ad231a887b02ada34addf0aa2f4744ed2e07995491
+
+Count = 91
+Adata = c17d311362c41d442b
+Payload = d6df8b60c697093987b3d89a3667b36504b6ddddf12b0900
+CT = d161b98175f2798336fdc21220de521cb6994108793215bb38a27466b8741bffce44ef04b23af321
+
+Count = 92
+Adata = 006669ef1a11b65b1d
+Payload = 49ad29ef5e82b08752ac5a50dd982e4bcb700005454ade6c
+CT = 4e131b0eede7c03de3e240d8cb21cf32795f9cd0cd53c2d77d11372fb0dab1c99b159e5fe9f91118
+
+Count = 93
+Adata = 8eafce9ba466fd53eb
+Payload = 385f9fb139dbf88561b7a500b0c7b835fe57e2698c6d9f76
+CT = 3fe1ad508abe883fd0f9bf88a67e594c4c787ebc047483cd09e4898a4046f6ec9f40e412915007e4
+
+Count = 94
+Adata = 796e55fbe7bed46d02
+Payload = 4ebb149b01cbacba32d11168ca61928ea149dcf2ee2c1001
+CT = 4905267ab2aedc00839f0be0dcd873f71366402766350cba5d40a9902481bfac7ff33d08fb4b3d31
+
+Count = 95
+Adata = 8f958d796be0566512
+Payload = 0d974e5621caa1d86eaaee689ccbca57843373fcf20db407
+CT = 0a297cb792afd162dfe4f4e08a722b2e361cef297a14a8bcd972d09a17172161eb68a30b593b1bd6
+
+Count = 96
+Adata = cc879ff2d583a7288c
+Payload = f8e0dac6a691dfb231411b5c5f70a0daff83cc637b0c7bb3
+CT = ff5ee82715f4af08800f01d449c941a34dac50b6f3156708119cc26a80c152c253fbc36cb886e0fc
+
+Count = 97
+Adata = 4765d696d19dec58bc
+Payload = 096a36396ccfa260f28fb0919157a5076b53506c51a2a4ef
+CT = 0ed404d8dfaad2da43c1aa1987ee447ed97cccb9d9bbb8549de06cc5c3bc4ad75076c774576843fb
+
+Count = 98
+Adata = a004f283afc3309c31
+Payload = 5b943269be41e2758a4ea6a3cc621b711a8ba6002783aa72
+CT = 5c2a00880d2492cf3b00bc2bdadbfa08a8a43ad5af9ab6c9135493b44f79a5774df6b2943b0bec67
+
+Count = 99
+Adata = cdd5d8aefe49a315ad
+Payload = 5f27867109e74862ce0dbc9ba73c420b93067bdede17ae51
+CT = 5899b490ba8238d87f43a613b185a3722129e70b560eb2ea7a5da4a29a9012d78b6de6f1b3e8c9ed
+
+[Alen = 10]
+
+Key = e2a92ffbb0b5eb68cb82687f12449fae5167d375131b0b10
+Nonce = 441ad5e1382e083a95224f395d
+
+Count = 100
+Adata = 2352648299b0413cb2ce
+Payload = 048c9ba4597c3bb595bfd5048e5e9a1296f30e5c0118b177
+CT = 25247a258e4ac0a988d8def60cc174a9d4578cd5346fb5150c96e8ab8774baa421f39c64a386c418
+
+Count = 101
+Adata = ce003c836a6f5f066053
+Payload = 02ea8e7e488c863584f828df13dfeb68433294d11d9ca9d7
+CT = 23426fff9fba7d29999f232d914005d30196165828ebadb5d453036cdc6bad0c5e770a6249a52e74
+
+Count = 102
+Adata = d11be73a104ccc6346d5
+Payload = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024
+CT = 4cfd9248f0ae6ccbcc072678175fa50e889b2fa48bfea4464627ad75bbfe17f3f5ddfd3dbc1045f3
+
+Count = 103
+Adata = 6a7b80b6738ff0a23ad5
+Payload = 97a813e75d95d25c2edb1c705c4ffe4d7c08c756761fbc0b
+CT = b600f2668aa3294033bc1782ded010f63eac45df4368b869af8943f74706cc3394a170fd49f7011a
+
+Count = 104
+Adata = a391acdb3a06dae4a671
+Payload = a78981ac244307451e4d3fd7f654b70cc4e6518aa47a3c18
+CT = 8621602df375fc59032a342574cb59b78642d303910d387af22597f63074ca3533bb5e107860481f
+
+Count = 105
+Adata = 0b9f28f2d3215785f569
+Payload = 5d649d79ff0e304e164a383c74f13d7ffab145d00cb0ec2c
+CT = 7ccc7cf82838cb520b2d33cef66ed3c4b815c75939c7e84e905b5609f593c6ea9281f66cd2e646dd
+
+Count = 106
+Adata = 7928b1091cbfb2eef0fe
+Payload = 83a273687dced7b94d569f81d75508595cde668f06406183
+CT = a20a92e9aaf82ca55031947355cae6e21e7ae406333765e1428195355618ea0cf87260ad20b6d7b9
+
+Count = 107
+Adata = 3b74afb81f54a93c79d5
+Payload = b4dc3c059cf7b47dd0bb7f165a63fc80b5c6b5f3ca7eeb73
+CT = 9574dd844bc14f61cddc74e4d8fc123bf762377aff09ef1155019659f41a5f0430695b4ada9d8b8d
+
+Count = 108
+Adata = a46ae4c71d4c9eb72fab
+Payload = 7e919581c5105d98717d0613e1ca869c6516506ea482d5c2
+CT = 5f3974001226a6846c1a0de16355682727b2d2e791f5d1a01514b252f33dc870c42260e48c4fa9fd
+
+Count = 109
+Adata = a1ace61711f0a09ac17d
+Payload = 3a4558b55214f21cbd2ae2eda5a2321cfc2f102e059b744a
+CT = 1bedb93485220900a04de91f273ddca7be8b92a730ec7028c263c667d7ed58907452c092905d0b31
+
+[Alen = 11]
+
+Key = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Nonce = 8e7d8a44244daa7df2b340993e
+
+Count = 110
+Adata = 521583c25eb4a3b2e46120
+Payload = 9f580cc6c62a05ce125c6bec109a48ca527ee26a64b14b68
+CT = ff0ff95bcb0bccd5e4aadd77ac6770f5013654eb3c6386fded2c87135861b43a99f258b6938f66e3
+
+Count = 111
+Adata = 31adb39e947f8883fa4b69
+Payload = f16bba081bddda83546eabc9a55c81a439720dd8562ce964
+CT = 913c4f9516fc1398a2981d5219a1b99b6a3abb590efe24f132b87476d66a1bd405f484ef9ac8ab7e
+
+Count = 112
+Adata = f05f39eb0a3d6460076aa8
+Payload = 6baf784f63cf45a1836fa8f3609fff7870ce8cbd1e91268c
+CT = 0bf88dd26eee8cba75991e68dc62c74723863a3c4643eb19a120b455b366cb104fd8b6dc2c80471e
+
+Count = 113
+Adata = 74c7a633ff73ff507009c5
+Payload = d8176a6de1c15a14c8b8b58725c179dc84c9308268d718d5
+CT = b8409ff0ece0930f3e4e031c993c41e3d78186033005d5400c8ca09f4bf06b1c27e75abf15112e49
+
+Count = 114
+Adata = ab322a88cf44b9ca774415
+Payload = 3706e4d8ff748574f382e5f9b0a3b6258f1f360fd87001b0
+CT = 57511145f2554c6f057453620c5e8e1adc57808e80a2cc25b3159274a7de3550baf759f7fae53dbc
+
+Count = 115
+Adata = d6fe6e17221d4e06ed3ab9
+Payload = e02217394772deffe218c405e40f2a3a56ca01d55d6d3330
+CT = 8075e2a44a5317e414ee729e58f212050582b75405bffea516fba8d193e133e6f78daa39681cb262
+
+Count = 116
+Adata = 2739d2cdfcbe7d5cd7d28c
+Payload = bb713f74a884bd1a994adba87561d637853c6181290ef5e8
+CT = db26cae9a5a574016fbc6d33c99cee08d674d70071dc387d65f92db3b3d1c2de04c69c5d06b0e001
+
+Count = 117
+Adata = 5841571299cd064a6262b7
+Payload = 9641dedd50d80ac0abf7591436065fa2e23e4687abbb86e4
+CT = f6162b405df9c3db5d01ef8f8afb679db176f006f3694b716e4d20ab5ffad6f71155f6839dfdbb25
+
+Count = 118
+Adata = dc5d7fd97bb3243ba585fa
+Payload = aefda8501193edacb8abb94fff875529a537a462c4b9b69c
+CT = ceaa5dcd1cb224b74e5d0fd4437a6d16f67f12e39c6b7b090ebc3af2de52b8bee3d130fa973f716b
+
+Count = 119
+Adata = 8789e0b3e0dc13d9725b37
+Payload = 65e53f549b62aca03f21ab2a494b93805e02cfecf4f12aa4
+CT = 05b2cac9964365bbc9d71db1f5b6abbf0d4a796dac23e731b5cd5a004a0ef28e30383bdaed8f93c7
+
+[Alen = 12]
+
+Key = 44cba20b7204ed85327c9c71c6fea00b47ce7bdde9dea490
+Nonce = f3329154d8908f4e4a5b079992
+
+Count = 120
+Adata = f1e0af185180d2eb63e50e37
+Payload = 6333bde218b784ccd8370492f7c8c722f8ef143af66d71d7
+CT = b9401a4927b34dc15e9193db00212f85f0c319781ec90e3b4484d93cb422cb564acc63d3d18e169c
+
+Count = 121
+Adata = ea74231e49e667ca1c21d46d
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+CT = e67d8fbeec794d42fc64d7f36a87d2ac22aafa440021ea72c4c151d9927e6a9f19d47ff7d79ca6f6
+
+Count = 122
+Adata = 7f5871a8300471dc325f8289
+Payload = c642c9722d84d708682350dc70bdaa9a1181a415a9e72b93
+CT = 1c316ed912801e05ee85c7958754423d19ada9574143547f959eee29be1415ab03444de0fa42707d
+
+Count = 123
+Adata = ee7e6075ba52846de5d62549
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = f8f50646e284ba77f4ea3e08d69777a53aab062ec784ad70ce97c1c8aea70de04580d7b37f8c014d
+
+Count = 124
+Adata = a30f2fd445820cdf80014554
+Payload = 92577d5db20391110309d490f52acecdfc18382f368bbe42
+CT = 4824daf68d07581c85af43d902c3266af434356dde2fc1ae23b536f993381e525a14599dd5c02e80
+
+Count = 125
+Adata = 0cfec933831644b468724e80
+Payload = 6803dc3f7c06568ca78ee5aa2e9b1b354a4f1e067ff6a25b
+CT = b2707b9443029f81212872e3d972f392426313449752ddb7d6ea722fdd82ede2c7b8832dde3cbe80
+
+Count = 126
+Adata = 6bd14e3bf91dc7fd6be07647
+Payload = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adba
+CT = 8ff3c0856dae0290f7eca38aebda1485163fe5bbe0edd2565c2994b2b469ad977564d83db1ebfe38
+
+Count = 127
+Adata = 6c6ad35e97d023217018162f
+Payload = 1bd1bcc6766d251144376d91ff93ef83033d0e0ee546266f
+CT = c1a21b6d4969ec1cc291fad8087a07240b11034c0de25983ac31ebf9e255eecf3c69ddf198760556
+
+Count = 128
+Adata = 52c35db85cc34b6efed180ee
+Payload = 28f71a2fe498f89203a5d23e8f8fa64b124aea6459fe721d
+CT = f284bd84db9c319f8503457778664eec1a66e726b15a0df13424079e3de87fa59c3d10fd62380a90
+
+Count = 129
+Adata = a96e4776270683ee7d0c9b6e
+Payload = 5be078ead1926074afca81f9a97dc93dcb954c955e4343e4
+CT = 8193df41ee96a979296c16b05e94219ac3b941d7b6e73c082258e1f3fc3eb7e976c86c8a21bd6569
+
+[Alen = 13]
+
+Key = b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731
+Nonce = 13501aebda19a9bf1b5ffaa42a
+
+Count = 130
+Adata = ead4c45ff9db54f9902a6de181
+Payload = 3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34
+CT = fd80e88f07dad09eed5569a4f9bb65c42ef426dda40450119503d811701642143013f28ce384d912
+
+Count = 131
+Adata = e63b89e95df8338ecdcc885c3b
+Payload = 37f86aa62b1e31e9ded3e1a38a7e1a8a638d619ac109694f
+CT = fd5e4383d49a097ea9f835351bb5714999cab5d5a356836ac6d3f9c7b9f25e09ce164a11370b8b05
+
+Count = 132
+Adata = a2161536e263459e0b0a29a225
+Payload = 1749f5977197359a5d318d5fea38aba95b3603f1d7011e66
+CT = ddefdcb28e130d0d2a1a59c97bf3c06aa171d7beb55ef443e02b848b006c28803303fd97bdc35476
+
+Count = 133
+Adata = 8ac95a6ae0bce0fb07f85368ab
+Payload = 0842bfb8b38283257c2ea58b29c8350775f1dbf15f73c905
+CT = c2e4969d4c06bbb20b05711db8035ec48fb60fbe3d2c2320431de2bc45b2b726bfda92939a11f68b
+
+Count = 134
+Adata = 44cc9b2510680c4d73f1938c77
+Payload = 68d09fce5e89e4ef6d453b8ee326090cedb97b75b886c7b3
+CT = a276b6eba10ddc781a6eef1872ed62cf17feaf3adad92d96786add8c2619f0782ca12312a1d64266
+
+Count = 135
+Adata = d8a662ab8449bd037da0346a24
+Payload = 45245de4ac6a6196a0b15b77c622a21bb50627379ddb4256
+CT = 8f8274c153ee5901d79a8fe157e9c9d84f41f378ff84a873b6bd4a09f9b4aa2864d39ff1a03e0ff7
+
+Count = 136
+Adata = 8ed39da1d9179e77156eb909f3
+Payload = e928e37dbe8389a53c650edc86f83cd3589a53dc8e45adfd
+CT = 238eca584107b1324b4eda4a17335710a2dd8793ec1a47d819b6935778ffbc0953974de0a9d87a31
+
+Count = 137
+Adata = 423515f7bd592d6a7a2408661a
+Payload = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b1
+CT = 869df54479ad40017e50e6012b5bd71d829b5ed19c64329400a3da0d3ce34a272b51582a998f461e
+
+Count = 138
+Adata = 5a6bc2cd6890a473d478a582b4
+Payload = 1c5ebaeb7b926a39b8aaf65a4c484b113d6f2caafadc33ea
+CT = d6f893ce841652aecf8122ccdd8320d2c728f8e59883d9cf4ef28c338f497a40f550f2945734ad1a
+
+Count = 139
+Adata = 7bdc26b5b4df58af539d91eb2e
+Payload = be5c9fee6babf569c66e6a0d0f3c4dc314f40c0aeca493f7
+CT = 74fab6cb942fcdfeb145be9b9ef72600eeb3d8458efb79d2e07f1998e57ba9b611568632dc5cb9fe
+
+[Alen = 14]
+
+Key = 13f179aa2a23bc90a85660306394940e9bb226ce3885ec01
+Nonce = aaa52c63ca1f74a203d08c2078
+
+Count = 140
+Adata = 5cc924222692979a8e28ab1e0018
+Payload = d3b36c6289ad6ae7c5d885fe83d62a76270689ce05fa3b48
+CT = bc4fcef401c2e1d1c335734ff23ea52c3474d2e6f31648a7f58649400ac9e825b038d67f0c2a6f1c
+
+Count = 141
+Adata = 21fb9cdd9b110bbbc6832275dfa7
+Payload = a7742dd9c3e8bbad08157fbd01ebfb94e1639117c4b4eb5d
+CT = c8888f4f4b87309b0ef8890c700374cef211ca3f325898b23fa5ad4142e0b4650fa5cc8f7ef70d62
+
+Count = 142
+Adata = 9919ddb6ee6c330646cd15953d39
+Payload = 297b4498bf5427e6341aa9275c1f62e3b0c9b150a195ae72
+CT = 4687e60e373bacd032f75f962df7edb9a3bbea785779dd9dfec551d11b8647432cc4320173939600
+
+Count = 143
+Adata = f94cfd1f8c7902a57784c10b9a5a
+Payload = 2218868033e17220655f0196dab6193c58293ca105d467d9
+CT = 4de42416bb8ef91663b2f727ab5e96664b5b6789f3381436a79a075ec2cacee1482b8328b697a3b2
+
+Count = 144
+Adata = 63f3fe58c348dc6bcbb44c3c370f
+Payload = 4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ffa8
+CT = 256760f9396f8b937d738519d23b803cfcefb350d4ed8c4739cbe17b4edd64a3dcd2b8ae3352c04a
+
+Count = 145
+Adata = dec0ce763833305aa9c9efdc2c65
+Payload = 1b61b3ff3e4847a17f55f7565826b0e2ccc1368f4de32022
+CT = 749d1169b627cc9779b801e729ce3fb8dfb36da7bb0f53cdf54665c476d0741164685b0d81caca31
+
+Count = 146
+Adata = 592ef6784ee839a049e0d96257fa
+Payload = 32e5998b37987a38800f5bfe3132979ca1447314570aaef7
+CT = 5d193b1dbff7f10e86e2ad4f40da18c6b236283ca1e6dd18500d93b11fecc8b4560320878ba53550
+
+Count = 147
+Adata = 4a47a82b999a2a739959f153a091
+Payload = 84acfb6cf10b301558e5acbf41bbbe0b145dc66dc600f4df
+CT = eb5059fa7964bb235e085a0e30533151072f9d4530ec87303c2a41443578adaf31483bbb6b9f10b0
+
+Count = 148
+Adata = 4ceba98cc0ff5de1a7d580cf23d2
+Payload = d7c73d77a286df38aad116843620911c92e11486be5fcb0c
+CT = b83b9fe12ae9540eac3ce03547c81e4681934fae48b3b8e32232a856c07999e99a4701988b486ef2
+
+Count = 149
+Adata = 15e3b3c5794fececd703ac58ccb2
+Payload = 140882c5d3534bb0861e7ba9423e67439a02ee6f0b0b00f3
+CT = 7bf420535b3cc08680f38d1833d6e8198970b547fde7731cb3a6d50a92f3183c0c5090edc3c7f822
+
+[Alen = 15]
+
+Key = c1dfc48273d406a3a7b9176f80b2dc4e9a7f68134bab66d2
+Nonce = 1ac53ba965cdaeeef7326a37e4
+
+Count = 150
+Adata = 39ba54a410a58a5d11615a2163cc3b
+Payload = 67d9728a88f1fac3af43ed6d634ba902896bd226858697d9
+CT = 360f0fc714994e3b59448b50cdd61d511b4f09e0e5fb5ac826a51fe5b9b598a17eb3da10f936813b
+
+Count = 151
+Adata = 38b0cca09d69320105d24ee3f96684
+Payload = a8365ba9fcfff060b28895f7a2d786c5991a8f7758962caa
+CT = f9e026e460974498448ff3ca0c4a32960b3e54b138ebe1bbba673a94f4280e84724f4a2510165e9a
+
+Count = 152
+Adata = 76718dfb9c68acdd82592d96def39a
+Payload = 497be597dd695cb159d8a64f44049c3b549ac927837b1b90
+CT = 18ad98da4101e849afdfc072ea992868c6be12e1e306d68118865ab37be6f015316e0d177b6c2e91
+
+Count = 153
+Adata = dd719ba1710916a546233c1494a7a7
+Payload = ca452c21383ebc3fb584f0d59a227374854983f243a3f460
+CT = 9b93516ca45608c7438396e834bfc727176d583423de39713d903f67ad0d72fb8ffea2035216b769
+
+Count = 154
+Adata = d893fa2bd7c70e21a5934dc2e99037
+Payload = 3dd118ed65453d3d7844d8de78d7a43587ac5e9305b11464
+CT = 6c0765a0f92d89c58e43bee3d64a10661588855565ccd9750b885e3e054f519d0355db1bd589bb35
+
+Count = 155
+Adata = 97c60265a3a6993b97ac1b375a79b8
+Payload = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117
+CT = f6e126eebe391bf9cebaf9e55248de2fd18ff76fc781cc064a950e4bed4137e38787839e39924821
+
+Count = 156
+Adata = acfdf302ed116ac4755069d1704423
+Payload = d39d188f28521e4fb0a0c5e48e6d6efe4383c95b2535ea8d
+CT = 824b65c2b43aaab746a7a3d920f0daadd1a7129d4548279cca94dd97fd2a5d50eb7dd6234b40c525
+
+Count = 157
+Adata = d449f97164aae9a3046624e98810bc
+Payload = 758102470e221e30d87d2807b5f8b793a7a56c83eecf32a4
+CT = 24577f0a924aaac82e7a4e3a1b6503c03581b7458eb2ffb596f11450d5d2ba55ffb4a6cf7eab847a
+
+Count = 158
+Adata = 3e6c914a196e175079315b1c92b2b8
+Payload = 1db875c4b4f9dd4926dfb5604d6c4d21aba7d905aed9d1b0
+CT = 4c6e0889289169b1d0d8d35de3f1f972398302c3cea41ca164894e9218ecacd143fb62df69a13d33
+
+Count = 159
+Adata = e2b7b00d0cfbdfcc24f1819ae1869f
+Payload = d7a75bc621addccbbe162b86d536d69c887c278384af54e7
+CT = 8671268bbdc5683348114dbb7bab62cf1a58fc45e4d299f685a7c19bc9c2f8e36ed95015ebb679ae
+
+[Alen = 16]
+
+Key = d8a662ab8449bd037da0346a24565683a3bbbbd1800e3c1c
+Nonce = 166fb8d0e110124c09013e0568
+
+Count = 160
+Adata = 1c1c082eeb5b8548283d50cc2ace1c35
+Payload = 61fdd10938557080191d13dd6c3002dd445d9af988029199
+CT = 23c05927502a4ee6e61e4e10552d49b020643eab476eeacc867601fe79a122a7817819655183283e
+
+Count = 161
+Adata = cae884fa25adedd883ef4e7c855def19
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = ce476aedad7cd761d26d59297533ece2b6703002fa0bda63160bb976ab072aec8fcea8eab3dc5aff
+
+Count = 162
+Adata = a350ed58c04473e113b9088b1fb9dad9
+Payload = 863f9a26182f131c594972398b52b3a01a9d314fd9390bf4
+CT = c402120870502d7aa64a2ff4b24ff8cd7ea4951d165570a1291b2c13a3f5e49ce35b9047ee1e8627
+
+Count = 163
+Adata = cb7090f7a465782f680fd44cbc558107
+Payload = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402
+CT = ffa941830a2cfc3b3b14a5b6574fab5b45f550e17099cf57fdd9fd1d469a9042b80e6458d25292b4
+
+Count = 164
+Adata = 914cf55a3fc739b5f87ac7518cc4171b
+Payload = c313bd213dc29c00691e25ce028884192e21a820003aece4
+CT = 812e350f55bda266961d78033b95cf744a180c72cf5697b1a8b8e82175ff30c69ea71d2cfb814ada
+
+Count = 165
+Adata = adc8b69d84ef7ae62f9ca9f371d3488e
+Payload = 85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2
+CT = c7d9687dd109de0c9bdcf59f082d86b566ea439119bbec9776fa36db27b2f84d1b8ab55e2fc89ab8
+
+Count = 166
+Adata = 29ed477994dd231d3a71157eb56d219d
+Payload = c77aae5fd09dc9bceee7428e0734d4b0556528396a58f909
+CT = 85472671b8e2f7da11e41f433e299fdd315c8c6ba534825c0e32058ea939036805a735198934a072
+
+Count = 167
+Adata = 494c8f931029a4919e2dcbc16512a8bf
+Payload = 1f47273103f265f963e498878361c06c01a5ffcfb630a161
+CT = 5d7aaf1f6b8d5b9f9ce7c54aba7c8b01659c5b9d795cda3437098c81475f8a1d8f3b0e63d499d387
+
+Count = 168
+Adata = 53200bc5d1f1fb0eeff02d2bc42f7d54
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = e1bfb9812822f9d1f38ee14181532085c4e58ac732b057bd9d7317973878957e8fc1fa57a025a3e9
+
+Count = 169
+Adata = 61e0e28bf344a9a1b04b15156e06498e
+Payload = a0d3a94ba6bb3bedf38220d1cba7e91273ad19f9a1c436c0
+CT = e2ee2165cec4058b0c817d1cf2baa27f1794bdab6ea84d95b0aa1befae96e71b9d221673844b1cb7
+
+[Alen = 17]
+
+Key = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5
+Nonce = 924322a3ef0c64412f460a91b2
+
+Count = 170
+Adata = 03c2d22a3bb08bbb96b2811ce4b1110a83
+Payload = 1bd3b5db392402790be16e8d0a715453928f17f3384c13a7
+CT = ad736402626df0f9393fe4491eb812725ad39d6facf20b5b2f9340b0d48a17ae1cc71d7515e61ee9
+
+Count = 171
+Adata = f390387610741d560325b5d2010d8cd4a0
+Payload = c93aaa04279e451b6880ed7b7fdb3ca9e80ab76180434937
+CT = 7f9a7bdd7cd7b79b5a5e67bf6b127a8820563dfd14fd51cb717bae4c040561bcfcf80fd842ae8dd8
+
+Count = 172
+Adata = 891d7988a56415a7b433f463b1e80eaa62
+Payload = 2611612ccb5ffefaa73195509bb52c641472bca0dfd09d49
+CT = 90b1b0f590160c7a95ef1f948f7c6a45dc2e363c4b6e85b5bc9fb15d874feccb6b5f581fa470734f
+
+Count = 173
+Adata = 831c0fed5e600dd82d7d55669262a9a17d
+Payload = 08136e946e306cde0544ddc2f3f4a529c89c7b77a5e635c1
+CT = beb3bf4d35799e5e379a5706e73de30800c0f1eb31582d3da72589ee50d23f925f7998ab3ccac37f
+
+Count = 174
+Adata = 32ca9d412d4ef0e89928496e96c9de7f2e
+Payload = 695aaac402942de7d899cc3f741c7fb2b2d8247a7676cf29
+CT = dffa7b1d59dddf67ea4746fb60d539937a84aee6e2c8d7d555c0b608f331dca47c65f5c879f2d532
+
+Count = 175
+Adata = 0746b2e6149c7f55854e9ca3e6861bf0e9
+Payload = 8f958d796be0566512f0512dcebd2e12f3160b05b72ae955
+CT = 39355ca030a9a4e5202edbe9da7468333b4a81992394f1a9b039bd916e923e2fc1f7c60eb59916fd
+
+Count = 176
+Adata = 0e4cbd1c574d656112bf6e70a8f23347f0
+Payload = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364
+CT = 80de1cc22a964beab63cbc5b3cb91bdb23ac4da247e34b98ac07f2c0847069fe5be26e623033f532
+
+Count = 177
+Adata = 1a05ff12412bf728497536534c234901ce
+Payload = a9ccee975feb10f635d548a8502f7c8b6adbd2be74117257
+CT = 1f6c3f4e04a2e276070bc26c44e63aaaa2875822e0af6aabf4e66a2b210e5a03bb10ff2926ed8a48
+
+Count = 178
+Adata = 3bd063a51c71fab5aeb47e7f8f958d796b
+Payload = 7df6220599d6235eb450989b6f0cd6c96db62b0d13afc4f4
+CT = cb56f3dcc29fd1de868e125f7bc590e8a5eaa1918711dc08ec90169d0c5c11fff8f255fedb13a99a
+
+Count = 179
+Adata = f0d334e0a27c3d00d56b15c2ee426e6347
+Payload = 6f65a24344c32debaf9f8c3fa426fe0b139e8ad1c8b1fbbb
+CT = d9c5739a1f8adf6b9d4106fbb0efb82adbc2004d5c0fe347170141cf3f207c4f0fc1b0238477cfad
+
+[Alen = 18]
+
+Key = e67f3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863
+Nonce = a727ed373886dd872859b92ccd
+
+Count = 180
+Adata = 68d199e8fced02b7aeba31aa94068a25d27a
+Payload = d7a954dae563b93385c02c82e0143b6c17ce3067d8b54120
+CT = c6cfaa1f54d041089bd81f89197e57a53b2880cefc3f9d877e30b2bcc3f1ea9ec2b8f28bf0af4ecf
+
+Count = 181
+Adata = fc4bbe329a86089ebe2a2f3320dad55a9bda
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd2
+CT = b3605f2ec11a2a70abff1c3ab717fd172ba9e9ac72d961753a6e6844102d6bb86986c030765d3393
+
+Count = 182
+Adata = d8741e540330692d83cc806a8ac1c4742be6
+Payload = 56ef76dbec6b8b46f5b7b4e311c0baaa6fcf54c69c0b9c3b
+CT = 4789881e5dd8737debaf87e8e8aad6634329e46fb881409c3f92a80b1d82f8c1dc32bfe64adca12a
+
+Count = 183
+Adata = c8b1992dfba55b4ab86b480546c861655e1a
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 364f9da4a34153d9d97696eed355ec79d464405a927d14a12fb48ad162b0c0678674d79d26a6b5ef
+
+Count = 184
+Adata = 347e12eec56e95aafcc7d25bf10fc756b4e4
+Payload = dd433eb7422c7c4dccee57a1679633ced3b5f08df763d457
+CT = cc25c072f39f8476d2f664aa9efc5f07ff534024d3e908f081c7cd81c974d985bf24b7fe9542141a
+
+Count = 185
+Adata = 45b35a04d6e2645e9a5aef206ed4e36199c9
+Payload = 70523bc397417e09d791a4976960e02636ca7144a5681cf7
+CT = 6134c50626f28632c989979c900a8cef1a2cc1ed81e2c050a7f6a5c04e59896074e1594706ab27e9
+
+Count = 186
+Adata = 378b48531fe34f55125b2f14f59715dd6ef0
+Payload = 514cb462dd4b117f26cac22062fcbeb353650c71649a7b3d
+CT = 402a4aa76cf8e94438d2f12b9b96d27a7f83bcd84010a79aa9d16c3ab79276cff345444511940a9d
+
+Count = 187
+Adata = 73ed686d6fecdc031cd97653137f269d6537
+Payload = 7f0c2b261db3f3de0ce3a733f4b8c446c374567d96d00379
+CT = 6e6ad5e3ac000be512fb94380dd2a88fef92e6d4b25adfdef92bf8aa6facbe6f9607ea02b54a1bf0
+
+Count = 188
+Adata = 5b0441107e5560be94f030a41cedbdb116d9
+Payload = ebb3e2ad7803508ba46e81e220b1cff33ea8381504110e9f
+CT = fad51c68c9b0a8b0ba76b2e9d9dba33a124e88bc209bd238e4936ee93b5c7a302913292df33c1700
+
+Count = 189
+Adata = feedcc5f8524fe7d49bcd178415b9f4c450a
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = 237022260902363567fc3cf433ad446235fc1a5a3d53ad7493426b6193afe765a76b3dec00266e69
+
+[Alen = 19]
+
+Key = e0a29a2c7840cf9b41de49780b9ee92d646a4bfc5b9da74a
+Nonce = fc9fd876b1edded09f70b18824
+
+Count = 190
+Adata = 36e15baafa0002efbb4bb26503b7e3b79f6c68
+Payload = 344dc8b6bd66a1fbbe330a95af5dd2a8783dc264d6a9267d
+CT = 43b3b96aa5a54378f3bb573ffda3e154aa7f425fc3008175b60a77b9d38740356b544b1c0f259086
+
+Count = 191
+Adata = 712b788f0276e2b5a58be80f9114a12ab2a268
+Payload = 6d0546d4e95d1cfcb37a8f88a62064f5d95791311511535b
+CT = 1afb3708f19efe7ffef2d222f4de57090b15110a00b8f4535f750bb4cd42db3038e2c1622b72cea8
+
+Count = 192
+Adata = 07f77f114d7264a122a7e9db4fc8d091334a03
+Payload = 05024ce13b9057dd2c509db7dbcbd5585e4e64a1e2e380ff
+CT = 72fc3d3d2353b55e61d8c01d8935e6a48c0ce49af74a27f761e77b59ef7eeeae35bb53bb9543b64a
+
+Count = 193
+Adata = 899b036138cee77cd28382ba27984d858a6351
+Payload = 77b8e735b13b10e45e411ab94c6fe1a9eb89f0a7af40ff1a
+CT = 004696e9a9f8f26713c947131e91d25539cb709cbae9581244a60fdb473098a11b2176d37b2c4643
+
+Count = 194
+Adata = 4b000440a8484a5201cd54aec058919769772e
+Payload = 6b21800ae599a15254bb33f0bb080788fb6e9fa054bfd8b2
+CT = 1cdff1d6fd5a43d119336e5ae9f63474292c1f9b41167fba58d4afc30a7f672ea34e05ec1843d848
+
+Count = 195
+Adata = 73a222e681ed1ca47d92a6dd90625d895fbf29
+Payload = bfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028
+CT = c857a87376dcd0352fe24172c9e201ade919d09a987317204ef270e0f3b5e3ca0b8440af65c76e85
+
+Count = 196
+Adata = 7109a3a36b286059bc1a1abb2767c92f884e3f
+Payload = c68b1bc0050e19780ab53efbea175634f70a7245d966966e
+CT = b1756a1c1dcdfbfb473d6351b8e965c82548f27ecccf3166ffb66991b38a0345fbbff5f2362f87de
+
+Count = 197
+Adata = cd15973753b94b77bb4b778de8b3b0cabbde85
+Payload = 4256f1c9b64390fe2120df9fd38e497c2903c2ca5679ab75
+CT = 35a88015ae80727d6ca8823581707a80fb4142f143d00c7dd033a087c44c2e44adbeb333aa9ded10
+
+Count = 198
+Adata = 6e5e0793855f7145e13a5872f563e5ec61cfd2
+Payload = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192e
+CT = ccfe476f53cfc28a00bb072626088022766c6cf454ecbe26ff9c8713422fe38d5bbf2dedccbffe10
+
+Count = 199
+Adata = f844684f5404e7d8eedfa20394b40b4f5d910a
+Payload = 86afa9cdd743916563ebfd3adbdd56e015ea3a4ebc61cfe2
+CT = f151d811cf8073e62e63a0908923651cc7a8ba75a9c868eae75de56eabcf8e02c1a27705adef2732
+
+[Alen = 20]
+
+Key = 26d0a3a8509d97f81379d21981fe1a02c579121ab7356ca0
+Nonce = 8015c0f07a7acd4b1cbdd21b54
+
+Count = 200
+Adata = 093ed26ada5628cfb8cfc1391526b3bcc4af97d9
+Payload = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711
+CT = a3a60b422eb070b499cf6da0a404b13a05cedda549c6b93e6ca0e07e04674f21a46df2659a5905fb
+
+Count = 201
+Adata = 7df13c9d2247aa40af7bbe2da98bd366d8b47b43
+Payload = 93925579b6367ff592ecbd59495fdeccb50f31ea4fa390bc
+CT = 079f7430e3ef9b6373c1c0cb11d884507d02a31d83cd9e93836597806f5da1d176c745d95c4fa46a
+
+Count = 202
+Adata = 7f369bbc99b6f08049eeb43566269a174829d4dd
+Payload = 8363aef9c7c34e1f8149de46c97d5ac79d38c6ed31ab1d12
+CT = 176e8fb0921aaa896064a3d491fa005b5535541afdc5133df826dda99111691993027628c70ff6ae
+
+Count = 203
+Adata = 04aa8442179f62babad0c006e36af0c21105f27a
+Payload = 17281acb525b13653000ab45d86e70106c10a93c99b18f76
+CT = 83253b820782f7f3d12dd6d780e92a8ca41d3bcb55df8159d074b018143a7ea1b5369b7f80eae20d
+
+Count = 204
+Adata = 997e646014f19a53beab8877ca6022bef23016f1
+Payload = 5d48a71557608736eded309027a80349a18e9ce5dee2bc6a
+CT = c945865c02b963a00cc04d027f2f59d569830e12128cb2455db17d3f75214c3cf39858617cfee57a
+
+Count = 205
+Adata = 60ffcb23d6b88e485b920af81d1083f6291d06ac
+Payload = 6c9d11cfb64d96bfab61c04a25d9e19294fb7330fb4847c8
+CT = f8903086e39472294a4cbdd87d5ebb0e5cf6e1c7372649e79550998376e61e11a5a69e9f8fe1c329
+
+Count = 206
+Adata = d574632658bf456dfbb11c2653602ed0f4dae777
+Payload = 7d41688c86d5e3bc53966810f2299fdd732e3471fb0a88f9
+CT = e94c49c5d30c072ab2bb1582aaaec541bb23a686376486d6a1b0d05a7ebc657c3235479893bf7e5d
+
+Count = 207
+Adata = d896ed60128f4bb0277d3af94c5138cf91697aa9
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = 1877c38a90da0d91cc43797614a9fd131a4406a7f909af1980c98c8959c158ce209aebcbd554f250
+
+Count = 208
+Adata = a350ed58c04473e113b9088b1fb9dad92807f6b6
+Payload = 49bc9d3bcf3c22daa8cf55c1b59d4bffddc2412d60518e98
+CT = ddb1bc729ae5c64c49e22853ed1a116315cfd3daac3f80b7573175f9105cd16ee384465ebb232200
+
+Count = 209
+Adata = 1db5887001204194e8b5dcee92c8af8fa5f7321f
+Payload = 25f3788e0d3dd8f5821faa4e45a9d6b3995fd881f927135c
+CT = b1fe59c758e43c636332d7dc1d2e8c2f51524a7635491d732b67e993384f2e7229d1838efd040d99
+
+[Alen = 21]
+
+Key = aac60835c309d837aacc635931af95702a4784c214283ebb
+Nonce = 0e20602d4dc38baa1ebf94ded5
+
+Count = 210
+Adata = 796e55fbe7bed46d025599c258964a99574c523f6a
+Payload = e8610756528f75607b83926597ef515f4b32a8386437e6d4
+CT = e0a3d5f43e688ce104f4ae1a4fcd85500aa6b8fdbcd1b8d3003c0c3b7369e79339433e1754c0937f
+
+Count = 211
+Adata = 5170836711fcb1a350b087907d8a17c7637aa1595b
+Payload = c61b0c1845fa9b2e0013b3fa9a8cb4f4fbbc6846f63ed180
+CT = ced9deba291d62af7f648f8542ae60fbba2878832ed88f87120a7f18d021833b167bf330c4858239
+
+Count = 212
+Adata = 2a68e3fe746f593c1b97cb637079c3e5ee352c107a
+Payload = 10c654c78a9e3c0628f004b061e28c39a3c23e7250f53615
+CT = 18048665e679c587578738cfb9c05836e2562eb788136812ca9698d9a88e892c364e57dd35c2f17a
+
+Count = 213
+Adata = bf38ca0e89b8f5ccd29387f7f193ab5a967caa715b
+Payload = fa3a959fdff853c39f76da626094a1ea6dbc78bd2f091a79
+CT = f2f8473db31faa42e001e61db8b675e52c286878f7ef447ef3839d6f7e20a2e343f4c4da9eb9be13
+
+Count = 214
+Adata = bee00f2f75a4415ce993d2d14a6d8e01d1d59a48f6
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f6d
+CT = 7e13fc9e20ba608a8a14fa757cbb4a5dd81998ba4fa1216a6630bfb7a2a2441e020efdf36274b72f
+
+Count = 215
+Adata = d5b614e4e8f72a5d8b1ec2b375da5dac64c2cc30b1
+Payload = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b634
+CT = 61fd7cd894ad5a168fc586d10191139a7ee1f78794afe833866bcee343ec5aae61f9effa19b99d3b
+
+Count = 216
+Adata = 33f11aa36d8ab0fc53486839a576b31ee915dbd769
+Payload = 56ce9a09f38127b14dbbdcaa59f363c92a3b9843ad20e2b7
+CT = 5e0c48ab9f66de3032cce0d581d1b7c66baf888675c6bcb00331b60eb252f744a06b4a95aa9f4e7c
+
+Count = 217
+Adata = f40bce1a6817b29b9e8b56f214fcca7dfde17e7ee6
+Payload = 5cd8986e974d09ede34ba68fd81d6109a64092e7fbbaf87d
+CT = 541a4accfbaaf06c9c3c9af0003fb506e7d48222235ca67a4153778a644cb2469cef3ad125e257bc
+
+Count = 218
+Adata = 53c457d8d4d4ab95ba116c28b82c16743cb09de9fe
+Payload = 9c3c610f204d98702dd91ea28e0cc14830b26bb5e2ee0349
+CT = 94feb3ad4caa61f152ae22dd562e154771267b703a085d4e7013e1c34dbc5efc7bcd4f8e52797644
+
+Count = 219
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c
+Payload = 90c5dd9db0316dac89db18f70491bdf0a06a6a7f72b77d9a
+CT = 98070f3fdcd6942df6ac2488dcb369ffe1fe7abaaa51239d66aed667c761b7dea44822e30cff671f
+
+[Alen = 22]
+
+Key = 671544bf2988056f7f9ccd526861391a27233793a23f811f
+Nonce = 0a259148a1d081e0df381ecd0c
+
+Count = 220
+Adata = 61dafc237cb52f83ab773ba8a885462b6f77d4924611
+Payload = 576b069ae2713f53d2924c1fd68f786cb2eec68892f9e1be
+CT = ce06b3d09b02921f290544032a081a7766612940048867281bb089af0245792c16e6320cf5ffa19e
+
+Count = 221
+Adata = 87e49b8164e7052becfa0c966991637b38df833fc5f7
+Payload = d7eb0d7dd737805cd3b8dbf451aeea2fa1f6a96eb58cb428
+CT = 4e86b837ae442d10282fd3e8ad298834757946a623fd32be3cec29bd5df92363d6bb75456f5cd32b
+
+Count = 222
+Adata = d302a518d7c625756d3e4c8cc2b1d973a19107c945fc
+Payload = 77d8c9e6321314524afd05b7ad599c29f4eedda9e9f0763f
+CT = eeb57cac4b60b91eb16a0dab51defe32206132617f81f0a901ca82cddb78a2fe3904d1d8bf6fe5b2
+
+Count = 223
+Adata = 6566bb616a94bb03df5c26b722bcd38d516285c5f6c1
+Payload = abbf28b3ae164051648293d0b94e11f5af8468450005c7c0
+CT = 32d29df9d765ed1d9f159bcc45c973ee7b0b878d96744156d095ad121f0f76f07b715cad996def52
+
+Count = 224
+Adata = 141be3601e38185a9fa1596d2ee406415c9673af32f5
+Payload = b67d50110f844b36a00d352123012a1123c7c3cba959dc48
+CT = 2f10e55b76f7e67a5b9a3d3ddf86480af7482c033f285ade8529ec8f477462dc2409482c3479756d
+
+Count = 225
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732b
+Payload = 2a63f7b09b43fee65738e8115bd8419b3ef3e8f86eca707f
+CT = b30e42fae23053aaacafe00da75f2380ea7c0730f8bbf6e9b14fe8dbb3c361ea61d7b44e689a1c48
+
+Count = 226
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc
+Payload = 59dad755af92c29522da4348ab9b3037fe87004f5fa1394a
+CT = c0b7621fd6e16fd9d94d4b54571c522c2a08ef87c9d0bfdc54f0659fae291f943f2f3b33688602cb
+
+Count = 227
+Adata = 5d895fb949344e603ce5de029842b20d2bb614ecbbb8
+Payload = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f
+CT = fdb508761d1cdb90977f95f3288015e5c3be88e1745a2f993af4e3a7a20390a8da264299712a34e3
+
+Count = 228
+Adata = 74cc8da150b0bacdefa8943900b4ea047611d96be70a
+Payload = 0c3c9a634a000f00be003846eac7482e303a5bef3a70fe75
+CT = 95512f293373a24c4597305a16402a35e4b5b427ac0178e3a7f79d2b5a9bde5bd453bc8a03e971d8
+
+Count = 229
+Adata = 65f6adbaaa803dbad5ba9cb6d231314d55147cc61399
+Payload = 712c788928c8a1562bc1f3f0eb1286e15c3405f6a6fa0443
+CT = e841cdc351bb0c1ad056fbec1795e4fa88bbea3e308b82d5ffccebfb8c833833db40e98a1950fb70
+
+[Alen = 23]
+
+Key = 90e2c63b6e5394b1aeec03f95a9d13a01a7d4e9d58610786
+Nonce = dada5465eb9b7229807a39e557
+
+Count = 230
+Adata = f5629ca0eea589f6cf963d875a7d2efb656983f2dd2231
+Payload = 44dd098b1f869d670a8a841900c4bef023a1946a0c278354
+CT = 6b38ca85450e05e7b9362ed7e6e291a130ff233b5a561cdef7ec84dd992fdf98514f845dac8f656e
+
+Count = 231
+Adata = d43d7753530a7280b76221906dca85d396b6cf05125018
+Payload = cea19562328bd1fea889f575db6a28a14b7d06fb9f9c98bb
+CT = e144566c6803497e1b355fbb3d4c07f05823b1aac9ed07313613ed15d527d9dc58ab6893e723db58
+
+Count = 232
+Adata = 75650ce366757618af20205b69af7e5d4e82c398c00101
+Payload = f0641f595b791edd860977fcf699688587a354e053e9c7fe
+CT = df81dc5701f1865d35b5dd3210bf47d494fde3b105985874ef8728d1bf3a2d93db3266bafadb7c26
+
+Count = 233
+Adata = c00f1b8066677c63e898fddfb8a1b482b536963da0628d
+Payload = c7486a084f8475e6f5138e8d6e9f42a1de90f05aa88a362d
+CT = e8ada906150ced6646af244388b96df0cdce470bfefba9a7a5bce94d7564d297fe87730f1a36acf4
+
+Count = 234
+Adata = 5a89ab6b26b2ca78f98a8f8409fe8008b97ba9ef185d41
+Payload = 091ef698e16dc43a11d3ea005d5a5cdb7f1bdb5665a6c81e
+CT = 26fb3596bbe55cbaa26f40cebb7c738a6c456c0733d75794cd971b07fc14c512b8df6dd964b129d0
+
+Count = 235
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d3
+Payload = 62f204394b367c4410746001e02dfd171858396568fdd43b
+CT = 4d17c73711bee4c4a3c8cacf060bd2460b068e343e8c4bb1a192b781dc94448d4a0f6a439a716339
+
+Count = 236
+Adata = 4a47a82b999a2a739959f153a091a65c4d7387646da66b
+Payload = ac1cd5ba4997af91dbd74aee7730f9ee92cf8a360ca96a8a
+CT = 83f916b4131f3711686be0209116d6bf81913d675ad8f500cade9533b272e0a3edeba68362b057b4
+
+Count = 237
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab
+Payload = d0a249a97b5f1486721a50d4c4ab3f5d674a0e29925d5bf2
+CT = ff478aa721d78c06c1a6fa1a228d100c7414b978c42cc4785d68df8ff28345be4d83541a72071059
+
+Count = 238
+Adata = 720a9dc3e33ac080775a06f67f4a6591c37d0e101944a0
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664caa7ec8892be6a18458c663665495035
+
+Count = 239
+Adata = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664862fda880e45e891a3a50da7e14344c8
+
+[Alen = 24]
+
+Key = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903e6
+Nonce = f97b532259babac5322e9d9a79
+
+Count = 240
+Adata = ad6622279832502839a82348486d42e9b38626e8f06317c4
+Payload = d7c837971b973f5f651102bf8d032e7dcd10e306739a0d6c
+CT = 4709600418f2839841e6d126359f6982bdb53acc7ff209635623d15b24184481eadc63bb8c878fc4
+
+Count = 241
+Adata = ad4833aa53218949cfd724814a43889a74a2114bbef4cf37
+Payload = 7d672bccd0fb01ce79320ed61779146aa432038daa13cb41
+CT = eda67c5fd39ebd095dc5dd4fafe55395d497da47a67bcf4e614c3e546273f0aeef207bd3f4d32fca
+
+Count = 242
+Adata = 54a723826086c7175e8fdc854b62d780de6ac1f90b57dd3a
+Payload = 0e1b73df74982f535a5fb08bc13d22515ee10969efe033bb
+CT = 9eda244c77fd93947ea8631279a165ae2e44d0a3e38837b413c6395ce9aee2e22ac0606beb140185
+
+Count = 243
+Adata = bec02d7df4cc3deefdd7e7d3ea82d381c870ad46bc06d64f
+Payload = 9a55aff269b180118ff0ea99e851c7474d19d23e641f16a9
+CT = 0a94f8616ad43cd6ab07390050cd80b83dbc0bf4687712a661e4f02150bedd86dfa49f52b214239d
+
+Count = 244
+Adata = 1b8090d712e0ec95a01bc3aeb6f5230c67c355e0ed68043a
+Payload = ff19294e8faed8353dbcab0b146e2ef928dd2680833424bd
+CT = 6fd87edd8ccb64f2194b7892acf269065878ff4a8f5c20b2f0e82b9f04bfc0cc0ba432b5135450c2
+
+Count = 245
+Adata = 5ed0b9f25d07b26717cdcb2507bef9d681ecd9389831ac15
+Payload = db1eba6ac4a79aa1d97838d263c7c4ffa7d354770e762805
+CT = 4bdfedf9c7c22666fd8feb4bdb5b8300d7768dbd021e2c0a2e64c82b60880c5c7506321a1060a481
+
+Count = 246
+Adata = 55f16fefaf2168aebc61b5e01d9e1f7bfe215eaaef118974
+Payload = 012d45168505ca9fde5aed123875639a207d473b993dc7b8
+CT = 91ec128586607658faad3e8b80e9246550d89ef19555c3b77152f64dc993b36ad9d5d12bb52b1ad5
+
+Count = 247
+Adata = 9893bf14fd3a86c418a35c5667e642d5998507e396596c50
+Payload = b205f26d6c8a8d6085ab28d595703cae046f96d82093082b
+CT = 22c4a5fe6fef31a7a15cfb4c2dec7b5174ca4f122cfb0c243e5c69256b6326ebb7ee6e677d396765
+
+Count = 248
+Adata = 244b840085bda9576c8424bb05a925a6b09cad2d0528ab8d
+Payload = 549ba26a299391538b56ce4bd71dbbfd96995836f8915ca5
+CT = c45af5f92af62d94afa11dd26f81fc02e63c81fcf4f958aa2083dac565c7a63908f0022e2867bb68
+
+Count = 249
+Adata = 9e8d492c304cf6ad59102bca0e0b23620338c15fc9ecd1e9
+Payload = 9e9dbd78a1066800ae33253be6104015158a0187e4f38116
+CT = 0e5ceaeba263d4c78ac4f6a25e8c07ea652fd84de89b851968242fe32958ea32e670ae1b3543974f
+
+[Alen = 25]
+
+Key = 90851933d4d3257137984cdb9cba2ca737322dac4dbd64bc
+Nonce = be02df3a840322df8d448c600c
+
+Count = 250
+Adata = 69a9dd9ac8be489c3a3f7f070bdaca10699171f66ab3da9351
+Payload = ba1785a149cb8b69a4e011c11a3ff06f6d7218f525ac81b5
+CT = 89ab2efefa8406336d9e2245199fbc9454f0ef650b9ed0f446c7246bd3130803bf8d703ef5bdf15c
+
+Count = 251
+Adata = 0c39a72f0f38d2713c164b0f870646fc65b9838a322ecfddd0
+Payload = 263dc4fb5cd8798ce0f183a816e51fafba167533dde1bf96
+CT = 15816fa4ef97f4d6298fb02c15455354839482a3f3d3eed7096a6a4422e582c5d02973952ac80e5f
+
+Count = 252
+Adata = 911d9f5c4c34c2f4b69be1e253d43fe729e2ab2622130394b1
+Payload = 7b5da2c283116713f3d80c7907114270964541e03ab80d50
+CT = 48e1099d305eea493aa63ffd04b10e8bafc7b670148a5c115965f6df4332fe7a2cdc4d1b80e28a34
+
+Count = 253
+Adata = 8a961df9c23f6d5ecdafa94c61164a22f460a1bf7415258d39
+Payload = 541a2b3ee25022c92fdc6783a6cbde90680ad3dc41868e5f
+CT = 67a68061511faf93e6a25407a56b926b5188244c6fb4df1e18bed174081b2170ffc6ab53b54c9ddb
+
+Count = 254
+Adata = cac7a248a4d4e96a9733627e247234995d6aa57e491498118a
+Payload = ebb2e893da9f32c363f98bc76fd14eda59e7cc620070f6d3
+CT = d80e43cc69d0bf99aa87b8436c71022160653bf22e42a792bac3d3a2b9ef6d4c8715f9a5c6fe8245
+
+Count = 255
+Adata = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eebd9
+Payload = 199cca0d0e1c70ec405d6816cbddc69f8ada624f2c168891
+CT = 2a206152bd53fdb689235b92c87d8a64b35895df0224d9d07f9610c82fe9a7c78e8f1980e886b446
+
+Count = 256
+Adata = 78b6ed20ed85337c969618bd41917cd85c37e7c35c3a12e25f
+Payload = ca481f557306f9ce386edd0cfde375a550cb5b574be524f7
+CT = f9f4b40ac0497494f110ee88fe43395e6949acc765d775b6aab366637ec41d0bf557f578be424a8b
+
+Count = 257
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc93e7cf
+Payload = 6f1b4ff66d3aec7b0c0d9e202acc52722e15bca0983291e0
+CT = 5ca7e4a9de756121c573ada4296c1e8917974b30b600c0a1e57a5b3ae26469d229425f887ad5a2a1
+
+Count = 258
+Adata = 7f19ac3e53a629a2df1cb56d68fde0c80a46be40a996830e2a
+Payload = 7533c88ce55c2243b64b6c5bd01aed4dd6ac8bb9fd333e06
+CT = 468f63d35613af197f355fdfd3baa1b6ef2e7c29d3016f476ce4fe492062f74bff4c3c0e9ea849a4
+
+Count = 259
+Adata = 0516a69bfd8785ad001367b51e5410b75c11b761be08b9eea5
+Payload = 19ea09a9bfd10db2a74e398859d8f4831fa5749767773acf
+CT = 2a56a2f60c9e80e86e300a0c5a78b8782627830749456b8ead47ffc17b871f530f62b9f9aec98509
+
+[Alen = 26]
+
+Key = 5c5d02c93faa74a848e5046fc52f236049e28cd8096dcac6
+Nonce = 54cbf2889437673b8875a0f567
+
+Count = 260
+Adata = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce33bb
+Payload = b4da43ebfe9396b68f4689fba8837c68d0064841c6ddd4a7
+CT = d40725397229021a18f3481e3a85f70445557bb2a85e4ae8101a34c777e918e16186fda05a386572
+
+Count = 261
+Adata = 10f0c45d06a138a964fb11b2d450620a2977bcd2952afe371cad
+Payload = 7b628930d44e22907277db057395601b82b65479fbd59613
+CT = 1bbfefe258f4b63ce5c21ae0e193eb7717e5678a9556085cc1e79234882846d916dabae40b1bd055
+
+Count = 262
+Adata = 64dbb170a037b36beed28a2637c87830e2b23f8eea6cd9a7331c
+Payload = 9db30b669fc5d25f05e0dc708d597da6ddce2dacc85ae99c
+CT = fd6e6db4137f46f392551d951f5ff6ca489d1e5fa6d977d3e35499e3c09dc384eb41344ee8be3769
+
+Count = 263
+Adata = c47de6608546a02c6eebd6628c9123f6936c0154d3df52a367e5
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 02de0a6c5fdcf929f5f8fc2c53f2bc29dec98633526340ddd605189608ce40b237dde7bed6fde487
+
+Count = 264
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb7
+Payload = 5c9bc739f6b6fe4214f3c6aad307d1f208892d79de010e37
+CT = 3c46a1eb7a0c6aee8346074f41015a9e9dda1e8ab0829078c31f69c847440be20bd08cfef330002f
+
+Count = 265
+Adata = 8a9716135fa38c250e249f6712f7cb3ad9210d7278b53d599df9
+Payload = 0df109298083d3896214b84ff6edb11e9cfdbd88f5702839
+CT = 6d2c6ffb0c394725f5a179aa64eb3a7209ae8e7b9bf3b676ca83622b127fa50fc9637998c0ddd44d
+
+Count = 266
+Adata = 2d52447d1244d2ebc28650e7b05654bad35b3a68eedc7f851530
+Payload = 518f651f6d82f670b63767ad8476ed8fc24df12a45110611
+CT = 315203cde13862dc2182a648167066e3571ec2d92b92985e81e738b9e4b0dc7b7a39eb7d03adc64a
+
+Count = 267
+Adata = 3cba0fd2bb16ae1d997cbe659a2dd101885c97f2322b0172b5d6
+Payload = e91a694bea2d351928b6098660d49f382c087f6777de159c
+CT = 89c70f996697a1b5bf03c863f2d21454b95b4c94195d8bd3d298c05b1d2e597f44f8621ecd11ed16
+
+Count = 268
+Adata = c7f93152016bba584dadc6002ec493a46305726068886d2340da
+Payload = 2d14792ed349a878b2b879e7fa5f438a50e36947ce827e73
+CT = 4dc91ffc5ff33cd4250db8026859c8e6c5b05ab4a001e03c5fd5221fceecbf0dc7211a1aec06793a
+
+Count = 269
+Adata = 799cac048eaccded37ca6a70dd89595e1ee04606212da5572679
+Payload = 315b8d95938d304015bbc94ea03c21f6dc25c90f991ba680
+CT = 5186eb471f37a4ec820e08ab323aaa9a4976fafcf79838cf5c25f00b862b49fcfe8447949f39787c
+
+[Alen = 27]
+
+Key = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+Nonce = 16d345606a315ad2406abbcb43
+
+Count = 270
+Adata = c37fdf7449fd7e943595d75e977089c623be0a3926e63fdbbfdf4a
+Payload = 0f960a89a7e806f8709047cb7a2e7c4211ad724692c88a05
+CT = 3907880d25f910eab12dd14e704d1b33ea7c453634d54da2a461f44dac1112ae3f9c65671a931d3e
+
+Count = 271
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb99
+Payload = ab40a4baa39b0e568bf2193fecbc36b84c76bb50523b2912
+CT = 9dd1263e218a18444a4f8fbae6df51c9b7a78c20f426eeb5ed15db6e142ee07b59eb5b0ad3a59194
+
+Count = 272
+Adata = 79ae14843b2e7ccf0fd85218184f7844fbb35e934476841b056b3a
+Payload = b74c06d9077c568762796d5be14f3563e7205a6e9bc65bcb
+CT = 81dd845d856d4095a3c4fbdeeb2c52121cf16d1e3ddb9c6c203f11f66b74366caeca8dbded2bf17a
+
+Count = 273
+Adata = 542d86fd7ff591f97e6926a090553538bc3b8a6bcd45f2e29c7d9f
+Payload = f2179beb5635a6d8a8340acea0ffcf4428e5de1306a8c12b
+CT = c486196fd424b0ca69899c4baa9ca835d334e963a0b5068ced925fb9a4cf6b6bf17f72ab044653d1
+
+Count = 274
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a4
+Payload = d1a9e4593bc3d02c407e84a1736e587c1819c72195a07d57
+CT = e73866ddb9d2c63e81c31224790d3f0de3c8f05133bdbaf0d1f677deca1bfda83c1b9223aaaedbfc
+
+Count = 275
+Adata = 966954582e78e99ba68d6ffaf794b55a82325834ec4f373b2bd227
+Payload = 15b94910853a8f23dfb8b31c0262b8461f777075cc0937e9
+CT = 2328cb94072b99311e0525990801df37e4a647056a14f04e12937871932a7ca3e1e27a90a7f73694
+
+Count = 276
+Adata = b7aca715dcc402565cb711b001f21e8e95ec54c4afab2e2dcc8a2f
+Payload = fd1681cc306518bf77766f55226afac3eb21e31ed897075c
+CT = cb870348b2740eadb6cbf9d028099db210f0d46e7e8ac0fba0464ff4ddeccbd523a5ed3b32337f7c
+
+Count = 277
+Adata = 290a36f7daeeeafca4431446b396dbec0bea0a1f6f081418811656
+Payload = 0804fa48fc76f98bb021e3501bef8875b64a3b508adf8594
+CT = 3e9578cc7e67ef99719c75d5118cef044d9b0c202cc242332f68ed5e44a71c5ba8bade07b7bf5495
+
+Count = 278
+Adata = f0739a855422310a21ed863376bce9d75dc7c687b9b535cb7a05cc
+Payload = 4f5c6d80a3955f12f4d2594e02a045c42fabb11d90817fff
+CT = 79cdef0421844900356fcfcb08c322b5d47a866d369cb8583b5dc1fbe32743e257b7c1c9d624adc8
+
+Count = 279
+Adata = ffac0edb0b62977bb5040e4128a48deaf711f5e6a84d8f677341f3
+Payload = 5c29c458212d010a0d9c5a547aba1138eb4ce94742fef01e
+CT = 6ab846dca33c1718cc21ccd170d97649109dde37e4e337b9e53b654de1976294897cae0476ac6248
+
+[Alen = 28]
+
+Key = 6351a67fd6daabd2fd49ee944dd41dd37301f958dd17fcc3
+Nonce = b8d517b033754058128d13d11a
+
+Count = 280
+Adata = 511c6924fa96db716f6b053b7a48aebdc1504145a56cd02d6be2590d
+Payload = 0c0663dd69ccbffbbd0c8c2e9473d0354451ae7a20fa3695
+CT = 19f2745df5007619c79c84d174e4521b942776478a0601d982c560fede4741e2fd3b54b3a48f3e38
+
+Count = 281
+Adata = d9ccd93317441e9d6ccc358f31e7e2ccef8c921b23d742993eff9d53
+Payload = 34a882834172924d39d2df5d637d9d273a99a9222971701c
+CT = 215c9503ddbe5baf4342d7a283ea1f09eaef711f838d4750ee82d927a2aa678e792acdeb615409f8
+
+Count = 282
+Adata = c268d65f7a7b30d3d198b2045fc8d1db7adda56604fa567d8855d1a5
+Payload = 5b7450b73d68de079e92bba56c7860f11126b8fdedd3334d
+CT = 4e804737a1a417e5e402b35a8cefe2dfc15060c0472f04017a48226389d24ed3ec3da2da1a9bdf7c
+
+Count = 283
+Adata = 4c2b6815156f0643b4573825e28b9f2a668a4976e3342884f48bc310
+Payload = 140c6933248f052e05bd4a36aec185ee86730108cc2989b6
+CT = 01f87eb3b843cccc7f2d42c94e5607c05605d93566d5befa16fe6bd83993ccbdd50e1ca061f4845f
+
+Count = 284
+Adata = f11c873354b3c0cff2c8f8010e9e364582b9c05c62efdefbdcc2e1c0
+Payload = 2a083de317380d94dd991349a7b8761c7c98013b1b0227e0
+CT = 3ffc2a638bf4c476a7091bb6472ff432aceed906b1fe10ac577c5893cb3896400012e48f5b190b73
+
+Count = 285
+Adata = d0a056754098d7f7ef2f639d61ea3d2b9cc936c48a1b2c5a9e96d169
+Payload = 02769283d5a06c363c2cc66c09b1ac954134e3ec7df773f2
+CT = 17828503496ca5d446bcce93e9262ebb91423bd1d70b44be80c80101fdfe6dc4cfce080bf921582e
+
+Count = 286
+Adata = 56de0e55653b9a04a3ded71c31f8807c3c8dd96bc82892e4acccef30
+Payload = 4890404bc5b24822b4cf7a2fe28abc52fbefb919ae0629ec
+CT = 5d6457cb597e81c0ce5f72d0021d3e7c2b99612404fa1ea0122dfc20e3088dcd33b6706a0c1fdfa8
+
+Count = 287
+Adata = 794a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b425
+Payload = 161f8501f59338f72026815c77cad6d8d581859192cd5644
+CT = 03eb9281695ff1155ab689a3975d54f605f75dac3831610828f0a78ce798448529afe26eec875aa6
+
+Count = 288
+Adata = b1eafc03ea2fa3e9e3842a09a225e83055de8a1f412badd6fc9ead12
+Payload = b3f38aedbf08dd7ead9d402c5aaa1ec9279c7e4bfd4a2967
+CT = a6079d6d23c4149cd70d48d3ba3d9ce7f7eaa67657b61e2ba48856a266c0d404474316f418f8f4e4
+
+Count = 289
+Adata = 8fec99f1be0e69267620c0b934bf984d60c1437f74c6ac19610fe188
+Payload = 5c09e2a6a055fe9c21e06e5519cf56b8e2e7fb44094e79f9
+CT = 49fdf5263c99377e5b7066aaf958d49632912379a3b24eb56412292d8015285efaa6f1154580eb57
+
+[Alen = 29]
+
+Key = 9a5a9560baed3b8e0e90b92655d4e5f33889e5d7253d9f6c
+Nonce = c0049382cdd8646756d4e6bff5
+
+Count = 290
+Adata = c95a86d52088a8b0107cc5b437a8938b2c9e74e46e2e03bb9bceecdbe3
+Payload = 5bbe9c1fb2563e3e82999fe097b28da4dc6ff2e020f3b4f3
+CT = 6d5401db42b5c48b79203b6ad82806d7460ac4c82ad0809b811020480e834f6fe55900a162a4e61a
+
+Count = 291
+Adata = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193dfa755a5943
+Payload = 8a85a9b32a323c6af156a3fa2f1448b6387cc3660aa8a0f4
+CT = bc6f3477dad1c6df0aef0770608ec3c5a219f54e008b949cba9827513c7f1de970d316b6f81c109d
+
+Count = 292
+Adata = c834096e059ea73ddc90b0c982f9a3a31bfc6b1b81a03f9d41c9c741e7
+Payload = 1e02c13104937fe084b18eba1ea8951dcc5e75b692937dea
+CT = 28e85cf5f47085557f082a3051321e6e563b439e98b04982c9d79dd3255a8323f8229ac1c6d76ae4
+
+Count = 293
+Adata = 9249022bdead3d86ef5bd03acf053132d08663ba1f2426e19c126b22e9
+Payload = 3225570fb15ae13a13c71e364ae9a9fef03d1c9a7fa5dfa0
+CT = 04cfcacb41b91b8fe87ebabc0573228d6a582ab27586ebc8425dc81f93257ae8399fc2d48b4a7685
+
+Count = 294
+Adata = 3c3a92c4ece49fb9f84243d7c1bc91f595fce118305a758c83985c34b4
+Payload = fa0a458174537ddba25708b8d0c22d5517d57b122517b0c9
+CT = cce0d84584b0876e59eeac329f58a6268db04d3a2f3484a1b595003c58e69600c2a3b9ec45c0e15a
+
+Count = 295
+Adata = b49b845ccf76acf508f9db8543c73375d530d91f3b0e4ed70decfd2c2d
+Payload = b7fbdaeaa3ee1d0bbf5ec47898b069ec4ba6a140a3e83996
+CT = 8111472e530de7be44e760f2d72ae29fd1c39768a9cb0dfe0da009261c43c6640303696655e2981f
+
+Count = 296
+Adata = 3aabdf589eeb1709bb3d60b08bc71eaa3ffeba4e2903a5dbd8339aae85
+Payload = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7e
+CT = ac001b7d0b3a47f0ff578aaf4ad3c9c0a759edf04836ef16dfdcdbd4ad711c493d3176f032a02af0
+
+Count = 297
+Adata = 6a79879cd62bd1dbf9609897d2ebf2dc4dda43cc15fcb241aaa0deb4b3
+Payload = 3a861638ccd6591e51e2a525be59447e4a28bab32e36a5f3
+CT = 0c6c8bfc3c35a3abaa5b01aff1c3cf0dd04d8c9b2415919bfd59b45c05873c670f5f8bb47732d59f
+
+Count = 298
+Adata = c5b6ca474eb251817ae4d2f47c0632c381e222aae3b6f585a0dcae120a
+Payload = c7da4e9ba6e5758be726e6e227d7bddb0332228f7e3ecb6b
+CT = f130d35f56068f3e1c9f4268684d36a8995714a7741dff031572a24bc00b40a6b4b172b3648142e7
+
+Count = 299
+Adata = 64a96d191f1d5f95f5fed6259e33e7206adc07b0279e16cb453a9c6438
+Payload = 2b9347d3e195152dce22afdb92acd179eb484872285704c3
+CT = 1d79da171176ef98359b0b51dd365a0a712d7e5a227430ab828bc33396179ac39ce0027a1d62e0fe
+
+[Alen = 30]
+
+Key = 3e61094c80df0053e86d43fccf4e1d3ee2cdb862d3237b0a
+Nonce = 63f00b2488809fdc49ca5f05d5
+
+Count = 300
+Adata = a08763ca936abdeece06467bef8c3c47c3a473636a039d4db540c867d3e3
+Payload = 1fada8f4c7daea0d1c370184c169485b80a278708ed41451
+CT = 680dd22f16a1290bde42c9792dfa997aed24d5bd2265b6e095aa6b99d3f894d3790c2aa2dae1ba2c
+
+Count = 301
+Adata = 19508a6c83b992c660a1a28597e07c729ea2ed39401aadbf9d7586b5720d
+Payload = e9f1f2cf0b8d563e2d20f39f9f464a808b136dba364a6446
+CT = 9e518814daf69538ef553b6273d59ba1e695c0779afbc6f72d9d77109f4597e9c4c8cf7023dc5f3b
+
+Count = 302
+Adata = e5929c3b5d68a4c9fcf1168ea35bf8c0bf3043cb1ed54ff301578b3b7266
+Payload = 07a74c3b874849ecbf013713b80a84337c90b690cea0b837
+CT = 700736e056338aea7d74ffee5499551211161b5d62111a86b2544ecc3c7d5accd22ac075e7b44d5a
+
+Count = 303
+Adata = caa5cc5d0d87680eafc29429bac55c9e33167d485789c7c124b5c57a1ba8
+Payload = 4255f2cf90f0d15e9bead4be799165c57f7225980713d609
+CT = 35f58814418b1258599f1c439502b4e412f48855aba274b8f1a8a1db25de0fab7cabb11a18497584
+
+Count = 304
+Adata = f61cf7ae23a66777bd3fabc3d542feed2b00c6d4f46a772fda11b5214551
+Payload = 70b1e2e4cf260b108f5a52d0d8234838ffd6ffe7b4acd78d
+CT = 0711983f1e5dc8164d2f9a2d34b099199250522a181d753c5a9718ed0257a50e38de86154054fc3a
+
+Count = 305
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb993e86f4
+Payload = af4be10b3a59ea99dadc75fbe5651f6f7630852bb556aa39
+CT = d8eb9bd0eb22299f18a9bd0609f6ce4e1bb628e619e70888550d1acca34c28ba8a3b890bb0542b23
+
+Count = 306
+Adata = 296cd04c4d9ab493def7aeb6841a45309e777028868efe45166235c56b2d
+Payload = 72d5663727592f1bfc9c65be83f4d3508126fecc4e34ae72
+CT = 05751cecf622ec1d3ee9ad436f670271eca05301e2850cc3a268dc1596a7855639c63fa76ad8479b
+
+Count = 307
+Adata = f380ca0a26a94adcf2c1ce26d226d3bf520268c72412e58a71acd9a66d00
+Payload = 3e2ccce03c10ce1527ef8e002adb265edba5779fbd4fcaf6
+CT = 498cb63bed6b0d13e59a46fdc648f77fb623da5211fe6847e3416c75fc28924a21cc123e62a7894c
+
+Count = 308
+Adata = 8825532a31680cb3b5bdb027802d2d8718755e135367e0c8c88e21288311
+Payload = a18dfe7f2d7bbaf316366f67445170afcbe18e2a1de1e947
+CT = d62d84a4fc0079f5d443a79aa8c2a18ea66723e7b1504bf6ff1a47f23d08485951aab18b393584ef
+
+Count = 309
+Adata = f768375589b687fb17c56673af4263626da69eb991007d94d4f5a163fd05
+Payload = 17ca72a440c944fefd6c08ecc3a8ecb54d96b9cad9d2aa4c
+CT = 606a087f91b287f83f19c0112f3b3d9420101407756308fd7d024456bcb69a4f77008773a3f48805
+
+[Alen = 31]
+
+Key = b5664dd6ed435df006052f6ded74bb7ce9482ca9229886f7
+Nonce = 7a1649896f3e030c18f0205599
+
+Count = 310
+Adata = c5f1a26351e53e6509c8bbbed03c42c23ad81c65fccec7ffa1cb494c7f1fc4
+Payload = 0b6de49b530703affc94010c2b793ddc6de0c44d48037ff2
+CT = 56b02fea595cc24e798691ae905be3d466ca68ca744005dba260b5ea3b047020b73b5bafa17e5084
+
+Count = 311
+Adata = 89899be18b4c389afa769b11ecd22e9fad8f38fd614ea5f8eb7a066c0ed8d8
+Payload = 2f1821aa57e5278ffd33c17d46615b77363149dbc9847041
+CT = 72c5eadb5dbee66e782151dffd43857f3d1be55cf5c70a685e4bd97b9dc83134867c00c2acea0aaf
+
+Count = 312
+Adata = d43b841f174335f1347834590b0984a2cb35f7a00a0ee993157d2d4f848748
+Payload = c7da4e95cb38342c6d5bf0c381d5a192adc3bfc1cda3a1d7
+CT = 9a0785e4c163f5cde84960613af77f9aa6e91346f1e0dbfe55202ba34bb9918fe915776de65947c0
+
+Count = 313
+Adata = c1093518efd80245e3c42371f220b21f2034e6738fe02ef43e828190f01aef
+Payload = 414a70aba5a219dbd41cdc46b84812b28cc4f7399218004d
+CT = 1c97bbdaaff9d83a510e4ce4036accba87ee5bbeae5b7a642fdf807b5a6880f2d4c36d558b40eb90
+
+Count = 314
+Adata = 90f627d5b939625bc76fe1bd4643b39edc11d3dc7f4bfe16e61bc26c3d49d8
+Payload = 58b260d3f645a35bad7a3842440bc03608248bd46e725e60
+CT = 056faba2fc1e62ba2868a8e0ff291e3e030e2753523124495a9307ca4239380a45bb7f87e41c4cf7
+
+Count = 315
+Adata = 2f360a4715074e942244ab7f9b6db127b0442df9af2efa2e78db1a94312905
+Payload = 5505caa97218957e90247fde60275bdafce4b16bcb36c263
+CT = 08d801d87843549f1536ef7cdb0585d2f7ce1decf775b84af3aeadff9dd60468aef2a8e2c56dda7d
+
+Count = 316
+Adata = 7db564811f14bc5c2098d5635655c3671fbd8288ea14944af925eaec653408
+Payload = b93e40f556a786e39126b8834a6ecacd2dc9f0f528bab135
+CT = e4e38b845cfc470214342821f14c14c526e35c7214f9cb1c8335f2e31a0468b830c5009cd02dbd5f
+
+Count = 317
+Adata = 36be91854d3d02a5d62503bb9047ef4354280510f7576c4272fd757240b621
+Payload = 543a070fdb3a855dd7d83fbc5f983671ad9e905f307148e4
+CT = 09e7cc7ed16144bc52caaf1ee4bae879a6b43cd80c3232cd5d772a599e91504e022b9dbfb124b71a
+
+Count = 318
+Adata = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb8813ccc2f2dd96
+Payload = 86ef67572cb339c6706eb5909b96848aba5246a196972a1e
+CT = db32ac2626e8f827f57c253220b45a82b178ea26aad450379846cd12430f7adc910d1f0c51d80636
+
+Count = 319
+Adata = 3a64414c3588d7c26871d7d054ac6c8420d4917e3baad4a343685916265321
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 9313393a683cabb7a6ac4a4ab359450ddcc887c69d0ea8fcd9ee65ac3a8fae1b00a4f1dfe2577293
+
+[Alen = 32]
+
+Key = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+Nonce = 809343e986f6ff47f54d4cac22
+
+Count = 320
+Adata = d70aef3532bdc5293a3ebb11589ac1f801c9f93ea0d656e1d04068facf9f768b
+Payload = 718f061e8b972a3adcf465d66c5b28e8661f080127f6722f
+CT = bad3b0e6772e9c4c9c631c095e259d99692292932efb72b8966e91a19617bb748f3495aa433585bb
+
+Count = 321
+Adata = 1ee0eb409398bc252175cb460ef9a2da4c9beab2ef6d8206e4fcce74df785246
+Payload = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+CT = b9ba78455331962a0ee33b5956c2b80fbb55e0b52b1ab75dc8f70aa565a12ca3545e68110968040f
+
+Count = 322
+Adata = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698b0ed5c8cb09a8c96
+Payload = d959dd38a458039e2400d21d27b9a2faee8fe23683330cb5
+CT = 12056bc058e1b5e86497abc215c7178be1b278a48a3e0c22daf38076c810e14a7843444a02f010e0
+
+Count = 323
+Adata = f555216840a1f40b411d44128e567617e2694caf16216ea74c604a8d6ec01e72
+Payload = 337f12e8ebc0544b82fcdd3c4a0dab0e5e75c9f433a27d66
+CT = f823a4101779e23dc26ba4e378731e7f514853663aaf7df1594aebf9b8318877bdec2900a22df858
+
+Count = 324
+Adata = 2311a6fe1feeda3a1f16310d635496c0dd662024f0b0f1de79325e030cb850e5
+Payload = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb4
+CT = 8d60d302875518204538f90eccb4ec7651d51698b6ca2c231d9872d1c10a6594b5c349b84f710d64
+
+Count = 325
+Adata = b2c633e3181ae5fe7828707ed5b70e0460088a84465eadeecdbcfa0e9ff19bb1
+Payload = 23c1732959c4bf85bc707e45cc964b6227acd3a8fc73e675
+CT = e89dc5d1a57d09f3fce7079afee8fe132891493af57ee6e2a9db7c4bcaf6087e158c1a5d4eb1c2cc
+
+Count = 326
+Adata = 791f23252094b9b99fafe7fac1d8ff3ba09305c476041e75afb245ac438b4069
+Payload = 02f60f967e7fbcf957313619882407ea8a03fc943062296c
+CT = c9aab96e82c60a8f17a64fc6ba5ab29b853e6606396f29fb5e1c87d9e1c1f3b7d30fdc2f0ccac783
+
+Count = 327
+Adata = 22197f9ad14591e7a6d5f8b18c969a553de9a85309757fa5d319cc505c24f438
+Payload = 6c1aa088d1a6086d0e72636744a6840c80ab8223409c61b7
+CT = a74616702d1fbe1b4ee51ab876d8317d8f9618b1499161201514b449a741e07f9287f7e9090fa54b
+
+Count = 328
+Adata = 0bb18f7280a30767cd769cb5ffd3edd1c18914b92d1b2192e27ac88f57135616
+Payload = 57275bc3b4d63b9b01b0b0760235c9785d45761cace23f1e
+CT = 9c7bed3b486f8ded4127c9a9304b7c095278ec8ea5ef3f892c889b610157e16e9f31558c669298a7
+
+Count = 329
+Adata = 3e5f0f32e27be18ca6f84de11e6e9c25fc0c4cb0cf83633eea1f033aa1373f3c
+Payload = eba27a27f0d4604a5296a41b3fe995c50c66bcba302d0447
+CT = 20feccdf0c6dd63c1201ddc40d9720b4035b2628392004d0fbe19321dc22c748a17aa5eda29d8cf3
diff --git a/lib/crypto/test/crypto_SUITE_data/VADT256.rsp b/lib/crypto/test/crypto_SUITE_data/VADT256.rsp
new file mode 100644
index 0000000000..af4f5c1df7
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VADT256.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886df3ba3e6da3a1389
+Nonce = 72a60f345a1978fb40f28a2fa4
+
+Count = 0
+Adata = 00
+Payload = 30d56ff2a25b83fee791110fcaea48e41db7c7f098a81000
+CT = 55f068c0bbba8b598013dd1841fd740fda2902322148ab5e935753e601b79db4ae730b6ae3500731
+
+Count = 1
+Adata = 00
+Payload = e44b4307234281209bd41f89dbe2cc3fbf68e14df2f7fce4
+CT = 816e44353aa38987fc56d39e50f5f0d478f6248f4b1747ba003abc6a4b020625adc8b6cd7bafbd42
+
+Count = 2
+Adata = 00
+Payload = 8db7a73856bcb4007346bb3e00096f69e75e97c0bb960f3b
+CT = e892a00a4f5dbca714c477298b1e538220c052020276b465e7cfa7a208a8b3e6b6377236045df17d
+
+Count = 3
+Adata = 00
+Payload = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e676d44
+CT = 2dd6c9e8563298008cba3be237c67ffb68f59f97c787d61a81b39a0c55822e32042b4f8981021090
+
+Count = 4
+Adata = 00
+Payload = 7cdb2c9b167b3ae811289acf7dc1814bbe241f553447699f
+CT = 19fe2ba90f9a324f76aa56d8f6d6bda079bada978da7d2c1091117e2ad77db510d902038743b5a98
+
+Count = 5
+Adata = 00
+Payload = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eeb
+CT = 24cfc842c9bb65abbc5ff4e61cb2156c19663821c6d395b5ac7379b8e51592b98e4874f4592278a8
+
+Count = 6
+Adata = 00
+Payload = bde9e3eb9f0c57302c9185b1cb912ef76d88f2f9c3b51e9a
+CT = d8cce4d986ed5f974b1349a64086121caa16373b7a55a5c4d08c1c902c4c2f078452dd6943b85028
+
+Count = 7
+Adata = 00
+Payload = 6f9ccc033c6bfbdfad4719ad033c927e2175727a9a021dc6
+CT = 0ab9cb31258af378cac5d5ba882bae95e6ebb7b823e2a69832fefb87445f1ca42811899acc0cdf68
+
+Count = 8
+Adata = 00
+Payload = cc67bc3b7afd625b2610226d3b30e111e6aa47a3254f711a
+CT = a942bb09631c6afc4192ee7ab027ddfa213482619cafca4481d605a1019c8e9778b8928b4636053e
+
+Count = 9
+Adata = 00
+Payload = a10c81725f49ab9075fbf4d96be030a2d881d8501b115d61
+CT = c429864046a8a337127938cee0f70c491f1f1d92a2f1e63f96a82e8411e5b04426dc608298c6408d
+
+[Alen = 1]
+
+Key = a4490ed6ab51dbfccd6f3702a857575dad44da3a27eaf31178abc97da60d1e4b
+Nonce = 26ceaf6e3b28190a17c4f0c378
+
+Count = 10
+Adata = 9e
+Payload = 1b5cc6b1651dec4bbbf5130343852e971c7ff1774100d9be
+CT = 789bce069a725a96c484e64a9e54dcb7a7c268c85df47815a462ff2dd8ba44a381e1f6edab12b5a9
+
+Count = 11
+Adata = 4e
+Payload = e7ab98901c0cb1d7d76e125d8ac8e86edf6f469fa937bc10
+CT = 846c9027e363070aa81fe71457191a4e64d2df20b5c31dbb6b0789c5866b7e3312ad992e228d6d20
+
+Count = 12
+Adata = cc
+Payload = 53bc7e3648d0b389b887b065e9e8f79685beb2eb36e2eb95
+CT = 307b7681b7bf0554c7f6452c343905b63e032b542a164a3e39b1b1a480fdd268c1c75b131cde798b
+
+Count = 13
+Adata = 45
+Payload = 6d7262476da95db63b322c5193ea05030923c3cbf0f8e8b1
+CT = 0eb56af092c6eb6b4443d9184e3bf723b29e5a74ec0c491a32060fea35c3e9528fd18994fae9fce8
+
+Count = 14
+Adata = 2c
+Payload = 8246bf7b81b287411777df7ecb53a1795e54b150ff3dd584
+CT = e181b7cc7edd319c68062a3716825359e5e928efe3c9742fb4e0a604ab30a764e8c98a9cafbca8d4
+
+Count = 15
+Adata = a9
+Payload = 2596ca8772bc69b50bcbf33088c6efbab614b691ed836f92
+CT = 4651c2308dd3df6874ba067955171d9a0da92f2ef177ce397ca72f1acf6dfd078b6f4eb82fa01e9b
+
+Count = 16
+Adata = 85
+Payload = 703065d701f4fcadee20d64300b3082c0c76490eb2dc4ba7
+CT = 13f76d60fe9b4a709151230add62fa0cb7cbd0b1ae28ea0c2a85c9252ee62612dc29cffa7289b2ca
+
+Count = 17
+Adata = dc
+Payload = a1aeda4b4cb8dd2943675181561bac48ba07e8de5b327837
+CT = c269d2fcb3d76bf43c16a4c88bca5e6801ba716147c6d99c9fbdac729413152c089d3939e30b8602
+
+Count = 18
+Adata = ce
+Payload = aa17341f4cead054d41c171dd34c459f7052da225c6c365d
+CT = c9d03ca8b3856689ab6de2540e9db7bfcbef439d409897f6f86266c273f8184e901b50c04845b8ab
+
+Count = 19
+Adata = a6
+Payload = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f
+CT = 274bd52b4497d536191e2f7f65f40159339a43830fbdc0b4ddd02d5c9ae2bbac47a7a076edb1d207
+
+[Alen = 2]
+
+Key = df594db94ef8eca56a417afe946085eaed444c7cc648d07d58132e6cb5bc2bc3
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+
+Count = 20
+Adata = c0c3
+Payload = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259
+CT = bea778540a90033b2c0d087e3cc447711ea25f7eea96855506ec97f23bd6ea97834f92f7263c3195
+
+Count = 21
+Adata = 34b9
+Payload = f6c043c70136585d012ae0df6f42b25584e374649d0116c5
+CT = bcb0ac1ca69079500eeb5d1a4b21c21820cb45216b0581c9f3230df0b52b5cb7ac907dcadcb662ca
+
+Count = 22
+Adata = d4ab
+Payload = dec0c896b04490816409da1783478ef2510231d0a28c5b39
+CT = 94b0274d17e2b18c6bc867d2a724febff52a00955488cc35a99c3165ce83102891ef3885088ed6eb
+
+Count = 23
+Adata = 2a3a
+Payload = cbfd94fc31785d30214271dab2264134805fee6e52aa0b5c
+CT = 818d7b2796de7c3d2e83cc1f964531792477df2ba4ae9c50c9d8078607994ae5dff0de6526fb53d1
+
+Count = 24
+Adata = 4eb1
+Payload = 134d2d9726400d09dd3521326f96fbef993ddc0c40887700
+CT = 593dc24c81e62c04d2f49cf74bf58ba23d15ed49b68ce00c7e84da7d2564533e7ad55390ec3a6ff9
+
+Count = 25
+Adata = 0a79
+Payload = 1ccdcf789d42caba80d7893feaf26d3853fbcaf7d964df0b
+CT = 56bd20a33ae4ebb78f1634face911d75f7d3fbb22f604807520849295a56191367a696999ffef8e9
+
+Count = 26
+Adata = 865f
+Payload = 4042dbe148db3e6dc542b25d57a5787af535d38e8c34c71b
+CT = 0a32343aef7d1f60ca830f9873c60837511de2cb7a305017bc4aceed1a10309b6402b9e9420b33a3
+
+Count = 27
+Adata = f4ae
+Payload = 85b6894fec36294aa934cdc3523fd95c90ad56cbd18545dd
+CT = cfc666944b900847a6f57006765ca9113485678e2781d2d176c180d2e299ccf0b8781ba6de8a72ce
+
+Count = 28
+Adata = 10bf
+Payload = 0f27f4fc8538a676a763b3e5db845a1bfb20d5fab340dee3
+CT = 45571b27229e877ba8a20e20ffe72a565f08e4bf454449ef98d91c68d94873a5d6557611a5402a0a
+
+Count = 29
+Adata = b92e
+Payload = 1b5ec0cb03810a12fc6a0a1ff565afb001405d2a45a1f18a
+CT = 512e2f10a4272b1ff3abb7dad106dffda5686c6fb3a566865321cedf1122354636e130acbd69718b
+
+[Alen = 3]
+
+Key = d98193ab2a465e3fcd85651aaeca18b8e91489b73b7c7e93b518c4b5b81fc6ac
+Nonce = 2247dc7e2674e9e0a63fe70613
+
+Count = 30
+Adata = 4dc2f4
+Payload = edba7d6312144e90ec9eaace7576045a46e553dcb8ee5a98
+CT = 44b9ea727c847336fd739ad11f4b906b292edb810462f06ef59626ad5cdac2e4d4cb07b538a1fd8f
+
+Count = 31
+Adata = 2f3bf0
+Payload = 52a9626f5279c11e17e96f5dc5e1c1f58c1e913020d8499b
+CT = fbaaf57e3ce9fcb806045f42afdc55c4e3d5196d9c54e36ded0d53402253453e494ad350994ca77a
+
+Count = 32
+Adata = 95d2cf
+Payload = 87b6447d97a74d0b315031078aa06fffc7b9f246bfa5f147
+CT = 2eb5d36cf93770ad20bd0118e09dfbcea8727a1b03295bb196dbc3bff865a1d94b164df23d708e8e
+
+Count = 33
+Adata = 0caba9
+Payload = 1852848046706f2e274ba381a2bee1422df4f61d93219af7
+CT = b151139128e0528836a6939ec8837573423f7e402fad3001791b4469fe50d45f8efb81217cd68580
+
+Count = 34
+Adata = f8d459
+Payload = 99aac82fa66a15e4f76b76cf4590150999d5cf8468df7f42
+CT = 30a95f3ec8fa2842e68646d02fad8138f61e47d9d453d5b4587106da25012f92f01cc2db8d11ac29
+
+Count = 35
+Adata = e883dd
+Payload = 4e2f0f91990b855a00d27fbb2e8db7184cd82909de361b52
+CT = e72c9880f79bb8fc113f4fa444b023292313a15462bab1a464148536847290e4fdda7966fe6d5e3b
+
+Count = 36
+Adata = e45da4
+Payload = e558be3fd246170b294d18ffa708842242681890baf8bed9
+CT = 4c5b292ebcd62aad38a028e0cd3510132da390cd0674142fcc4cb33472825363940e2b26424b7802
+
+Count = 37
+Adata = 3b6fc8
+Payload = f8b284c2d851289275973fcd807fac5d8e5e3b6a75ba2ace
+CT = 51b113d3b6c11534647a0fd2ea42386ce195b337c9368038a99dd8dbe89b3ecf663eda1b0f92be7f
+
+Count = 38
+Adata = 043d68
+Payload = 8edf1eb90f0ad33be8a7c6446899e06addc10b3badc4ea25
+CT = 27dc89a8619aee9df94af65b02a4745bb20a8366114840d3dc4894c8fa0a1e1aa760acf9360042f5
+
+Count = 39
+Adata = e89257
+Payload = 8fe9a6bd82462c97f436d382d1ff971c95406b1a6c847d81
+CT = 26ea31acecd61131e5dbe39dbbc2032dfa8be347d008d777cdad1590fd8bf2d7ea919e60d0316566
+
+[Alen = 4]
+
+Key = 45c8afd7373cb0f6b092af3a633d9fd97c4ca378e19d75f9b74d089429726c29
+Nonce = fdb1fa230ae0b172ff98fc7496
+
+Count = 40
+Adata = 270981af
+Payload = 0b92adbb251dc29a67f0bb97f8e7160862b6c4e843d07fd9
+CT = 274e2faea3271ea6fa0494c1951f115b5491a893056c3ee4c76fc350e585277e373e9119bf9595cb
+
+Count = 41
+Adata = 633f3efa
+Payload = 1f88dfd4f5c52c22b1db47f9f4fb6e2f8bcd78d593061369
+CT = 33545dc173fff01e2c2f68af9903697cbdea14aed5ba52540fa7e55dc54e80488a05ee7f1fc96e9d
+
+Count = 42
+Adata = aad86fb5
+Payload = b2b4cb5e90ebf4bd265093b7f5efd4d62dc60e29737aa496
+CT = 9e68494b16d12881bba4bce19817d3851be1625235c6e5ab18151c17d9e3f97244000a3b2d3c2f95
+
+Count = 43
+Adata = ed42941a
+Payload = f312b47d05f8eb5a29943b41347cb1983c75cb7a458a3868
+CT = dfce366883c23766b46014175984b6cb0a52a7010336795562d521c4b5c7a6f2c5ac65f2fd15b066
+
+Count = 44
+Adata = e5b085d8
+Payload = e9fb86938ea7f04cc230296859e7c96fcc352f968c9473e4
+CT = c5270486089d2c705fc4063e341fce3cfa1243edca2832d9e491a31218f688744098851672a09a64
+
+Count = 45
+Adata = 3776f37f
+Payload = 8af6b7540f997954812e38dbd99ccfaedd5c69963c353a4e
+CT = a62a354189a3a5681cda178db464c8fdeb7b05ed7a897b730ece28347d7ebf8291d7eb66b7651b4e
+
+Count = 46
+Adata = 4eb08c9e
+Payload = b90cfd9dd58e320d98510483b1d939bdb5f3b81666ecee59
+CT = 95d07f8853b4ee3105a52bd5dc213eee83d4d46d2050af64cbd25fb40480d15c039878b5d2f25afb
+
+Count = 47
+Adata = c7f93152
+Payload = 02caabc6ed0641681e7148c10cf3159fe35e44013252071e
+CT = 2e1629d36b3c9d5483856797610b12ccd579287a74ee4623fbfd98c8567b78d4b9c3a49a4641908e
+
+Count = 48
+Adata = 57957630
+Payload = 2f29882fdf1418d04f0b9d44272995a56973c4369c687a99
+CT = 03f50a3a592ec4ecd2ffb2124ad192f65f54a84ddad43ba4655c1abcb3ed1a175f12721a407c5d00
+
+Count = 49
+Adata = 19da955d
+Payload = 4e427130be9e94639320529ec135715e65da1117b5ba3c76
+CT = 629ef32538a4485f0ed47dc8accd760d53fd7d6cf3067d4b90621a5e5683df421a0dc52341485d1b
+
+[Alen = 5]
+
+Key = a2e6bf39efd1ceddc92b4333ed92d65efeea6c031ca345adb93a7770a8039bcd
+Nonce = 693cbb46bc8366086ec7cd7776
+
+Count = 50
+Adata = 3ba11282d6
+Payload = d822f84b023f12ea9e3ce16b904278e4aaab5e11c2c23f3f
+CT = 9f91fd2f6472e33b02b1eabb9d6655729d44c44dad6b3883fe0667bcc5806b225224b04ade8b21c1
+
+Count = 51
+Adata = 3f3a4718ea
+Payload = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12
+CT = e834b623d3d3c675b88d41d09d59e6595dbad43bed00b9aea6750fffa5a487540ce65770cd836e99
+
+Count = 52
+Adata = ff79ca8965
+Payload = 82b7cd168b6a82cb2d837f41ceda0c27adc5f5b28030454b
+CT = c504c872ed27731ab10e7491c3fe21b19a2a6feeef9942f7e7cfafe32bd71ea9813607c5df446c9d
+
+Count = 53
+Adata = 0021be18ed
+Payload = 1c1a0f144df76781e7c85ab178ed9b1ce8c6dc3f15c59149
+CT = 5ba90a702bba96507b45516175c9b68adf2946637a6c96f576716fe674c33ad3b9d3e54cc86bfccf
+
+Count = 54
+Adata = 9ae7996547
+Payload = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841
+CT = 9e0874c9f658dc8d867e53185d3b85088aa48de3205d3ffdab55dbee34f1bab555bbb196095fb5fd
+
+Count = 55
+Adata = fa292d1958
+Payload = fc7d028a1aa05c74b7ffe333ba6f676913b0f9f1ffa050b8
+CT = bbce07ee7cedada52b72e8e3b74b4aff245f63ad9009570476a4e9e759d5bb79c187a157099e3d12
+
+Count = 56
+Adata = 88800df7b6
+Payload = c9ea772e61742a6706da3ab3e81df14b31506ae58b063ece
+CT = 8e59724a0739dbb69a573163e539dcdd06bff0b9e4af39729f0f3699c9743ad6c9f09dc00ea10487
+
+Count = 57
+Adata = 715041afd4
+Payload = 70d2b8d64121ceccf1961444e8d33b7b7f998aeb58d3d270
+CT = 3761bdb2276c3f1d6d1b1f94e5f716ed487610b7377ad5cc560d78cba6d9f50e9c2677a710f92155
+
+Count = 58
+Adata = 14682301a9
+Payload = 1013946815001a2c08acca4196e0d6668ffbb3883cf111e7
+CT = 57a0910c734debfd9421c1919bc4fbf0b81429d45358165b95ffb6e29172a283d47e4478e2e1f7c4
+
+Count = 59
+Adata = e44c3c21c1
+Payload = f40dc834067bd163e0004d0ec5dd4b96e2a1ea31ea431c98
+CT = b3becd50603620b27c8d46dec8f96600d54e706d85ea1b24ccf233caf0bad9f68f71d78ee58512ec
+
+[Alen = 6]
+
+Key = c5a850167a5bfdf56636ce9e56e2952855504e35cc4f5d24ee5e168853be82d8
+Nonce = c45b165477e8bfa9ca3a1cd3ca
+
+Count = 60
+Adata = 4759557e9bab
+Payload = e758796d7db73bccb1697c42df691ac57974b40ca9186a43
+CT = 93ad58bd5f4f77ac4f92b0ae16c62489e4074c7f152e2ed8a88179e0d32f4928eff13b4ce2873338
+
+Count = 61
+Adata = 2ea07d393a0a
+Payload = ce60ddbe40b70bd55a9147036ad079dec1558ef4c2c625b3
+CT = ba95fc6e624f47b5a46a8befa37f47925c2676877ef06128b7d812c4d69f1f53ee9158382e56625b
+
+Count = 62
+Adata = aa6667faedc1
+Payload = 89eb3056770a6157f06921bc153834447c4b6d862d10d185
+CT = fd1e118655f22d370e92ed50dc970a08e13895f59126951e26fdbed62b228db008a1b14bd7942e12
+
+Count = 63
+Adata = 9e2127d92311
+Payload = 132f3e19e12f462a7463226b716c41a05a59c76f0e1a2f72
+CT = 67da1fc9c3d70a4a8a98ee87b8c37fecc72a3f1cb22c6be9124e1eb78de01b8af83b684baf3e43ad
+
+Count = 64
+Adata = 2f191bc9cff6
+Payload = b8611cbb9a3667b9458ca57eb636eb1dc580e7dbb5701692
+CT = cc943d6bb8ce2bd9bb7769927f99d55158f31fa809465209cb0f79736d1a810d06a776094f9fb67f
+
+Count = 65
+Adata = ad739d5f4736
+Payload = 112f89ccbdadc2433008d3ede2290f9ce81e5c736abf42a8
+CT = 65daa81c9f558e23cef31f012b8631d0756da400d6890633bfba2348f629471c232c9ff7e5f6f85a
+
+Count = 66
+Adata = 01acc909b7d3
+Payload = d47f2ff745de39a9055ad002de6334971fde480bef268b33
+CT = a08a0e27672675c9fba11cee17cc0adb82adb0785310cfa8c0f694d03ffed043787343827ea2603f
+
+Count = 67
+Adata = ce003c836a6f
+Payload = 13be365884b8a91a284ca24f70011e48794b51be275153b9
+CT = 674b1788a640e57ad6b76ea3b9ae2004e438a9cd9b671722279b553998a6fee0a86e177a448573a4
+
+Count = 68
+Adata = 6a759a4efd00
+Payload = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e
+CT = a13d5db4b781965f9dd065b0790f42dedde61cce68d673f54eeb434cca3ea719827417e94d6ed564
+
+Count = 69
+Adata = 02b84a26c773
+Payload = b7bc1580c68fd5d06c1bf75c31dad7a3e26d636d7eee20b9
+CT = c3493450e47799b092e03bb0f875e9ef7f1e9b1ec2d86422a74b5e4e2edb91fbbe722bfaf1500db4
+
+[Alen = 7]
+
+Key = ae8f93c3efe38e2af07e256961dd33028faa0716e5320a7ab319a10d2f4c5548
+Nonce = 6333bde218b784ccd8370492f7
+
+Count = 70
+Adata = 0b1fabdf2a4107
+Payload = bc9ca92a9c9919e39095d3e53fb148694620ae61227e0069
+CT = 45811b0c8f754bf03950e520cd4afc81c2e3eb8a11f4fd386d5a6e4b1fbee15d35939c721004502e
+
+Count = 71
+Adata = 2fc7f5c0ce052f
+Payload = f25a4ca20bbf4969bed6b93c1c77e3d7415f60fe3784216b
+CT = 0b47fe8418531b7a17138ff9ee8c573fc59c2515040edc3a24a68f98716190fb55f743a8bf62a085
+
+Count = 72
+Adata = 8a74412da3034b
+Payload = 3237bf953989d17c65a0fafd2bb1e32c237f98f55389e8f8
+CT = cb2a0db32a65836fcc65cc38d94a57c4a7bcdd1e600315a923afef7b4955d7d1e8f1abef9933bf9f
+
+Count = 73
+Adata = 7139f3c1d6cc36
+Payload = 55d86dc0423cfc2616ef996a3316e776707f8d25c985884a
+CT = acc5dfe651d0ae35bf2aafafc1ed539ef4bcc8cefa0f751b8e824c62632dff5cbc103d3060fbd174
+
+Count = 74
+Adata = af7a380f079aa1
+Payload = ac48398adb10292314973946f261ec39397442ca09b98dd8
+CT = 55558bacc8fc7b30bd520f83009a58d1bdb707213a33708980202d518ca871c9544f4a8c55fd8d20
+
+Count = 75
+Adata = e602abe8f72964
+Payload = 2fb78654e4395df8c37f260d74def234a3a4e3d2b1fe8614
+CT = d6aa3472f7d50feb6aba10c8862546dc2767a63982747b454b33ea6e4344033f74f513d1e41b82ae
+
+Count = 76
+Adata = 82741c5fd6e1df
+Payload = d488bdda400932de56a9f105f0e74ee79c2ed869faaadc31
+CT = 2d950ffc53e560cdff6cc7c0021cfa0f18ed9d82c920216073ccf18c7ea7dce79d0be1204c593234
+
+Count = 77
+Adata = 78f0cc22535402
+Payload = b22aba8d3e9f4b4bf006e26062de15daf94597731a600912
+CT = 4b3708ab2d73195859c3d4a59025a1327d86d29829eaf443b81b8af57b85093778690266e20e2fbb
+
+Count = 78
+Adata = 18e468139dd16f
+Payload = bd864f7b8efd6ed2b068f425482d449bf53a203ea88e1ca1
+CT = 449bfd5d9d113cc119adc2e0bad6f07371f965d59b04e1f09b94a857e7a0423ef6c9cbebde1f9c40
+
+Count = 79
+Adata = a6dab47c0fbfe1
+Payload = 47d9d18b6addc5f88986f0457b666faae59aba4fa3a02abb
+CT = bec463ad793197eb2043c680899ddb426159ffa4902ad7ea64718820065a739fbd3ba560a416895c
+
+[Alen = 8]
+
+Key = 548c2d1eb7d91e003633d4d9ff199e4a8447180edd89ac7867d25a1db288b5ce
+Nonce = 23b205bd6ff8ed0bab0c98999c
+
+Count = 80
+Adata = a6601111cd92c943
+Payload = 49fd5cbe4aff89dc3b8718f9ce545d612cbbebb289ecbf42
+CT = 3cfc6211e359ae322802fc9566f377b0dfe17d1dfe0878ebf2a9047e37cc0be1fab0006af8db8dc4
+
+Count = 81
+Adata = 96f0b7cd7439721d
+Payload = 94a95e945f660d1571b4d7d22709b000b45ff98b2129a4ae
+CT = e1a8603bf6c02afb623133be8fae9ad147056f2456cd6307106a430b04938e97f2e4cda81108ad3e
+
+Count = 82
+Adata = 2ee135dc2ddd9501
+Payload = aeed3aea01755c912213c8c276a2b75dad24f888a611efa3
+CT = dbec0445a8d37b7f31962caede059d8c5e7e6e27d1f5280ab2ab219c6c4952d52505cd9f904b0e04
+
+Count = 83
+Adata = 10c361934fd6ff77
+Payload = be1fcebea4c22a1d71e08047b028d7f4ccab0a6b8085d344
+CT = cb1ef0110d640df36265642b188ffd253ff19cc4f76114edfc1f7b2fe314faea28ab0dae349feb9c
+
+Count = 84
+Adata = 3f6c8a69917f7776
+Payload = 87680ac26fe1511e0f1f745aa4c2a5b9f6c0117dcf08feaa
+CT = f269346dc64776f01c9a90360c658f68059a87d2b8ec390308e529d64e786a29661cccddc0366f3b
+
+Count = 85
+Adata = 0f7a1426ff3b5ee1
+Payload = 9e004b072a27b085e59ca201c157c7d3c906a2c3b455c56e
+CT = eb0175a88381976bf619466d69f0ed023a5c346cc3b102c797c6510b85dfd097f3eac276aff00ba2
+
+Count = 86
+Adata = faa5bed84dcf168e
+Payload = a1bf47b15cd66e43daff420edf014a14b11994b97ada4030
+CT = d4be791ef57049adc97aa66277a660c5424302160d3e87998e522b6f13f99ecb553b6de845940907
+
+Count = 87
+Adata = 2851dae3cb3fcb1c
+Payload = 2d15734871adc63ff32d7002ab40c4a235a4d5fad223953f
+CT = 58144de7d80be1d1e0a8946e03e7ee73c6fe4355a5c752967a9ca39566189ee96c86462bfea78af5
+
+Count = 88
+Adata = 35a29c1bcbe2182f
+Payload = 5a84c4fdd47510fb7aebc0f79d7b625ccd0a96575740b8e6
+CT = 2f85fa527dd33715696e249b35dc488d3e5000f820a47f4fa613b5fbbe73a2df6c630a00ff4b1b92
+
+Count = 89
+Adata = 45820ae66c3e8e77
+Payload = 2052a94e1392dc1db0e89be19ea8f7379ee4cb607a914c89
+CT = 555397e1ba34fbf3a36d7f8d360fdde66dbe5dcf0d758b20d19feb067e9f6225376da21b4899d296
+
+[Alen = 9]
+
+Key = aab793e377a12484dbdd74c9b3a85c74c286e1cc498663fbd7c718b5633bb91a
+Nonce = 10022cddb323e88b3c08f95a0f
+
+Count = 90
+Adata = 82b8c736037ce2f2e8
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1044250f58857c69f72b5d3454d43949e5c02b3822970b280de1a3f7fc5d06cc30f06075f5504ed7
+
+Count = 91
+Adata = 8f2777ec4930f7e349
+Payload = bd845561f099500a6ff3fd09964dc3820f7ab48ba4ed04d5
+CT = d1c8f9ebee44ff231485207e684b0e65a033db29b082ac45835840df6fa96f5c972ac09d94148cbc
+
+Count = 92
+Adata = 5cab3b846870709569
+Payload = a6e09404fe60badfc63dc228057485e6f563ba82acdabd7c
+CT = caac388ee0bd15f6bd4b1f5ffb7248015a2ad520b8b515ec2f83ef84b299cfdb61d2b5039d536c3f
+
+Count = 93
+Adata = 0938f2e2ebb64f8af8
+Payload = 33404d7e0e620c1030b91020e33619c5f53d8b210fa86489
+CT = 5f0ce1f410bfa3394bcfcd571d30d4225a74e4831bc7cc19db04e655cbe22b9ea508d2a03757b97c
+
+Count = 94
+Adata = 82f78ca0e0da2b2d3a
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb9f087a50bf50
+CT = 0d34c4248f2aaaefcef5688a80188d610ef2f0aa6e3f17c04bd88dc6985f819004c2b634c5303ed8
+
+Count = 95
+Adata = 401191aa3fd34abe87
+Payload = 949cdd7c2973d7519e7bca98b2c5947e6d8e91c90e632319
+CT = f8d071f637ae7878e50d17ef4cc35999c2c7fe6b1a0c8b894ff3572e4ebf78473760d8cb4b0366b4
+
+Count = 96
+Adata = 4df4377596d8987671
+Payload = f6720a0bd8705c70e0f923338965e810b3ea939bad652327
+CT = 9a3ea681c6adf3599b8ffe44776325f71ca3fc39b90a8bb7de95ec3eee17753e60fb3c0661bdd098
+
+Count = 97
+Adata = 6593194b9970545c5a
+Payload = de9b0556661e726f3e6e34515ff7196420fe61b4f38419f2
+CT = b2d7a9dc78c3dd464518e926a1f1d4838fb70e16e7ebb162b8590ff04f967e51fbd1be84f01b4dcb
+
+Count = 98
+Adata = ab2d432058b540ac72
+Payload = 6cad7f3b9f196839bbc5a7f755c09aa8e17c83d9cb8b3954
+CT = 00e1d3b181c4c710c0b37a80abc6574f4e35ec7bdfe491c471d67b75b2da855a12ffb24ddd64a048
+
+Count = 99
+Adata = 5dc631eeeacb5a0b0b
+Payload = 70a55aec1144357377612fd0bbc2c817f33465a656219957
+CT = 1ce9f6660f999a5a0c17f2a745c405f05c7d0a04424e31c71fc798dd16c1fadef607a9297cbfbfef
+
+[Alen = 10]
+
+Key = 06ac39896073a44283611a66ccab067e2dd2faa8da82ff9a45bb29e54d2e6e77
+Nonce = 6c7942c9819cf69b817bfcdb0a
+
+Count = 100
+Adata = 215e2a6c24325340fdec
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = c5b3b50ed8a7b7b96b02ba9464b6a2ff80e90548605699a63d70e6dffb31a376a1eb7f94526dca48
+
+Count = 101
+Adata = e0a29a2c7840cf9b41de
+Payload = 7e5e5710a693ebfa36335cf7965574740880acdddd13fb1a
+CT = 89fb3efdc685924d24d5e99c3824fe2091730366a49c136fcbf516608fe20e06bbff931e84683545
+
+Count = 102
+Adata = b8026fbada6339d84802
+Payload = 08c342a50aa23362622934dfab55d9b22c22c249ad08138c
+CT = ff662b486ab44ad570cf81b4052453e6b5d16df2d487fbf9d70eb14f3fa0229906b9e0360be3d3f9
+
+Count = 103
+Adata = 65f4b3a00c1c1ef39445
+Payload = e085aba85882c75d5e41559167731496cf17d3907894352a
+CT = 1720c2453894beea4ca7e0fac9029ec256e47c2b011bdd5f4184771199a427861bf17cd8401e794e
+
+Count = 104
+Adata = 96118dbfe53434d8aed8
+Payload = 710f890be2b8da77c1eff429ede9cc931d50f059748cbcb6
+CT = 86aae0e682aea3c0d3094142439846c784a35fe20d0354c34e20b2db52fde68f88bfb886fdcb2c47
+
+Count = 105
+Adata = cdf4b485d2e04709cf8f
+Payload = cda96efee4e188ab3048bc1904ac2c36ab018f2ab7602682
+CT = 3a0c071384f7f11c22ae0972aadda66232f22091ceefcef782ee3df38ddea8e269eb47e39900345e
+
+Count = 106
+Adata = 50e57e57cf8e49e3a4e6
+Payload = 3dc596d52e520779a50bcba3049388b340dbf6d0f2eb94cf
+CT = ca60ff384e447eceb7ed7ec8aae202e7d928596b8b647cba44aaac4ed86f687cfc031f22827725f1
+
+Count = 107
+Adata = 48c670f11ff7f74e7003
+Payload = a33105c0dccf8e3b687212a870af9f710462756705fe09b3
+CT = 54946c2dbcd9f78c7a94a7c3dede15259d91dadc7c71e1c6d75255006ac037d6a4d048f1fc338012
+
+Count = 108
+Adata = 465e3be6113a2fb2ee20
+Payload = 573ac2436158eb7dd9be981e3cfbe75d3a188ea9cf2b1ee2
+CT = a09fabae014e92cacb582d75928a6d09a3eb2112b6a4f6976c1da33a80bc8157cece1acf9400b2bb
+
+Count = 109
+Adata = ee4e10574faeae85e9b6
+Payload = ca35bdb54e73eac5a5200a296b3aba5f37c87349746102d4
+CT = 3d90d4582e659372b7c6bf42c54b300bae3bdcf20deeeaa165c1cb98da4a1a920ca1ed9a7b6ec514
+
+[Alen = 11]
+
+Key = 50412c6444bcf9829506ab019e98234af1541061557412740bc120b456052763
+Nonce = 85684f94c3702c5d870310166d
+
+Count = 110
+Adata = f706a3e09df95d3e21d2e0
+Payload = 6cdbd63f6d591f59776f828533b28e2453a214d1d0dd8a39
+CT = 8c8b4ae854a5d5c265b25e3b54bded9444cc454b3e0e6a24d6c05eaf406a5ebd578e19edd5227380
+
+Count = 111
+Adata = e46b25b9a41a858e87900a
+Payload = 100132c315bfc9c4fb93023f5d3500d7208a68acb4d2c630
+CT = f051ae142c43035fe94ede813a3a636737e439365a01262d5088446e42591c0ede68e82334d97cfa
+
+Count = 112
+Adata = 28d34b29afe6586fd9bf0e
+Payload = d5460c1db0d24dedc63c4c78ce6d1f0b2d46f3b01934525c
+CT = 351690ca892e8776d4e190c6a9627cbb3a28a22af7e7b2413eaaef2823f5ac3f313f560bd774d10e
+
+Count = 113
+Adata = 2852d4fd68a3e9e47d44a7
+Payload = d2d73b62e3b1c9ab75f3544ff8616741e0adbae84b8cf9d0
+CT = 3287a7b5da4d0330672e88f19f6e04f1f7c3eb72a55f19cd62d30d99bb7dadec34e2891c156a1f5d
+
+Count = 114
+Adata = ec1c17b2ab13d7c8ac874f
+Payload = 74796d78d6ad03634ed80800af530212baa7e5093651cedf
+CT = 9429f1afef51c9f85c05d4bec85c61a2adc9b493d8822ec241c9a05ebf9ed27792bbced83b5dc582
+
+Count = 115
+Adata = 4f1ab5ddb1c199e9a5daab
+Payload = fb432488b5d08d576a90f085181ad883407a6ce9ea29950a
+CT = 1b13b85f8c2c47cc784d2c3b7f15bb3357143d7304fa75171ffc24020e86b1314724104e6b57b3ce
+
+Count = 116
+Adata = 864e0e728aea856fae6c6d
+Payload = 2b82d96ed1778412378abe4e09c633acf3359b9709ae3dcb
+CT = cbd245b9e88b4e89255762f06ec9501ce45bca0de77dddd6539bbb0af8ecf77b4508533247b3501a
+
+Count = 117
+Adata = 21ee21a5ed0d75d0380a28
+Payload = 85143071241bb65261fe7afcc102416e59b9e46ee0c90073
+CT = 6544aca61de77cc97323a642a60d22de4ed7b5f40e1ae06ef8981ec6ce7c4687b178f2103fa8c8be
+
+Count = 118
+Adata = 2b63f7b676f13f45d103dd
+Payload = 185577b48237acbdaa3590b8057fe374f875ce829b62c98f
+CT = f805eb63bbcb6626b8e84c06627080c4ef1b9f1875b1299265d9d899c6b71c0ab3049ea1dbfaf6a9
+
+Count = 119
+Adata = a33e86d813c2c4ff3bab20
+Payload = f051beb936e60fd4f3bca31964f1ad3e6fa16dd27b65a6db
+CT = 1001226e0f1ac54fe1617fa703fece8e78cf3c4895b646c6b246474c4e79822f5fd55f2fb0067a40
+
+[Alen = 12]
+
+Key = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0cb00b1abade1b5ce0ed
+Nonce = d80210b9f9776ea36dc0e0a787
+
+Count = 120
+Adata = e4296d1c8cf4ffc4b2635135
+Payload = c825952293e434ea866db558aaf486ef09a92bf366988f71
+CT = b8b3b15fdf6a4a0b5abc313afc769e4e8413bd887552583ede3ed995d1b70561c8e28a7b1a7e3dc8
+
+Count = 121
+Adata = d18bfcc1584eeb8695388ebe
+Payload = a1e0248355bfd1d881fb1a4798cda2f6f6ad513c69c5f9b4
+CT = d17600fe1931af395d2a9e25ce4fba577b17c7477a0f2efb561575f6743c5759494be59afa0c3e11
+
+Count = 122
+Adata = 14682301a99bf680805d1ffe
+Payload = ded135fcbf62219bfba2cba40c2d2cbe4815ddaac1342231
+CT = ae471181f3ec5f7a27734fc65aaf341fc5af4bd1d2fef57e34f689367228cbaf3cd76fb407109cf6
+
+Count = 123
+Adata = 8853aa2dfea9c4d370678bb6
+Payload = 12d3900c6c01968b8344762e0e883e5e219f42b052dc6215
+CT = 6245b471208fe86a5f95f24c580a26ffac25d4cb4116b55a2cacb7fc3856abcf759feb8dc0998ab1
+
+Count = 124
+Adata = c5d3b9c593c3185fe4b6d1bc
+Payload = 8c3c1193fe1a1ebad7e01a1eed1a32c08a0091b1c948e184
+CT = fcaa35eeb294605b0b319e7cbb982a6107ba07cada8236cb42a740cd3262424a2c3d77849ead6149
+
+Count = 125
+Adata = dfb9e8149b51f89b1ec00a8e
+Payload = 8219618b7728ac89237705ecf84012cc7c80293c4cf171d8
+CT = f28f45f63ba6d268ffa6818eaec20a6df13abf475f3ba69747d4dbe0f9415d40843070e1e93059eb
+
+Count = 126
+Adata = 08a4590d262e4dbcb7e23ffc
+Payload = b344b7dc239617fa51b9ea10a349e940c3163779f5284c9c
+CT = c3d293a16f18691b8d686e72f5cbf1e14eaca102e6e29bd31215b3dccba4ca5de64be7fab8a7a22c
+
+Count = 127
+Adata = 74aab7b5b96238710637c6e5
+Payload = 740d4b25ca7221d0826057701a6bfd66c50a82f010a57be8
+CT = 049b6f5886fc5f315eb1d3124ce9e5c748b0148b036faca734e09945ee44c95c7923d8b9249ade7b
+
+Count = 128
+Adata = 420aac47a3f212fffca40549
+Payload = 5d9000489186abdf4f0a2794f0222fcaa156fe6309c10f79
+CT = 2d062435dd08d53e93dba3f6a6a0376b2cec68181a0bd8360a568dd779526a0058d522af1dafde30
+
+Count = 129
+Adata = 6e80dd7f1badf3a1c9ab25c7
+Payload = ac2c44263363810bec3a309aa618b303e05099dfdbeb5c16
+CT = dcba605b7fedffea30ebb4f8f09aaba26dea0fa4c8218b59279442c88d612ed1a39ae0005f88155d
+
+[Alen = 13]
+
+Key = a4cc7e1c90f8684e6a5f95e6898ab4e3c194cb46e196d8228062b9f3fa744930
+Nonce = cdc2712e51c7f333d6bad78eee
+
+Count = 130
+Adata = 569c56b27268d3db54e728aac0
+Payload = 10d4cff95ef490923c9e0906880729d4d05412e7675cce76
+CT = be3ce3e9dc72499839a98ae52abb17415e8547687e8a3c7b8aaaac20d4c9276f2851cbba2b04d185
+
+Count = 131
+Adata = d75635b6450e43285fba966835
+Payload = c9db03e2efbab713b0b640421018d3971ffe2abd70fe8fa1
+CT = 67332ff26d3c6e19b581c3a1b2a4ed02912f7f3269287dacc121ff83891335dd1214ea6fc25f6a68
+
+Count = 132
+Adata = 70750acea6a05f8b7b425d262b
+Payload = add631ce5846ce71434aad4998f8e429aed430e7d38bdbb2
+CT = 033e1ddedac0177b467d2eaa3a44dabc20056568ca5d29bf549e71ec517cd65150f42b3cb53f936e
+
+Count = 133
+Adata = 2a567c7ec7edaa5a438ae3bb35
+Payload = a514d170422feb1d87bb7725a9e77cc6fc8afb45c2af6d90
+CT = 0bfcfd60c0a93217828cf4c60b5b4253725baecadb799f9d0e432ec394ddbb65205dc40a5a8e90a4
+
+Count = 134
+Adata = 0f8795385b805246a0a2573afc
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d730a80a3ab4a07849d4ddf9280170800fb9897c917dbe30926b0d977107a3918717f79b63f36b0a
+
+Count = 135
+Adata = 111d224c102b136159fbeb44a7
+Payload = 2edd498e54b23aab6f4fd7b3f22c4c787e3a4f1fb06c9ec7
+CT = 8035659ed634e3a16a785450509072edf0eb1a90a9ba6ccac2cd61599bb93db3dd3dabc12aa90932
+
+Count = 136
+Adata = df0821c9ea6ab329c626d11b4b
+Payload = 6e3e25db29da2c787bb37755ee770e2402fb8208da23389d
+CT = c0d609cbab5cf5727e84f4b64ccb30b18c2ad787c3f5ca90bd027ecd00cc6dc5ffd5d746d92281e9
+
+Count = 137
+Adata = aacaf4839c35338d6e2b47ac45
+Payload = d4ed4584678e982ace8664e77d0e55be356be558cead3755
+CT = 7a056994e5084120cbb1e704dfb26b2bbbbab0d7d77bc5583c01354a450eda2588be7578530e38c0
+
+Count = 138
+Adata = dc6eed3f8bd1b5563c1eeb9afa
+Payload = 4ebf00eadaf70711f630f5badf0214d8518a200afb0e5765
+CT = e0572cfa5871de1bf30776597dbe2a4ddf5b7585e2d8a5688d7a1d546e25ba026cd46556eb2c4b7e
+
+Count = 139
+Adata = fbfe7e910f242a78dd6e69a2ec
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 89c14f71907472e8c25926068883be257653a57caf213a0b0e951aee790239e7067ef37f497b4bf4
+
+[Alen = 14]
+
+Key = 347e12eec56e95aafcc7d25bf10fc756b4e42bc2e43da7f97df24331f27f1f5c
+Nonce = b8d517b033754058128d13d11a
+
+Count = 140
+Adata = 511c6924fa96db716f6b053b7a48
+Payload = ca88dddfc876a12f45f19562bc9ca250f43267ab251a7f34
+CT = eeedcfa8f5b5b48c1d7e277526eecb7294213b9f5785167ae949b93003dfe63c95c1d49edfb4de3f
+
+Count = 141
+Adata = 10c26d5939618189a9503623f55f
+Payload = de0c0d17c3950e7f8985b56d60623cbd010cd765da4df5ab
+CT = fa691f60fe561bdcd10a077afa10559f611f8b51a8d29ce585c32a90d77fed97eb0ac164ed616e1c
+
+Count = 142
+Adata = bc09c59d20e55a9e184d70af2c7c
+Payload = 2f35102d78a32fcde1cfb563ea8d310ecb83c146ab8de362
+CT = 0b50025a45603a6eb940077470ff582cab909d72d9128a2c180fdf5f63045f326057cf74fd4cee6b
+
+Count = 143
+Adata = b75887f13d6e8c4b35b27b965693
+Payload = a3fcce3420effdd6edb37271735a0d30c10c65233aee173f
+CT = 8799dc431d2ce875b53cc066e9286412a11f391748717e7134959a180fc2cf2ba99af21cc1bc8e5c
+
+Count = 144
+Adata = 603401a9b8ecde4d5c86b6107363
+Payload = 4ac918727e41b8c536484e3781c403e260c278712853508d
+CT = 6eac0a054382ad666ec7fc201bb66ac000d124455acc39c32ca2e5195dbd44f0a119538c95788510
+
+Count = 145
+Adata = 7206b06f306124ca3a302e84c5a6
+Payload = 97d770cbb2c42a552e450cc4e35e5668b2ff89cec735cc91
+CT = b3b262bc8f073ff676cabed3792c3f4ad2ecd5fab5aaa5df74a4e1198878a76291594b9826d4b563
+
+Count = 146
+Adata = b15efed90a5d1d62f545ac22af6e
+Payload = 86bb2ae50e36c72936240a74502172625cbca210cf285077
+CT = a2de389233f5d28a6eabb863ca531b403caffe24bdb73939ff5f993dcfbd048274da7439c0f9ef5a
+
+Count = 147
+Adata = c9eb714ed9858a8dc11a26ee3f00
+Payload = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17
+CT = 29a28be439bcc3447e851e5a1e0db26f765b631cc3a436590e87710559a375ece6ef2953b6aa2542
+
+Count = 148
+Adata = 07ca22271e95cb48a872046822b7
+Payload = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a1
+CT = dd35fb1a58664b58636c174a35892b389ac289562cab29ef998035c81716e2d1ed4b4d56ff18af5d
+
+Count = 149
+Adata = b65f6773516124317cfb4b1fcdf5
+Payload = e160e28e601a49d16db18f25410756b330b036c42e615fd6
+CT = c505f0f95dd95c72353e3d32db753f9150a36af05cfe36981ae73a9b6896d8fc1b8c0d772d632983
+
+[Alen = 15]
+
+Key = 520902aa27c16dee112812b2e685aa203aeb8b8633bd1bfc99728a482d96c1fe
+Nonce = ddf50502f414c1bf24888f1328
+
+Count = 150
+Adata = 22b4f8f1aac02a9b2ef785d0ff6f93
+Payload = 533fee7d2c7740db55770e48cb1b541d990ea3f8f08ed1a6
+CT = fc867b319e0e4ab45ec518a1b5dcec4f29982173f3abfd4d8a8f8d14d2bdac84c3737cfbd75b7c0b
+
+Count = 151
+Adata = d0a43de391d492746ecf322acd6e5b
+Payload = cced20b59a6b2c3c45ea6c87802440c9c47b1015e83d86c3
+CT = 6354b5f9281226534e587a6efee3f89b74ed929eeb18aa28fce59f5e6e3cee284b4cc747ff5ee13f
+
+Count = 152
+Adata = 3a789c06f87f05933c34a1cf9834a8
+Payload = 90939a4530181ad6900664f66bfc2ce0289432a0afe9babe
+CT = 3f2a0f09826110b99bb4721f153b94b29802b02baccc9655ddaef56d8255125f7c316c6c59ce779f
+
+Count = 153
+Adata = 785260973f112c56d9f891160c4c11
+Payload = 86cd926b9565b76a88fde73c31e9ac908ffd1e6ca30b59ce
+CT = 29740727271cbd05834ff1d54f2e14c23f6b9ce7a02e752555810cbcdf48f05d0a7808673c82d08d
+
+Count = 154
+Adata = bf6a144591c0ea7b10274fbd3345a1
+Payload = 6ecd1c1acc6290672f9cf639ed0cebcb21ed0c56f35a5ce3
+CT = c17489567e1b9a08242ee0d093cb5399917b8eddf07f700849e41e5d34a698ae1d96f16bc68da944
+
+Count = 155
+Adata = 7d9488b500d89a27f367f34a448a87
+Payload = b01e3f4fb5ee7501e8c2f4ccefb542ae20d7fd61a2c41c8b
+CT = 1fa7aa0307977f6ee370e2259172fafc90417feaa1e130601bc54e546d1a6fcf6187169feb1ea533
+
+Count = 156
+Adata = 060fc718e994edc7bac9962ca7f28d
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = 8d12ff411dec3b0ad61a7225902cc07c97ca898c29c8fe6ff2eb6c0ab42acf42985c721bfd576e71
+
+Count = 157
+Adata = cb6f96dd06015967279ade310a7401
+Payload = f96ed20b23c784015ff58f5f040798ca75e3b98045deca8e
+CT = 56d7474791be8e6e544799b67ac02098c5753b0b46fbe665ac502b8e65cc1329b6895afdd354f5db
+
+Count = 158
+Adata = 9aa6d501455019b4ef4c7fb789d22f
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = cb3311cd8ed070804105f7aa90ee14ebf6ae04ebf2ab9a9a87e5f8a8148f21adf721477c36bd99ca
+
+Count = 159
+Adata = ebd1d12bbd14176a0d4080aa1edb89
+Payload = 32d71e59634126ac6c6156a80a0dfa0175b29e9f40a31696
+CT = 9d6e8b15d1382cc367d3404174ca4253c5241c1443863a7dda9ea0427522dbeaa509a11755434760
+
+[Alen = 16]
+
+Key = 57da1c2704219ed59abfdf04743a9a93c87a63d471818de0f1564b2db6421562
+Nonce = 4b60a47b7e90f622fa0bf803e1
+
+Count = 160
+Adata = 0ae8c012ff39753510df3ee80707e4e2
+Payload = ddc3c1aa73fb6de92bb4db138e26f3c2e0543ab4f5924871
+CT = daa8256d4753fdf9cfef876295badaba89b45cc497f54d220ec2c6fb687753bca4580adc6aa2f296
+
+Count = 161
+Adata = d5b22e7697ba70e00c7ef32709563f01
+Payload = 34270576724083e9989764d08a0d5c1b4738f34927a1e436
+CT = 334ce1b146e813f97ccc38a1919175632ed8953945c6e1658f30b9c8e380c98bb939a4e8a85af758
+
+Count = 162
+Adata = 6b4edef415763aabcef01863e8197aec
+Payload = 904fe88e7a8e76447a64b488ef84184d0f1ab1b67f0c5a7d
+CT = 97240c494e26e6549e3fe8f9f418313566fad7c61d6b5f2e53e80d8ccc687fd303f4cdef44b6e8b9
+
+Count = 163
+Adata = 4c099809061024c010a77e9621fc2bcf
+Payload = 51fe7bac8f3255f17f64fb9322210fb7d8da8e762498b233
+CT = 56959f6bbb9ac5e19b3fa7e239bd26cfb13ae80646ffb7600c635dac5b70338dac3f33ce16a99145
+
+Count = 164
+Adata = 9d329439588164d5a96675a85c07a039
+Payload = eab6dbc13bb92df36b1882df2b8f34c3cefa41f95717fbd7
+CT = eddd3f060f11bde38f43deae30131dbba71a27893570fe84f996e8163affb1494bb3c12eeadf16b6
+
+Count = 165
+Adata = b768fc3daf29ff9e8bd575072d986e99
+Payload = c44c9c287d3eac7c30570d9c4adf2e4857c598f7c54cd126
+CT = c32778ef49963c6cd40c51ed514307303e25fe87a72bd47598b4206a9622d5631751a497dfb1f662
+
+Count = 166
+Adata = 3efc7cc2d16bf82d2bcfbc559a09b2c9
+Payload = c11b9c9d7607f387359c0038d3e8ec4d527562ce63c3384c
+CT = c670785a42af6397d1c75c49c874c5353b9504be01a43d1f7dd300167d267ad700dea37fb475ecdd
+
+Count = 167
+Adata = 0ff89eff92a530b66684cd75a39481e7
+Payload = cc17904b166f28df82f57889f391159a4a308e752d714ee5
+CT = cb7c748c22c7b8cf66ae24f8e80d3ce223d0e8054f164bb6303e9c9bd0d8e4aac42894ca03d6ab06
+
+Count = 168
+Adata = fbd11bc75759f0461e796f6917aeb42b
+Payload = 6f97e595ea2f40612ea84a2097b974d235055fe1dae59403
+CT = 68fc0152de87d071caf316518c255daa5ce53991b88291500953f46e0e9cf1369e9eb018a4df3c09
+
+Count = 169
+Adata = b79940952f42537484aa2907c72dffa9
+Payload = a48cbf933b88c0ec5ddcdd8fcad186391c2cbef308607de5
+CT = a3e75b540f2050fcb98781fed14daf4175ccd8836a0778b68a1702dfa0cd9c290c5ff9c35cc83705
+
+[Alen = 17]
+
+Key = 9267ebc99ccf648b146cba3c251187e24a9947d806ceb0ced6894211641a1e0d
+Nonce = 9b7298950280e8762ecdc9bbe4
+
+Count = 170
+Adata = 5824689453bc406bf891b85e4576e38fe8
+Payload = 967daf12f16f166b7b5038f83a1cf0b980f5abf4c7746f2a
+CT = 7cfe2a7a54306eb8d8a63d3d1ae86794f9a2c22198b2cb4f10ca926f1a430c08c12e23db3d913e93
+
+Count = 171
+Adata = cd15973753b94b77bb4b778de8b3b0cabb
+Payload = c4a756f6024a9dceabf6e264fffff9c719217fb418141ac5
+CT = 2e24d39ea715e51d0800e7a1df0b6eea6076166147d2bea05d5b674fd15410cc235dba6d8c8d82a8
+
+Count = 172
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3f
+Payload = e0d5de7d1eace211c0e70859ff315ff485d1200c6dd13f93
+CT = 0a565b15bbf39ac263110d9cdfc5c8d9fc8649d932179bf688750b5f36c86e7eda9015e960a7471a
+
+Count = 173
+Adata = cbbecf92551a15f5cf00a5be4a50b0eb17
+Payload = 05a4a4ba28fe8876f9bcfa5ec60651fd3fd4732f22049bd5
+CT = ef2721d28da1f0a55a4aff9be6f2c6d046831afa7dc23fb0d5fa842209dbbc04c87965f78500fec1
+
+Count = 174
+Adata = 873ba7f8b71517ec50297b21cf94cdb7a5
+Payload = 9cdebaeee8690b68751070691f49593668a6de12d3a948b3
+CT = 765d3f864d3673bbd6e675ac3fbdce1b11f1b7c78c6fecd67d147edbe114bfdb3f3b9b37d5719ef5
+
+Count = 175
+Adata = ac087420feb1e1e8c2546c2a8b8a5af0d0
+Payload = 5672e61cf664d73918dc1ca84df1fce82db0e305a61d57b9
+CT = bcf16374533bafeabb2a196d6d056bc554e78ad0f9dbf3dc57b4c2bbc377937d15b3b89543e29d0e
+
+Count = 176
+Adata = a12c690568114fd7a677f49d74e84fc1a6
+Payload = 0f5452e6b51540cf219998590995cd7f8785fa40b4f217fc
+CT = e5d7d78e104a381c826f9d9c29615a52fed29395eb34b3992e6ca774074b47b59adabeaf8835582d
+
+Count = 177
+Adata = 7a78ddfe5afb2dc90ee4a600c2fc014b0f
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae72f7
+CT = 7050bda358442a350db77d357ef4910f0dafd9670168d692bd320f48a7221537e3cbed5ac4154a56
+
+Count = 178
+Adata = 6053e466ed1f647a3cd88c4d2052ec00cb
+Payload = d17b8d556e83190c84d4a812957c64ffa7f336298f4e2c72
+CT = 3bf8083dcbdc61df2722add7b588f3d2dea45ffcd088881740574e201f9a26932a87c8d822505814
+
+Count = 179
+Adata = f7673e3beb526834d6507058fe62e34987
+Payload = 2eaef86b0f602364f86510eabc58bc9ad1e6f0a6f6df0b83
+CT = c42d7d03aa3f5bb75b93152f9cac2bb7a8b19973a919afe6837dfa3fdef2f012b6609de2ac5dd9d6
+
+[Alen = 18]
+
+Key = 7a855e1690ee638de01db43b37401dcd569c1ae03dc73dd0a917d0cadb5abc29
+Nonce = 8f160a873a1166c8b32bccbba7
+
+Count = 180
+Adata = 72674aca7eba2fc0eeafbd143c2c4d8aa6c8
+Payload = 33ae68ebb8010c6b3da6b9cb29fe9f8bd09b59ec39f4ce4b
+CT = b22afdf4f12c43ec23e01ac1215a3f5286059211207e957057e9a9203da74387a9468f8af5e27547
+
+Count = 181
+Adata = f7da3f100b80e2ade812f1700aab6b72f746
+Payload = dbb29817b86cb80e0d008742cedfbf52b236f15ee8cad50e
+CT = 5a360d08f141f78913462448c67b1f8be4a83aa3f1408e35a3985f12a49eac424a35c94645917e91
+
+Count = 182
+Adata = 4b05eaadf98505d0806c233b2cdcaf4254e8
+Payload = 145aa8cfd544a2f46bae1aa83cbdb3d21c3d1350078a3af4
+CT = 95de3dd09c69ed7375e8b9a23419130b4aa3d8ad1e0061cf4ab089a8724b87a1167180963d44ec65
+
+Count = 183
+Adata = 05a3aaa08b9a6aaeb84704431425d0e45a14
+Payload = 6b32e8906dc89194a69410b79cd041b62eb01afb28a3e10a
+CT = eab67d8f24e5de13b8d2b3bd9474e16f782ed1063129ba310a7d1520141892e140448292185c41c7
+
+Count = 184
+Adata = 74db01edc26a2d2044cb8eaad8b907b78863
+Payload = 545ed03588fd85a8bbfeee66d2082ae6f8e2f3c9dbd8725f
+CT = d5da452ac1d0ca2fa5b84d6cdaac8a3fae7c3834c252296472d3eee219d94bd788f62df4add5ec40
+
+Count = 185
+Adata = 5f2c6ddf5a2403e04dac8b2813c060b67e76
+Payload = 66dd5fd8611c551973a3d0c078ec2b4d39ad163d9168de3c
+CT = e759cac728311a9e6de573ca70488b946f33ddc088e28507c600496f4f8b1b7da118ee36d8cd57f8
+
+Count = 186
+Adata = a650a2a5e3c6f7c95614570aaefd0cdd9a42
+Payload = 6f364b3f778376cbf3f4b0b0c5350a8fa278f9d8c25faad6
+CT = eeb2de203eae394cedb213bacd91aa56f4e63225dbd5f1ed4710004d06ce7a7efbd19da4e3ce3cf7
+
+Count = 187
+Adata = 477c2484cf5c56b813313927be8387b1024f
+Payload = 3de4798d8ad84c460b92abc10b7f5e7c9fae46a1dd353687
+CT = bc60ec92c3f503c115d408cb03dbfea5c9308d5cc4bf6dbc304099641c4ec3dc2c54fdf4f48dbef2
+
+Count = 188
+Adata = 564e1df74aa2d7ee33b66cfeda810774e16c
+Payload = 7769b45fea11f530fb9a67f1b5b1964a34cfa32bbb03f4b1
+CT = f6ed2140a33cbab7e5dcc4fbbd153693625168d6a289af8a905c1b05e8945685f8688faea777eb43
+
+Count = 189
+Adata = d5e66502529b0045883d935e05acd242baa8
+Payload = 0c0a502b42f81b51806c7080a8155280f493f2922cdc7df8
+CT = 8d8ec5340bd554d69e2ad38aa0b1f259a20d396f355626c3ea5a3b6a8bafde4006b993cfb3b13557
+
+[Alen = 19]
+
+Key = 0ebdc6ddb4c502725dd6ee8da95d56a0d1044b4694d6ba8475a4434f23a8474f
+Nonce = fb717a8c82114477253acc14f6
+
+Count = 190
+Adata = 41e9d65632f74f449a6842d5e6c4a86ef83791
+Payload = c7360282c85484a5a33ab1c68dd70873ab4e74ffd4a62cd5
+CT = 2e961b3a2fa1609a4e6fd04bff6ac5e306ae2638706f997b42be2e2ba05c54b619850db5c9d684fe
+
+Count = 191
+Adata = 555304659bde926cb2553b8a4605251fcddd92
+Payload = 1332314d1cf783b9f64e0fa2d42d43d225da9fd5165b5f0a
+CT = fa9228f5fb0267861b1b6e2fa6908e42883acd12b292eaa4bbdee2605bc69601b1e83d1e7a0b400d
+
+Count = 192
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9
+Payload = f264da8606ea429e0e25da3f2efafe28beaff05b42097369
+CT = 1bc4c33ee11fa6a1e370bbb25c4733b8134fa29ce6c0c6c7304611baf530932da7954f714514d228
+
+Count = 193
+Adata = d7186a67061319b44eedc0677ebf5d932d5bce
+Payload = c9ee6482144dc61c43041324a2c18ede370011cb4882b0c5
+CT = 204e7d3af3b82223ae5172a9d07c434e9ae0430cec4b056b6d1d44e26404b7324767f0b3f7486f8b
+
+Count = 194
+Adata = 38f37d5e2da017f1953ff3701be0b38809ba80
+Payload = 40524a4d32a711e7d5a59809878c318f42b6e2375b77b8a7
+CT = a9f253f5d552f5d838f0f984f531fc1fef56b0f0ffbe0d095453724d2db19f606c85d00e49b0bb38
+
+Count = 195
+Adata = b3b2d249cd3517555fa692bbe9116f069e7405
+Payload = 961c15bd7dc34cd5409c9e8869988676ec6845ecb0ee85fd
+CT = 7fbc0c059a36a8eaadc9ff051b254be64188172b142730536db1e4112fcd650e8c0f0f6fbf2d07e1
+
+Count = 196
+Adata = f5b5bcc38efaff01f69bd3a106dcfca3cc6414
+Payload = 879568ab9ebdea768a5459ced1d3181d822536c3d1ba38c3
+CT = 6e35711379480e4967013843a36ed58d2fc5640475738d6d1cedb29e68322e47ff9997f859257d98
+
+Count = 197
+Adata = a2098e3e23826e01f31107a208202f710eff00
+Payload = 47cb57599686716c75d7ecef5541d20fb908e6d98c39925a
+CT = ae6b4ee17173955398828d6227fc1f9f14e8b41e28f027f41c12bf2a3571ed672592b27e986e9058
+
+Count = 198
+Adata = 20a3d53e77201599540344c4e746c3ae3a5f84
+Payload = 4a8667b5ee09d3d4a6dca9a95f4ad406f1da94b846dcc6b8
+CT = a3267e0d09fc37eb4b89c8242df719965c3ac67fe2157316f12b2be8f5966d96602111c28f87b104
+
+Count = 199
+Adata = 92c592ead4b3f193cc36687593d4f0f412a5d5
+Payload = 1dc9e32ac4176f64bd78a6edd651ebeea3ba85dfcd8298a8
+CT = f469fa9223e28b5b502dc760a4ec267e0e5ad718694b2d06776df0a0cf048892e65bd8ad77cb2255
+
+[Alen = 20]
+
+Key = 2ff64bbec197a63315c2f328dcb4837d0cdc21a5d6f89ff1d97cb51195330cd8
+Nonce = a235f8ee3de9896b71910ac02c
+
+Count = 200
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112
+Payload = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a
+CT = 1bf122798bd8ee8e73391d589bd046a294d1615794e69cb9e6f3ba30143acbc3a1c1c6ec74333107
+
+Count = 201
+Adata = 0248359f8071143c3cc1d61882a3547a0b3d2175
+Payload = 4a6a7151465c2abd7e7fa1fd13019ad098b6ebcd190e96f7
+CT = 1b8c01056a837081553cb646ef73115a3ddcd3a095074e6436cb510c13a039f4df8cc26a942f9911
+
+Count = 202
+Adata = cca77bc4cf6c0abd3393dac3fbe90fbc8a1154f7
+Payload = a94f5ede43929d48d2c5a58c3262d9127d2ac3cb2fbd5768
+CT = f8a92e8a6f4dc774f986b237ce105298d840fba6a3b48ffb7fe0dedc2899dff81a251cff16bf5897
+
+Count = 203
+Adata = 9c082a84646c070bb11b7d6b92b62f06ee5b5b71
+Payload = 7303bd41cf47289a3111366d08e8e21548baf293052029eb
+CT = 22e5cd15e39872a61a5221d6f49a699fedd0cafe8929f17886c43ac23800de60a1fd2caef0f03261
+
+Count = 204
+Adata = 1c3ede1982a807a410ae1e21947bf430f8db7027
+Payload = fa9743a67978c20316cb91801d7789e350079aae3aadbd43
+CT = ab7133f255a7983f3d88863be1050269f56da2c3b6a465d026f7907e235c09d3322c4092d2e88f88
+
+Count = 205
+Adata = deb05a30a026ff66ce71e98afa62f0255aef84f5
+Payload = 99599b4042dcdb685350cdecfdf24992fd5b165670025d0c
+CT = c8bfeb146e0381547813da570180c21858312e3bfc0b859f6bb44a28c145d49f49f2821d4044e4b6
+
+Count = 206
+Adata = 93dd9b00a3353e5331338dcfcb7ca7e0bb873a4e
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 14f771712219a85a79678ae220e5c0f9c4bf49c59c1507400f7d20aa3d792d6a3ebc5ee0df2fd89c
+
+Count = 207
+Adata = 0855263860043207543c8c34648d53ec51c4f47e
+Payload = b2db87b7787531968d603098cb20ca7c438b4af72623fea9
+CT = e33df7e354aa6baaa6232723375241f6e6e1729aaa2a263a7ca4733f0208668b0a7879305e861d71
+
+Count = 208
+Adata = ee2d3a66deb3ebca867a902bb9202226ed516ded
+Payload = ca18ce38086223e63b4f0b616d110010f9e45eac42f2ba46
+CT = 9bfebe6c24bd79da100c1cda91638b9a5c8e66c1cefb62d5d76b482ff20429da8f60f0f863e1af50
+
+Count = 209
+Adata = 8e531aaea849addab6a83497cbc504f489505952
+Payload = 5717ed5da5b8aa806a18bfe979502bab6632c9428d3a7725
+CT = 06f19d098967f0bc415ba8528522a021c358f12f0133afb6aab66e1ac2346ef97850a4985c64b737
+
+[Alen = 21]
+
+Key = 24e9f08a9a007f9976919e10dc432002e2e078a339677f00105c72ed35633a3f
+Nonce = 15977424eeec0ec7f647e6c798
+
+Count = 210
+Adata = 2d838eb51a4bc69a001a18adf2084a680f02a3c5fc
+Payload = d3416a81b4246eb0bf8119a72a886bbc0ac9449c69f71d2f
+CT = e001a8fae390dc5d672cdd18f86a1f728158ec83a002050def9af5679edbcbb7db20ab6af30698db
+
+Count = 211
+Adata = d83ee7ce22fd1a2882d8d552346e4d7b3efdd67da4
+Payload = 22b6f10b482448626f6c7bebb14f1497896d071738133b4d
+CT = 11f633701f90fa8fb7c1bf5463ad605902fcaf08f1e6236fd435a5a38f84387f63b13407f65ec86c
+
+Count = 212
+Adata = 2d5537b24d0b0f7a45703c1e131656ec9edc12cdf7
+Payload = d60edc830be8207ffd9e9f646d3b4343b10b3d56acb89d44
+CT = e54e1ef85c5c929225335bdbbfd9378d3a9a9549654d85662ede8a705f8c988f55459542bd631b1c
+
+Count = 213
+Adata = 1a750eb326923412d94ccb35f5acd0f87415268178
+Payload = 716d3132f449a9def383978102ae50ed3ccae0cb346ba1df
+CT = 422df349a3fd1b332b2e533ed04c2423b75b48d4fd9eb9fd986de774a612230ce6c71449d26732ce
+
+Count = 214
+Adata = b10fc523bc4562d44edfe5956f93c15c4ab38bba3c
+Payload = 063c2ae2a15f26f979bf90657d20643e3184f1a9f75a3aad
+CT = 357ce899f6eb9414a11254daafc210f0ba1559b63eaf228fe710431005264fa7d3fc04bac50fc1ec
+
+Count = 215
+Adata = fe4f60ce9634e7dbc5e56204c4bf8aa9be577027ec
+Payload = bdc513e56a5bb70c02abc041af04d6e45e735d10cc88357f
+CT = 8e85d19e3def05e1da0604fe7de6a22ad5e2f50f057d2d5d5c13bea6ad0cad724e6cd02c89517ffc
+
+Count = 216
+Adata = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e
+Payload = 7dc5d8cd90ce2faf76bbd0d52e5ae11b310fc2b0051c4377
+CT = 4e851ab6c77a9d42ae16146afcb895d5ba9e6aafcce95b55d2a5531655aae01e249f213e0e04af0d
+
+Count = 217
+Adata = 199ec321d1d24d5408076912d6bb2b6f192d6b347f
+Payload = 66c2696edec26ba3d07bd3f485a0d6ce8a1b0a85b20083e7
+CT = 5582ab158976d94e08d6174b5742a200018aa29a7bf59bc52a127ef341345f9641b26e91265e1482
+
+Count = 218
+Adata = 8b013f5782d5d1af8dbd451a4202866095dac975fc
+Payload = f4da8ac3e8fe5ec6a5b6a2f27b68396e850b46a024d441f0
+CT = c79a48b8bf4aec2b7d1b664da98a4da00e9aeebfed2159d2a005ca13c4bf715c3b7b2782f799b23a
+
+Count = 219
+Adata = e320df32b71cc530e8493b12b9afbeabc255c5eb44
+Payload = 244891cb4af66cc8e99a3784a2e82475e51bd5c7fde67cf5
+CT = 170853b01d42de253137f33b700a50bb6e8a7dd8341364d704642aff9cb9288d49f0e567dd837e05
+
+[Alen = 22]
+
+Key = 0ec1b22b8df05dc92135d2dfbefed8ea81458f5ea1b801e8a218faf6cbdf1a79
+Nonce = 97ebcb8575bb58260208d5c227
+
+Count = 220
+Adata = a2f6337f86dd00d1a58448851e95d8c9bace4a5c8710
+Payload = 2f59d94d4ab8eeb84c2a6fefb7fb0a3ac059c1e1a65ae34a
+CT = 7ca0b1dbe34b0391e524b868b0af08b3e096917664d6aa2cabc1f9d0132394149c9062b74b82f04b
+
+Count = 221
+Adata = abf26b05558252c8e38c52b1ace087bbd1eb3d561239
+Payload = c25381853f73a3dc4195fdcbc45dfa1a40eb8324749adb2e
+CT = 91aae91396804ef5e89b2a4cc309f8936024d3b3b61692486d7df57c6a792f6f6b24cb5f87e92123
+
+Count = 222
+Adata = a13ade56b47803897666e42ef2ef88be0e779ac86c28
+Payload = 8dc5226a2a13088c87f4bf94262e0c0413f06b35d2fda79b
+CT = de3c4afc83e0e5a52efa6813217a0e8d333f3ba21071eefd4ac19b0b74cd9d5e100598b96c9f1f2e
+
+Count = 223
+Adata = 3c5b68b65edf62755b7e064bd26c843816bf6c1cd481
+Payload = ee4b23039cd512cfab8c7a2d0f2c78d66764520bc88759e1
+CT = bdb24b953526ffe60282adaa08787a5f47ab029c0a0b1087a77a27eabfc79f192c0ac491280af8d0
+
+Count = 224
+Adata = 0213fe13c49083d7c00335e1864dc139c9e7123162d1
+Payload = 30b48d4021838090fbd5251069ff8c631452daee5ef899db
+CT = 634de5d688706db952dbf2976eab8eea349d8a799c74d0bd39935f91c1e29fc1e4c5c5427ca9da79
+
+Count = 225
+Adata = a32291746b151be8134e183798aa82bef210343feaf6
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = 717fc97b74739e53db427ec6262a9d8b12485bfbedac9bfaaeaec90ada2a1ffef64c3873af645a40
+
+Count = 226
+Adata = a30f2fd445820cdf800145540602c877da0e4c311272
+Payload = fe703ca0901e4a706ce1393c7d8ce18a03eb2caadbfa7b8e
+CT = ad89543639eda759c5efeebb7ad8e30323247c3d197632e87932952831d0ba25c77c18fe154d8ed8
+
+Count = 227
+Adata = ed438e393e0e37629cb25044ae89de9fd0d42d60c1a3
+Payload = 7043c67726870bb5816da925925bc2722478311c8a606cca
+CT = 23baaee18f74e69c28637ea2950fc0fb04b7618b48ec25ac234fd0241d00f3890a23ccd0bf16dcbf
+
+Count = 228
+Adata = 1013946815001a2c08acca4196e0d6668ffbb3883cf1
+Payload = 695e9712dbbf883e9bf8af9188bd01fc631968928258168d
+CT = 3aa7ff84724c651732f678168fe9037543d6380540d45febaf43498b0c3f70c119f82d5812db940f
+
+Count = 229
+Adata = 44cc9b2510680c4d73f1938c77de21242c8ee790ed7f
+Payload = 67ba90d22c6bb5f649bc0c505c5ed23a299882559a3bf520
+CT = 3443f844859858dfe0b2dbd75b0ad0b30957d2c258b7bc46db66dbb03a4c943ac089ed11eb214bbb
+
+[Alen = 23]
+
+Key = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Nonce = 451101250ec6f26652249d59dc
+
+Count = 230
+Adata = 7cc9c51b69f98a06391ab32742fb6365e15106c811fe8a
+Payload = 065ef9eeafbe077c1c7049f43eb0d8999708e8609f214d5c
+CT = 990065322a438e136860f7b019807e9feff52a642bf3d44a9163fa7a867f04cab6f52dc250070f31
+
+Count = 231
+Adata = 7bb1bc069a783d45d51d8ecd0a53ab7a386fa1f5ef12a1
+Payload = 69b2b056f2265e707d3e31e68bff6a060544c8a737b2a9b9
+CT = f6ec2c8a77dbd71f092e8fa2accfcc007db90aa3836030affd33dd9155619fb040dcd6038c7b7367
+
+Count = 232
+Adata = 0dd220919d0eeee3b7cec36c47e376b778583b38bf61c8
+Payload = b98d79aaa4c04171398c7f1189497acaa7546ef068bc7a3f
+CT = 26d3e576213dc81e4d9cc155ae79dcccdfa9acf4dc6ee3294fcba5a886b1f33cf1cf44618d28f01f
+
+Count = 233
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c112479
+Payload = eeaeb773ade5fb2d27b50bb892916333e0b123c6e3ae5bdb
+CT = 71f02baf2818724253a5b5fcb5a1c535984ce1c2577cc2cdeafe2c670eac203d5e90b9d520e7a618
+
+Count = 234
+Adata = 614b0ac4611b6c6d3b4ed089510dcd2215567bc3789f85
+Payload = f2198e1f91fde2672a1ef60403c0d175f366b6780ee9f1c2
+CT = 6d4712c314006b085e0e484024f077738b9b747cba3b68d4f0388746438e83b731b5588fef53f1f3
+
+Count = 235
+Adata = 866fea4483d4e903566844e31c24283571832dfae32c74
+Payload = ba37617342b4eefd4bdce8fad30c4751b206d47814973b3a
+CT = 2569fdafc74967923fcc56bef43ce157cafb167ca045a22cfca81f8b36d16698a600fd701f2c6424
+
+Count = 236
+Adata = 9d7546f7e8b949c539d21a357f81d0151e278d0bf2c5a5
+Payload = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f6
+CT = f6f3563424142a9d8a8edc1d384bea5d612e770ac247b8e04c15a6d292c7ed2f31cf9512435ec7d2
+
+Count = 237
+Adata = 42b692048c8b3cce1b5e83f4f33232a7d7d0bc20695e7e
+Payload = e0753d4248643642c7a96404de8d76c9d80527b659ec6d31
+CT = 7f2ba19ecd99bf2db3b9da40f9bdd0cfa0f8e5b2ed3ef427a2ad73179d0314b5fe52dd7217518cb8
+
+Count = 238
+Adata = f1dfb6fdb31cb423226f181c0988a52ee4015aef4536f4
+Payload = 79ba959c7221b293e2115f538d9394c64284c756563c04b0
+CT = e6e40940f7dc3bfc9601e117aaa332c03a790552e2ee9da69ccc5ba1caf933b80bfc6f281109688f
+
+Count = 239
+Adata = 8eafce9ba466fd53eb87f499d7c76bd486db0e90a3d281
+Payload = e1590206717a708cad9cca7d23a3b8ee5f7fb7786aa3be47
+CT = 7e079edaf487f9e3d98c743904931ee82782757cde71275173271ec36d92fff34609169f579c8f1d
+
+[Alen = 24]
+
+Key = ef4c1d2314e671f666cc6667660f1438a293208c7cc29b412d81277f0a635c91
+Nonce = 50b23b052922366c25dd40e348
+
+Count = 240
+Adata = cd0522ebe1fed82465277d1c10ae9316a98b4469be63b180
+Payload = c99c3e79125b6fd95e737326a842424eb6c6ecea4c0475c4
+CT = 76df4be4ec8373864399acda11294b220b9f7c3a7d2b3660b25764e40ac6a171e7e6bab4fdee4288
+
+Count = 241
+Adata = ce5bf070678cb07e963263b1562ff79311144addb6e4de4f
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 519d742d71422c63c2fe1661c32e7a45cf9f7f2290f4454ffca49758d17f2073066b82667eae6ce3
+
+Count = 242
+Adata = 07175be2475cc735c9a3c1140895277378debf8fb1c87c24
+Payload = 6d5579aaaf8737b01620424f3ddeaf538f10dfad094e5ec4
+CT = d2160c37515f2bef0bca9db384b5a63f32494f7d38611d607c1d64d7e9de47a6ad7878283da9d870
+
+Count = 243
+Adata = c821a8d4bab9d993c20dd206955304a55968e6db5ab6480d
+Payload = d0628b2027f06c246497977d05f211b2c2e302d5b82700b5
+CT = 6f21febdd928707b797d4881bc9918de7fba920589084311adc2bb471862d25cfe25e66fedb8e28c
+
+Count = 244
+Adata = 68439bc9d176feeeb4119d00ed5449dfefb72b5a582bfd97
+Payload = 6cc9749f48c61050e421afa3a10ad3dd3aa02cc3f8586915
+CT = d38a0102b61e0c0ff9cb705f1861dab187f9bc13c9772ab1319a493abc947945f1312395ea98d937
+
+Count = 245
+Adata = adb262c924942e4e1964e9d97c6a8c159fbf9bfedc5ff296
+Payload = 92d50736466e64e6225962e76bd90da824f716a3301a1a90
+CT = 2d9672abb8b678b93fb3bd1bd2b204c499ae86730135593421d0602d29447ba6b24a67509eaee1e8
+
+Count = 246
+Adata = fc7b08707d3c3dac7689ec18088ee6502ef08d3ffbff38ed
+Payload = 87c7ac031fd63e4c83280dce6b68a92dfafb6ea19388fa9f
+CT = 3884d99ee10e22139ec2d232d203a04147a2fe71a2a7b93be52a2eeacb1f023e849161b6306b6cfa
+
+Count = 247
+Adata = fd43dfb66041b117f2ac54c94f7b6e2677860864d9494175
+Payload = 6b53c46266b2f4284d8fe7f0549c98977344d67e178e9a8e
+CT = d410b1ff986ae8775065380cedf791fbce1d46ae26a1d92a0d8c5b1e96b21460e0b5414639abeb0b
+
+Count = 248
+Adata = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Payload = 8e7d8a44244daa7df2b340993e32dac50e05d7b2e103be98
+CT = 313effd9da95b622ef599f658759d3a9b35c4762d02cfd3c1c97260d20797d374c595cbc2ff080bc
+
+Count = 249
+Adata = 9895b24d12b004b215583eac70a95f4fba7442164f35c57b
+Payload = cec07df916ffb7a453d0eb588b7462096f22874bd5abf814
+CT = 71830864e827abfb4e3a34a4321f6b65d27b179be484bbb06cd287afcbdbc5531f11246080b22677
+
+[Alen = 25]
+
+Key = 8544808e8fbf8c3a5e1d4ca751d4b603af9fe119eabc6923205815e0e748b7e7
+Nonce = b44a58724596b4d8dea827c1a0
+
+Count = 250
+Adata = f5b2c88f5232c37273b1e66aa31cfa7201e33c21d60054d025
+Payload = 617d54fc6a23601c79e3984f93bfc2d151fde420863206b3
+CT = 57b3414db48982c6567265e1e0173bf38fdfaffe4461fbebc1411af83237c0f9eb0bfe8ed914da66
+
+Count = 251
+Adata = 8fabe14dcb3aa2fd28281147c326e98ad699ca7997f03a105d
+Payload = 337290d0b4ce1e87afc3cf01d6c98f8c17a4603120dcfcd1
+CT = 05bc85616a64fc5d805232afa56176aec9862befe28f01897ed6e23720b60ffe54bbb9f7ff371008
+
+Count = 252
+Adata = cf193eb3d755cb8e06c5be2334b5c8b7a22b6524d46d547ba3
+Payload = 01ef7ac6470aa02ccd8c1712827e52699d05751b78e4c5a6
+CT = 37216f7799a042f6e21deabcf1d6ab4b43273ec5bab738feb6aa6b284e7720acbd027a50317f816a
+
+Count = 253
+Adata = b4cadb5f9cb66415c3a3b71421b926f147566a174160a0bcc0
+Payload = 64fb9322210fb7d8da8e762498b233b0eb172c91231c50cb
+CT = 52358693ffa55502f51f8b8aeb1aca923535674fe14fad937058e9c0164ca079668097fde19e5302
+
+Count = 254
+Adata = 48400d76ff882d6d5129c8674acc71f445356c9db9c91f8256
+Payload = 291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4
+CT = 1fd4b1d21a105eac9b37075c91d66d2386495116fc18fbfcf988611d5ce0f65b217bb4787bf59bbc
+
+Count = 255
+Adata = 749d369d837002ad33feb8aa22c3f68705eb4872e1b8f85a7f
+Payload = 141cdd7f964a78815be144a785c6a2a298c54230e73039e2
+CT = 22d2c8ce48e09a5b7470b909f66e5b8046e709ee2563c4bad6251a5fd375a48583a6d0f8eb75cbb4
+
+Count = 256
+Adata = 80214108b16d030feff6e056c9a07a00a1d5e3ebb07abd3f4a
+Payload = fa2441cb7f9d072b8a3f1a496b2be6728a38b94a4f44c9be
+CT = ccea547aa137e5f1a5aee7e718831f50541af2948d1734e6af1dab0f105414293cb130bea285fd6a
+
+Count = 257
+Adata = 8b9fabe29718a8f297c9bf6f199c80bbc71f94eb3034a11ecb
+Payload = c8ce88ab40b62229223d46cc44f21bb39cfef27aa9fdccad
+CT = fe009d1a9e1cc0f30dacbb62375ae29142dcb9a46bae31f51cc3f7640a42460be877fb7059a3ed61
+
+Count = 258
+Adata = 8812f28a0cd5fdaa226fdd44ed857241007377057be3bea577
+Payload = cf59f75ca4d6d216cf8862b44b5192c382c140f862def117
+CT = f997e2ed7a7c30cce0199f1a38f96be15ce30b26a08d0c4fbbe0ddd2e7f4aa2024b3fec9281b6cac
+
+Count = 259
+Adata = c8f05e96d703a4850bae1421ae9ff3aec7531baf9b899dfd75
+Payload = 4eed58f381e500902ba5c56864f6249d191e14d1b1fad3dd
+CT = 78234d425f4fe24a043438c6175eddbfc73c5f0f73a92e85e5df1e5e96bb84f730fcb253d468278f
+
+[Alen = 26]
+
+Key = e19eaddd9f1574447e7e6525f7fd67e3b42807e44fbb60e75d8c3e98abc18361
+Nonce = a8c459ce0223358826fb1ec0f0
+
+Count = 260
+Adata = ef88f4393d6c1e7b7be55a12144209ee051bb779e440432721ef
+Payload = b3b0de10b7c0996662f1b064e04e528b7d85ca1166985d33
+CT = d63e6082c95c6c5ff2bc0771321a4f883ef61cff7b99e0ea8a20a1abe7c842ebc08c8c81a2743c81
+
+Count = 261
+Adata = a4c891c9dd1fcc982c35bc74cfe71651bae424602519672b466d
+Payload = 4f0b40913f07269550b7b06ab9027a4d9331f8ef98a45dca
+CT = 2a85fe03419bd3acc0fa077f6b56674ed0422e0185a5e013845e2d6de83ab729dd200a21088a1ec3
+
+Count = 262
+Adata = 4db5730cb9794f3b1facc9d6738115d02ba9f27ba02330fbb856
+Payload = 841e032773d58bc72a3237bc9b24c61b9efdd850fc2ea605
+CT = e190bdb50d497efeba7f80a94970db18dd8e0ebee12f1bdc10ed272c732247a696a608ef67510f9c
+
+Count = 263
+Adata = 471a900ee49f2cfa1d3eb37c951d810c349364d4cc3b5b64fc47
+Payload = b4db42e523e65557157b93dc0281601f7997e6731543a914
+CT = d155fc775d7aa06e853624c9d0d57d1c3ae4309d084214cd15f0df52e392c37ec15f7458469dae84
+
+Count = 264
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5
+Payload = 73e0ed35c0e847188e607cde46586eb9e237fbdc5d59163c
+CT = 166e53a7be74b2211e2dcbcb940c73baa1442d324058abe5421433dafea2b5484ba87b5050e1fb49
+
+Count = 265
+Adata = d563f5c048a1b45265182b99ca7b9004fdc73a9cb07806dd44fc
+Payload = 4f7669caaedee961dbba6bde9d09fee1a20eee55baaf98f5
+CT = 2af8d758d0421c584bf7dccb4f5de3e2e17d38bba7ae252cdf91749fe3cd52a9431d9a847a8c2a9a
+
+Count = 266
+Adata = d301a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a
+Payload = 154454fb74e9565c56775a8e4654f75a38b954dd28c4e939
+CT = 70caea690a75a365c63aed9b9400ea597bca823335c554e07563d37846f5185bb44d71be1ea6a73c
+
+Count = 267
+Adata = f74b48d168f77fbd3429728c0b168ecbd854264eaef70b74fffb
+Payload = 716b371857e68a17b20ea06651cdcfd4560a741830ca8a13
+CT = 14e5898a297a7f2e224317738399d2d71579a2f62dcb37ca55e93bc2d3f05d7016747690fb920e12
+
+Count = 268
+Adata = 3a257ce3592a8f88162f0bb4ecd5db3bb79b54ab17b0bbc61506
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb39303b4135269
+CT = aa55cdf1e6c6552366b55f36afebaa845dc045eda912efb01c46822f839f09c41b7aa6dc06035c93
+
+Count = 269
+Adata = 21916ebeca9e66b77cf55d1cac80a4c85d8b6b014f268ffa73ca
+Payload = b4b67ac551d1966caa20d951351387f384c2e5d81a76a92c
+CT = d138c4572f4d63553a6d6e44e7479af0c7b13336077714f54f8e77600c5bbc6d028fa25ba61a1719
+
+[Alen = 27]
+
+Key = 9498f02e50487cfbda1ce6459e241233bd4c4cb10281dcb51915dbc7fb6545c0
+Nonce = e3bd4bc3a60cddd26c20aa8636
+
+Count = 270
+Adata = 70cfcb828d483216b46c3cd22e2f9ee879e9e3059b566179b6e16c
+Payload = 0d16cc69caa9f19b88b05e151b3d26accd018ca4a5786a80
+CT = f1c4bedb8d6f91676881daa37656a7e6402f472735b04a0f1f8332f4236437737438e7aa1b5100c7
+
+Count = 271
+Adata = e7e5779282db80f424dc050b2c1e7754b2a5d3a8beae77beb74e34
+Payload = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c
+CT = e85f94f2b407756d46c94172eb5944b1f4fd7c625e3135138be2f6f356c2eb401468be15104e7763
+
+Count = 272
+Adata = d17e8189a94a559b07be9549f73d653172740e8e978f5b0a38ad43
+Payload = 00a23b25bca7c206edd051814d81083db1cd00048ce8ead5
+CT = fc704997fb61a2fa0de1d53720ea89773ce3cb871c20ca5a9646f2b6c2455603f1a6f20ea5a4611a
+
+Count = 273
+Adata = fda37ff136895de7ebeaf81e701e5751245201baed2e13d7e1b591
+Payload = a89409b0977f60a029dc4c1560ba6dbe7c65b068633acf74
+CT = 54467b02d0b9005cc9edc8a30dd1ecf4f14b7bebf3f2effb303fa5d8321241b1c9e18a5909d6e428
+
+Count = 274
+Adata = 9c179fd0d6277a5e073e77dd6abb4cba00ad9c9932e6c002b951c7
+Payload = e16c69861efc206e85aab1255e69d6d33c52cf058dec9d0b
+CT = 1dbe1b34593a4092659b359333025799b17c04861d24bd849e8cb01db1da077502814db1610662ce
+
+Count = 275
+Adata = cf5703228e615428d3d3805e428e754961d205c5aa0297ecdea71d
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 9ed11e0c94a00d79827cb97fac9fb60fc6b47e43ac28fe1d40a02a49857d7b280330b8105efac854
+
+Count = 276
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb796
+Payload = 790ac86c5e9d8ce8cbec1dfb7e4fc4dca3d0b1039adfe585
+CT = 85d8bade195bec142bdd994d132445962efe7a800a17c50a5ecfa9dd03e2db70aa212ee7dcb573fd
+
+Count = 277
+Adata = 96f0b7cd7439721d4c9cc4f69585f8c90a95bed8fea22150efffba
+Payload = 3cfacd61ea3398de20ca6bdb00e81af482320614bdfb8642
+CT = c028bfd3adf5f822c0fbef6d6d839bbe0f1ccd972d33a6cde17a7a0cd162945a3616892e101e3e93
+
+Count = 278
+Adata = ee71e53d0b4eef82575c2bd38d7bd21b41fabe58c6f571954fe159
+Payload = d75c153e34ae1c6d1fcf5b1052190d8882041e1f9c5490e2
+CT = 2b8e678c73687c91fffedfa63f728cc20f2ad59c0c9cb06d15fadc2d79841d230cd55c04379f22b4
+
+Count = 279
+Adata = 18a4aa894861c7720ddb43809c3d2ed2af2f1bfe8f9fd4f872c14c
+Payload = 0e728056c7c64214be8f1f1727408d8cca8c42e2ac7bf67e
+CT = f2a0f2e4800022e85ebe9ba14a2b0cc647a289613cb3d6f1b229b9bae4634eea6b723f432e19ae55
+
+[Alen = 28]
+
+Key = 3ac7d5bc4698c021e49a685cd71057e09821633957d1d59c3c30cbc3f2d1dbf8
+Nonce = 54c8ff5459702aac058bb3be04
+
+Count = 280
+Adata = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c049dd1ec
+Payload = 89198d3acc39b950f0d411119c478c60b2422ffe7e26e00b
+CT = 7717b8e4447afcea1eeebf3e39ffdab2f52828e7931ef27e475acd27900478f09fec1f479ab3a7c8
+
+Count = 281
+Adata = 9a04820205234795ecd540b6a0b2fbd0b19f18106c42f374a2b98425
+Payload = c0f61950f98110db4226e269cf197c7e2794c5b87ad68cf9
+CT = 3ef82c8e71c25561ac1c4c466aa12aac60fec2a197ee9e8cf7b7ed6e8ede6ef5a73b484bf13b3424
+
+Count = 282
+Adata = 0e4dbd167da0240298f4795102ef18ff9a8772c6fd73b3374cdfa30a
+Payload = 7960dbc9136880e2eea7956c3271adfe2aba7dca53da917d
+CT = 876eee179b2bc558009d3b4397c9fb2c6dd07ad3bee28308e47d08ea0788f7ca0ecd846689c8027a
+
+Count = 283
+Adata = 2de4291068a5d290b599a73c6a8ecff4f9fd6c9cc48f14c233e18581
+Payload = 0c5d7055bbfbd2bc213cfbbafa763b71b1fde6f4de96fa59
+CT = f253458b33b89706cf0655955fce6da3f697e1ed33aee82cd081f66b1c7b70718dc50367c3da6792
+
+Count = 284
+Adata = dedeb714f555575fcedbd9de8171484090e6466dd4fba3c6b7c42eae
+Payload = b5654edcc8f09e4f80d0258c9376d7c53fb68f78d333b18b
+CT = 4b6b7b0240b3dbf56eea8ba336ce811778dc88613e0ba3fece672883438da186741e6c542b3f805d
+
+Count = 285
+Adata = 03d340904ace1cd52d4b72a96d96afd77aee68ac3936415005ed0d56
+Payload = d796f3409a7eeb896c3d4ebef46e9c6e553aab28b1cc4a90
+CT = 2998c69e123dae338207e09151d6cabc1250ac315cf458e5cf58d4a5552bc8ed1b1dda46703a256e
+
+Count = 286
+Adata = c67f9aa8cf1be3b4377c30c175d33ab2af390982c6a015d99209acdd
+Payload = e4dd279a79a381c68de777df941a4779e50a1381c8aa9122
+CT = 1ad31244f1e0c47c63ddd9f031a211aba260149825928357f95cf2b57e06de4d01bbb6c0e39f37e1
+
+Count = 287
+Adata = fef1b2ccd661b9fac85ba005addebdf8317ab104920549d3a490a21a
+Payload = bbf0c267d952aeb6f810601b9cf1962a92dcaba7273e6902
+CT = 45fef7b95111eb0c162ace343949c0f8d5b6acbeca067b777589cd12984286af98908db88920323c
+
+Count = 288
+Adata = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b6349c2fc20f
+Payload = e8b13a263e0c4fb5645e500e88ab8074ab7d92e5a8dac6aa
+CT = 16bf0ff8b64f0a0f8a64fe212d13d6a6ec1795fc45e2d4dfee8fc441da990dd92c0caeac9d956699
+
+Count = 289
+Adata = 85e5df4ddec99f0bea14b3338b2eb190ab6584f5253c6c2ee3064637
+Payload = 067de2869333ed22c7b63ed7eeba1301bbac69b0d430adb5
+CT = f873d7581b70a898298c90f84b0245d3fcc66ea93908bfc0d502f5434bea8c3c13ad5422ff90e218
+
+[Alen = 29]
+
+Key = 948882c3667caa81c9b900996e3d591e6fcb3d08333eeb29911e9c6338710c17
+Nonce = 43b0aca2f0a9030f90559fa6d3
+
+Count = 290
+Adata = a516ca8405e5c8854e667921b5c5e1968bdd052915b55ac9984b7eefb3
+Payload = 8b9130b0c3c15366831bbb19f377e3209a8dbf7619cd09bd
+CT = 4646b2acdeb11174171da23999cd54e297daa32bbc13d30512e57c576b315f48c11877178389aaa0
+
+Count = 291
+Adata = db3121ea71294983b185207a9d8de3e484a66c0431bf07c962eb82977c
+Payload = 7f369bbc99b6f08049eeb43566269a174829d4dddb05cb9b
+CT = b2e119a084c6b292dde8ad150c9c2dd5457ec8807edb112366775e693f93af6575dccc7903538065
+
+Count = 292
+Adata = 1651cf38fd9b2da65ebb4922b97dcb861128eeefa060d6c1c94b25eb4e
+Payload = fd0900b5fa72e2fba43d611bad25de40a3507a5cc5d186c7
+CT = 30de82a9e702a0e9303b783bc79f6982ae076601600f5c7fb70d8de40c2068de96a274d3b5086b5a
+
+Count = 293
+Adata = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12cb3047625e
+Payload = 36318d80c02a1da41ef1652d9a752e155526b5f597fba226
+CT = fbe60f9cdd5a5fb68af77c0df0cf99d75871a9a83225789ee7da096d2fb28f20f64a000fe93e96e2
+
+Count = 294
+Adata = 0680d5bacefa2ab14aa12b0e517a1432862d4215dc72dc4d5ac6b96c1c
+Payload = 7a29aa2994d11215ab3ef3382b3db6ed581164a235c4b1d1
+CT = b7fe283589a150073f38ea184187012f554678ff901a6b69b88748a2de31261534cdb2237565bf8a
+
+Count = 295
+Adata = 9af701f0a9de52309267289bd170fb97c03c131c0a169d736137ff3d74
+Payload = 3542fbe0f59a6d5f3abf619b7d58b199f7caff0205093f8b
+CT = f89579fce8ea2f4daeb978bb17e2065bfa9de35fa0d7e5330c003eb65ceedc98ae4e38ef341ee47d
+
+Count = 296
+Adata = dab7845fb7ead205569475753c7e26540c09d3a74312f2de25181511f8
+Payload = 83c15520d9541c86b3dd809ede42de22bbb2b75ff18a023b
+CT = 4e16d73cc4245e9427db99beb4f869e0b6e5ab025454d8835c2fb596d8ff6a863604cd224fa3be42
+
+Count = 297
+Adata = a844d6dbd05545ecc736994dc9fc2260c5ab63ed6ffdc40b915f8744a1
+Payload = 793a188fa3efa32f41d6e4c5b42353b95024117d546c79ca
+CT = b4ed9a93be9fe13dd5d0fde5de99e47b5d730d20f1b2a3722ac782e2cd8ecb06172eef2cb9b0e331
+
+Count = 298
+Adata = f9112503884615c0e8a1d8414724b0d19298988f393a27c436b2b6734c
+Payload = 6b237444fb0e1f4150701546c4cb24021c5edad30d9b31dd
+CT = a6f4f658e67e5d53c4760c66ae7193c01109c68ea845eb65f814492b42571033f4dffc0282ea2f51
+
+Count = 299
+Adata = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c2c94d3a5b4
+Payload = 6342312e8a72f71f2e5afe04cfcde4d60a41556111752103
+CT = ae95b3329702b50dba5ce724a57753140716493cb4abfbbb75999099df2de6e436bd99f0341423f4
+
+[Alen = 30]
+
+Key = 3bf52cc5ee86b9a0190f390a5c0366a560b557000dbe5115fd9ee11630a62769
+Nonce = f9fbd02f28ecc929d369182752
+
+Count = 300
+Adata = ebf0b3e3199a5c3773c761c725c7600add5f9d8321c9f8e5e5fd1c7a5d2f
+Payload = 094b538110495e938b08cf748a6bcf3e0c80ff9c66570237
+CT = 4d8b53016fc8bc9677184c0fa15bbd3d671b9366d82ecb67f8562eadcdcbcdbad1299bea1523f5d2
+
+Count = 301
+Adata = a865b88d512e485ab3f2844c29e6dde0cf1151efa9ad3b3021d06fffb74b
+Payload = 23edddd8732cdbf03af08162f0e4a24c9222bdbb4549c663
+CT = 672ddd580cad39f5c6e00219dbd4d04ff9b9d141fb300f3359ff77cf0962455b3539dbf91f3077cc
+
+Count = 302
+Adata = 16918dbc785d94a8f1720c5ad234dde860219874c9fb076a5c290903f85b
+Payload = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0
+CT = 535828ec4840b24a3cc7c35daac685047a743c977247e0806dbed76d94c90595b49d50c84c3efc76
+
+Count = 303
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918
+Payload = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32
+CT = 49c2770fef2086a105bd2aa754e23ce8ff8b0598aa61266248fbe60c146056e5cb01268403e4b9f5
+
+Count = 304
+Adata = 2de5222a0609f058f60e9e581b6e4f0ddebed84fc8302c8e985d17b89241
+Payload = b0c3858231e284af6d231f043b95772f5e7b16a34ffcd2ec
+CT = f40385024e6366aa91339c7f10a5052c35e07a59f1851bbcacff35df1ec942b43eef5aef980cb038
+
+Count = 305
+Adata = 3fc7453df038a92829dc103d44b63ad097d7cd7f9ae7996547012090c7c4
+Payload = 319f396cc02834f8e69d65f77496d0eb31ce1a7b7e324820
+CT = 755f39ecbfa9d6fd1a8de68c5fa6a2e85a557681c04b817091a93f5fc28e5f4f351cfb888da763dc
+
+Count = 306
+Adata = 18f1e92bd3c4a597ed970911d03a78ff9a6790147c9bb0ca5f23b70cce7a
+Payload = 25550c03f8fa02b3781330f96e0fdc58681b0c0bc5e83fe9
+CT = 61950c83877be0b68403b382453fae5b038060f17b91f6b92c6a90ef2e9a969ec0576fae1d126a85
+
+Count = 307
+Adata = 09ecb2406054716418ff3600c3c5cacb0845a377a2d80542abc36ec81bb1
+Payload = 210ff7975e08388b9a46eb732230e3a3856a497549b5eb49
+CT = 65cff7172189da8e66566808090091a0eef1258ff7cc221959fd6aeb047200907911621e8756b45f
+
+Count = 308
+Adata = 62d515bb0525b565a6a3613ae20343c8da7424c8368e8cad6a862b7d37a5
+Payload = 5d867265965bb2aafebb0691de9e157a24066d06fe3cbd7c
+CT = 194672e5e9da50af02ab85eaf5ae67794f9d01fc4045742cc4db6d5fd910c83fd77aefba3f7665d8
+
+Count = 309
+Adata = 00617ca141e55b045a188e4934caf6db63d4577f634db92c22010e1cbf1e
+Payload = 396b27afd16a1081f37bbc1f742b549f5f68df799b93083f
+CT = 7dab272faeebf2840f6b3f645f1b269c34f3b38325eac16fdf5f21f32cbe5d272004f1c104cbcae9
+
+[Alen = 31]
+
+Key = e45bb1730d0d539aab3805350ac986540de9f0f6c239ee70395c291397b70309
+Nonce = d5c7824af715bb7822b6b340fe
+
+Count = 310
+Adata = 860f4a09ad8b3d345c2aa18ffb803f0bc3b734a4d047a1437701a5e3d95288
+Payload = bc8b3bc48c7a88c9fafde258b6ccaa9d4f0d018703d63871
+CT = 95f083ad6bbaee6ab540fe023858f8baf25e333fd3e89c00e678a392d228b210dc5c991905dacf3f
+
+Count = 311
+Adata = 8a84b57915bdbe7bf5a1c1a426512b3c178d883251cc46c95a8bbc8ed9e56b
+Payload = 9499ea48edab9bc21b91dd614f04934ca20db8630622f481
+CT = bde252210a6bfd61542cc13bc190c16b1f5e8adbd61c50f010fbdd3b305522dae6b652322d89d9ac
+
+Count = 312
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3fbd1219a21aaa84044c4f23c08f5d
+Payload = 73843a4e9e7937fed24bb1fae15822213b1aa86c07f1b5d1
+CT = 5aff822779b9515d9df6ada06fcc700686499ad4d7cf11a08b6b08548e794eaf85ad9f5de80b1c00
+
+Count = 313
+Adata = 61bb196b212feab645f05a8aa1986f6210a384c15bc749245d840b3565fb36
+Payload = a8e24266e5981b2ed14213a29f961cbbf7f02f63a33c987e
+CT = 8199fa0f02587d8d9eff0ff811024e9c4aa31ddb73023c0fcc73643a7ee9291e15137d7046a92f3f
+
+Count = 314
+Adata = a49c2df94ba65107f375ce1c53b72406143f6bcd270945de5b7811682fe361
+Payload = 3e3c402caeca41687d12897102e04312edf7b8c7d8567a22
+CT = 1747f845490a27cb32af952b8c74113550a48a7f0868de53204438662ea82f423a69c6e4e3c0623a
+
+Count = 315
+Adata = 7c48480e9bc87ba299e03899698b2259eef150ee0f2efff40a5583b80ab484
+Payload = cfa9292b9052ac6bb863205d3c0dc2d9e20d2ba6a680d2ed
+CT = e6d291427792cac8f7de3c07b29990fe5f5e191e76be769c6ea00b9cd881e3f4b1e838dfa31f6560
+
+Count = 316
+Adata = 5cf9744090366d828b477dc890eab8ebebd44f6aeaa5b101291bf67d12867e
+Payload = e0fe4e139ab0deb4fdf2145b719f35c50b869e6cb20608b5
+CT = c985f67a7d70b817b24f0801ff0b67e2b6d5acd46238acc4c59b3b87d722a58cd1de58f3963d12b3
+
+Count = 317
+Adata = 761d74be5fae170a1bdfa16081b44c1e49972e15ce0818df1390bf7204f619
+Payload = 665fdcdf55a1231e9912562eaa5a5011d69f6948e29e3f8f
+CT = 4f2464b6b26145bdd6af4a7424ce02366bcc5bf032a09bfe158759886124f1f0ce8147c94f4e7114
+
+Count = 318
+Adata = 9815353b69d0b4effa52cefff13703fa71a6296f9cca0f02568661be4b64cb
+Payload = 7b2d52a5186d912cf6b83ace7740ceda3f5f443530c5a49f
+CT = 5256eaccffadf78fb9052694f9d49cfd820c768de0fb00ee6310a79c9932456dbc00515b264f3168
+
+Count = 319
+Adata = 69dd1a050c8d79dafbbe3403af4dc1f070b9b2b980888aa796e6cff68d9060
+Payload = 3cea5ff50167c5641066852fd00061df35b1f66bedb894b7
+CT = 1591e79ce6a7a3c75fdb99755e9433f888e2c4d33d8630c6da7e97f9984a7db3b93aefb4316d9acb
+
+[Alen = 32]
+
+Key = 2e6e34070caf1b8820ed39edfa83459abe1c15a1827f1c39f7ac316c4c27910f
+Nonce = c49ccef869bb86d21932cb443b
+
+Count = 320
+Adata = d37e35d7cdccd9824a1ae4c787819735e4af798a3beb49d4705336d6496853ad
+Payload = 771a7baa9cf83aa253349f6475d5e74dba4525307b022ba7
+CT = eebac2475004970071dfa2cfb855c4e78b1add8dcbccfc0bd6b14027324b657a56263df148665393
+
+Count = 321
+Adata = ab22bc22bf2628b0e0ab245c3db2fc5128d13a011c2cc9b9fea05a79a3410704
+Payload = dad95a4b4d3754613f0542caa62cfe4e375dfbdd369ec32e
+CT = 4379e3a681cbf9c31dee7f616bacdde40602036086501482a8c810b6944815fd2e434193520b1d5b
+
+Count = 322
+Adata = c48c5aacf701137fc40fd0d3649641aaa5be427ceee702cf7ddf6408f458a581
+Payload = 3f28df9263e473be648fabad163aa4142b633388b16d8392
+CT = a688667faf18de1c46649606dbba87be1a3ccb3501a3543e8aa447b79284c588bef50b423de97908
+
+Count = 323
+Adata = 477c2484cf5c56b813313927be8387b1024f995e98fc87f1029091c01424bdc2
+Payload = f83107b50a1f192ed45cc43fa80e6b519bfd859173ea9ee9
+CT = 6191be58c6e3b48cf6b7f994658e48fbaaa27d2cc3244945d4f4a413eb3ac2c474134995d4db9a16
+
+Count = 324
+Adata = 143bc037f1d0bd4ec16825c58cb3796bf8989200d27bda9beabbbc49247f59f7
+Payload = dfeb324ba459ec4a5c54d2534e98002412e67db19cfc66bb
+CT = 464b8ba668a541e87ebfeff88318238e23b9850c2c32b11756a3fb2e06734b28fbd57942a609d914
+
+Count = 325
+Adata = ffc416f1dae4e43c1a01339a604c44d6a0f25ab9ca3978c6aacb6d270d510ee6
+Payload = 0765949e6f22c422ebd47dc1ed73f1b849d7a058a1656fc2
+CT = 9ec52d73a3de6980c93f406a20f3d212788858e511abb86edb94280d3c4a1cd8cb00705f60ae36f2
+
+Count = 326
+Adata = 6090b596b4082ec6926576137f6561cf13916860ad1cfc43650d1b5142a12041
+Payload = 6db320cbe76bc5b8cee9ef89aca11765571c6c501993195a
+CT = f41399262b97681aec02d222612134cf664394eda95dcef612caca26cc3bbb289da3be0616b3445f
+
+Count = 327
+Adata = 178ba75adb7c5bea6769270bb3b4f6ce208d4a786913d3ced7bb4090b5f65544
+Payload = 0875020959ed969cfb38636d1d5aabce9658b00171a7614e
+CT = 91d5bbe495113b3ed9d35ec6d0da8864a70748bcc169b6e26cc8c665289d907628eb0e299c2d411e
+
+Count = 328
+Adata = 90f0474dca998916075b1b1428df14d90be05491bb8d5d88e32e65ec890ba9d3
+Payload = 4f89ca6ad371f86a6e073ec12fb1b928bb10d6639233b918
+CT = d62973871f8d55c84cec036ae2319a828a4f2ede22fd6eb4f7e481607a2a0529f9cda1d5903325b7
+
+Count = 329
+Adata = 5ad8dd40ecdce52d5b30424ca0bccb666f34f66b0c9a4c1260051ac04ca06aab
+Payload = fe2009d0a4a1711b83057b948cd0b174a3a042fd97579ab8
+CT = 6780b03d685ddcb9a1ee463f415092de92ffba4027994d140a1b9ba2bfe5bf778b859f0ff0c29a67
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT128.rsp b/lib/crypto/test/crypto_SUITE_data/VNT128.rsp
new file mode 100644
index 0000000000..b796541cf5
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT128.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = c0425ed20cd28fda67a2bcc0ab342a49
+
+Count = 0
+Nonce = 37667f334dce90
+Adata = 0b3e8d9785c74c8f41ea257d4d87495ffbbb335542b12e0d62bb177ec7a164d9
+Payload = 4f065a23eeca6b18d118e1de4d7e5ca1a7c0e556d786d407
+CT = 768fccdf4898bca099e33c3d40565497dec22dd6e33dcf4384d71be8565c21a455db45816da8158c
+
+Count = 1
+Nonce = f7a5098b2a4d92
+Adata = bc498326755503ff25d02805eb3517221b54eb4fd79af0fcdf9312b2a9ad95f7
+Payload = 3e2144e2a381b718962a77e167778bf579957a8fae29612c
+CT = 98ce91033fabaa8fe853d347be6cbe5de102fdccf042e7be697b41c9a69acaf8386140ee6e36f406
+
+Count = 2
+Nonce = 732d2dd64b4a25
+Adata = 495b03df82e317e4f351c5323d17c673f4c77856983179d7c7cb75c2b0573c72
+Payload = 4bb0d170bdcc70fd18f19605cf9c6181082c4367f1e6fbce
+CT = 9bd9304259962448fa8487bc15d950303621213afd88f1e32d442ff663242fa269c4a742a220edc5
+
+Count = 3
+Nonce = fefd3ac595428f
+Adata = 91ffb6be8e129cef9189f7e0fec8e937afcfc6083b6a79a778a724bb3e8d0794
+Payload = 9e8c4f1292e8d7e5179b34ae5d2ba2491d7754acc54bb91d
+CT = a5d012b3062cc93b831860d76539169c88854b85550c67fc564a2f1cb7d77e0223287740d5ff9003
+
+Count = 4
+Nonce = e14d81ee3b873a
+Adata = ecdc5249ceb48e8d5a4483043921c00c1acb1843fae00155a28f3a127150b1c4
+Payload = f99e23288e6b5ae85c14610994d90d5fcbcab62b4ed1333e
+CT = cc4ee711d0202deb58664e00cf0cf70b737f48ddadcefd6cd217fb611daeb66fa2d8e1bd43cb2131
+
+Count = 5
+Nonce = 2cbeaba94dbbd1
+Adata = d129674c6c91c1c89f4408139afe187026b8114893d0f172f16469b183fee97e
+Payload = 1b42cb685bd462fbd40e0273a81c767aa81cb43f17d3c0c9
+CT = 1a1b1c7130aa63098dea17ffbb2216d1d276cb10145b0762a45116736e95d823e579d73dc31dc487
+
+Count = 6
+Nonce = 8a961df9c23f6d
+Adata = 07185502bf6d275c84e3ac4f5f77c3d4b30d8e106603be84410c11849a3c18ea
+Payload = 434e182d04ecda519a6119fbaa4c45e8c9803a9a3eb51dae
+CT = 3f603939c6226d8208b2b0e675b82557609ceaeeee4032c7837ed517dbd7e6fe34ea42b01c69d370
+
+Count = 7
+Nonce = d3604d390faab3
+Adata = c95e7329d36145664da69d25f24b301d334e1bca2baa74b2d5c325ed7d04fae4
+Payload = ee104be898a225eb1da99163bbf768d8ae6d5850af6f8767
+CT = 3e6a7683d9d804f791f77d2b69996102ba82477ec4557747ef2e0b322f51abb366a1e8e37f4fe4ee
+
+Count = 8
+Nonce = db5004a1cdae8e
+Adata = 1370fc9d5bf1ad2d071be5a28b235402a85270f536b5601c221519a3b329c71a
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 6db54d6f5c3f3efa6da67aea1234d46e8b679a5c257c66d82e4ef944778281ed186b4a8099b47fff
+
+Count = 9
+Nonce = 783477f981ef05
+Adata = 04bbf2a826bdf3d55069b1936c4f8e8e08189f54066a035c950c7347604b1b65
+Payload = 6150f132b25727ebbaed9f16bd91ebce00c68e5b39bc0ef9
+CT = 36f78cef22cacaf9f3d4464821737f7fbacd79be517b4727bc5c098625c51ac7fdd15da2cc9ef4b6
+
+[Nlen = 8]
+
+Key = 0b6256bd328a4cda2510d527c0f73ed4
+
+Count = 10
+Nonce = 21fd9011d6d9484a
+Adata = 66ff35c4f86ad7755b149e14e299034763023e7384f4af8c35277d2c7e1a7de2
+Payload = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2
+CT = 5a0be834c57b59d47a4590d8d19a1206d3c06e937a9b57f74034d9fdb43c3f48932aa72177b23bf6
+
+Count = 11
+Nonce = 97f940d7c1230bd8
+Adata = 78337ddfe38be7897372b0f805603a9a9e55598452285764641c3bb7aeb54a3c
+Payload = 772aeff60eb3adf5a9589ad54dda0401cc9765589609dbd3
+CT = ef5c408dc6d0b501925a47def54d8deb9880a07a3e6380bca20a3995cf25c5a7b9477d8916adff73
+
+Count = 12
+Nonce = acfdf302ed116ac4
+Adata = fe9d9989bffae3c9e6161eb0aa9d54ee8f5051f0dcabb5a750c5478c11798ce1
+Payload = 99ffe16de323a9b65fe60305a2d062cae490ccca6d9fe9da
+CT = 1bbc2c7877d845591660636cb6ccf4edcd4c156996a26a707d0e2fe322f203c08f44d7f9bd7258c3
+
+Count = 13
+Nonce = c8d36e13b7459c47
+Adata = 3f3c3a4c26dba18f385274ac5ac3df73282686488d91bc8190b7f61071b07f62
+Payload = 316ee95430329f706348886b8ac7779e3056809e25da0a03
+CT = fd2db9611a26a3e90f4861467df60edcc595f442332b089905fdd72307c3355b19ea66d4a16ef17d
+
+Count = 14
+Nonce = 5822755a3e47c27d
+Adata = 1d72d6b371e85ca359483761704f80b3360f4d6610e6d5e490b0d509f73c3233
+Payload = af4ae8f19cf6cbd199677fe033859f56906f1979b1b5926d
+CT = d5ed6f8d5c42f4f3ea527094173b278724a2ba787e416ad759124db19ab1373a5376f46ec7095ef4
+
+Count = 15
+Nonce = 6c1c94c2e71b865b
+Adata = 298cac1e4684182786f386ef3de79c11e30b2dab7579b8ca18d0312200860403
+Payload = 6e4d992d7541e02a4aa167e56c7e47206abc25fea6c5125d
+CT = 560cd43a502a6e8b1af478a3b640a68937d1a83057110d38eaa52d69ab9790edc384b9a5d8c91dbf
+
+Count = 16
+Nonce = ce7ec65cfeda31da
+Adata = 13c1298cbf7fe6a9ab378f86d3c2207944cc2a232f9383513ceb3b202086d365
+Payload = 196c80d02b663bdd89fdaa31e329b5a8f7c596236ee8dd80
+CT = 00174dd83a7f8edc71afbe5da095160336be9184f693db3db1f45de395e021c6fb1b2991c91bd643
+
+Count = 17
+Nonce = ddb739acda6c56ec
+Adata = 7f89bbe513b9a7ebe9be3f6eb88782080593c83e8cbe47fbe15bdc3e5782090f
+Payload = e95e142217c838d1f998a52e342e4f2d80b1cfd35cf6b73d
+CT = 819d73dadaf095652cf39729b2e2cad7fc7783887a5acc15713d941b845d96a5bf65e9f80ae7f923
+
+Count = 18
+Nonce = d9bb71ad90152d5c
+Adata = 20bfcba120cdbeb07c5f4d70338ffce493822d78a03c9e80b5b934e16e39f70e
+Payload = f1fe98b50ea2f9f088f6f93910757cf744d5aabf3081966d
+CT = 36decda8ade6ab104a201c6d370412b907a559738eef59665e99761cb1ac77d772b9cce9345d9a75
+
+Count = 19
+Nonce = 2c9ec9f1f1358c50
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = d74badb8ad7f2c2bcdf67e497151d35a4fc2a3c4c871868a
+CT = 0e9066270da6e03cb4307c43adc71b4b596213a63fc8032085ce60506ac3bd97327904ad2e072a6a
+
+[Nlen = 9]
+
+Key = afdccc84f257cb768b7ad735edbd1990
+
+Count = 20
+Nonce = b7776aa998f4d1189b
+Adata = 9f9ac464de508b98e789243fdb32db458538f8a291ed93ddf8aeaacfbfc371aa
+Payload = 56d0942490e546798f30d3c60ad4e3e110fc04f5b1c1fa83
+CT = 96f124c74fd737819008ddef440320f4a3733d0062c83c893e259aecf12ba08f2a2e966a3341d6d4
+
+Count = 21
+Nonce = 278cf1f09b13f467fe
+Adata = af9627922758a9f7792345716782e8837ca78e8f9db16e3fe12a7124a3d4e99d
+Payload = aa9b9e80cef47b6db3816b1d665f233e696337e21bb8333a
+CT = 5eba7e3b3ecab78121b0d56acb9dbfc6756c1255b42f145d11751638ed36c1fd3c7268b71633c1cf
+
+Count = 22
+Nonce = 4ae701103c63deca5b
+Adata = 5872a1507c833c581ac2750b2b54add4b92be14e45d72db7679f8fa2b4d1eeeb
+Payload = e832b053854fbd40c0d8b6d6b8fd5de2da0c173f5fe594ef
+CT = 3b2b964c3a90d51c0ace186db79818b4d0f7b81236d36017d3635aa1d8167087600b01643b0a5ce5
+
+Count = 23
+Nonce = cfb5b12928e1c36849
+Adata = febe755bb8e4475d8d12f5e96269abd0d4e40d73cb966e2c523343e9a6d2d71a
+Payload = f46d6970dcc37d32d93ff062e68034c1906ee487fd28eefa
+CT = 0d5332a42fc583f4f81744b899cdf2a64cad1e78d577112fee6f8c4b252e10b42fbaf8c7af1e9f3e
+
+Count = 24
+Nonce = 68d5863cafc69e6ceb
+Adata = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab7da44d2887485954
+Payload = dd4438d7ba3edc73872e42dbbf78cf300fe4bf0eac9e16b6
+CT = 874d3ef7f916db2c2799b6892ef4bfbeb4729ecbf26ac4983a8639f21f8548fae45dc76de57bcee0
+
+Count = 25
+Nonce = ea09fbe5da0fa4fe91
+Adata = 63ee18eb720b21ee4c157dafcb8c7bcc6817f54d5c1b8dd7058c37228a03f8ad
+Payload = c1811d613bf0789beeef693611ef733cd173da703b66ab3c
+CT = cbe5c799952b28fadf414607a6cf8194e9f41194abace4541d3853a52971b0ab46cc0a3eded435c1
+
+Count = 26
+Nonce = 0021be18ed76b3a34c
+Adata = bb5eded483f0ae1106fd08c5e2b91cf06d3a7a73518ad4c479fb05e631ba5399
+Payload = 2d5531d1c51c6ea100b028596bf9f24dd90be14eab58f07b
+CT = 7af0449f7359b7f3e5f6c1e7bc264c7724037f4f16077fd0a2a8e3cfb827c7e6edabb34f7bbafd01
+
+Count = 27
+Nonce = 449b51ee0760179e35
+Adata = e99bdf783070a3a48431704e90277ca65a9704c12eeae2e2d70b62f816115267
+Payload = c4896d58442877c986e4f862a9f3a3179f0e9b96316a90d8
+CT = af7531c073df01077fd5c8ea9a5530c2fe1688d529e5c2f24aa8feae6a500919a336dbba1d9fb7e9
+
+Count = 28
+Nonce = 232114642e0c6b55b5
+Adata = da288d2014616f16a2abf5923dea49aded1748592adbcd97415c33ebfa57150d
+Payload = 11fd3f94b5a5ce94f2740a27a0771aeeac77f3155d2bc12c
+CT = f0c174a7927da0bb88e92917af8ae1df4ffc3527004e9e2d0b25cea7ed6e4fe9069a2ce49875230d
+
+Count = 29
+Nonce = 660cb6d654afcbdab4
+Adata = bd96c3c225099fc58cc1f97779304606b11efe9712fba13abf74fc1d7d44a900
+Payload = 793c0bc3deb6e0bec4c1d1fc17e455eb1aa5e9e25cada861
+CT = fa4b14a381ee41fec7b7279e58f0d06a3beec26d645f81336218635754d5563f2cd48bdbb267e5ca
+
+[Nlen = 10]
+
+Key = 6ccb68d3838d4ddf660b9cd904cad40f
+
+Count = 30
+Nonce = c4fb7519a19f13d9d1fc
+Adata = 092e64fef08b5655a86cdb8de63ffaa7772e8730844e9016141af8bad2216246
+Payload = 5ea35c082e2b190e9d98e6b2daad8672f587b4f2968072fc
+CT = cda5fe3d15d00150b99120c7f206b88a4c2c4a39ca9143425603ab284a73a38cc916f8b653c92ab4
+
+Count = 31
+Nonce = 45927852550961f1ae9e
+Adata = 53ae030474795ffda4d9ac0fc3c45afb592ddd761f7b5335c13a6747e21075a7
+Payload = 6c5f468077536b4c9a94ea4a6fe3cf621083a210daee45b6
+CT = 694847b6429cbc3902d9cb7049625aef1e97b569e1e3169035bb811491d142cf1b26350f8451bd14
+
+Count = 32
+Nonce = d8c54463dfcf02d0e327
+Adata = ff95c0ed0da32d1b5f57570b815a50592ecdc9c1c4e727e0f6dfd93fc10ce88d
+Payload = 7321a6de8d694ea05623206f5df438c5c2cdd6b1eccab4d8
+CT = 9cf8ef119aa5cf3d6305d50b2b520a0b10bcd240e27276749c68e8e641b0120f7dd66e8f0cfa4205
+
+Count = 33
+Nonce = f690f3a996928275050b
+Adata = 41c05fda535770699ed22cef253753b658437f833afe65c9c393581d835f0fea
+Payload = 56520a4bfd7b73a471e0446f9524a407e81c2681b7329e35
+CT = 14aa15f9f64c4c64f6e88094e012ecb24193249f044c033dda44a62f97c0fead3f65b28928bfbcc3
+
+Count = 34
+Nonce = 26eb9ef25be62148fa61
+Adata = 8f45608a07521de86ed5a84a851e629b579b51d7bf4cc7202a773e0f9e9d8748
+Payload = c68094c26c7f017b79f126dc26b3bbcb95f97535ca412da5
+CT = 7ba8a0c2fe2b230768d1c1874085ddff8926931961bc4558f0d5444466bcc631bef8e58fe5818af7
+
+Count = 35
+Nonce = fad21bc27dabafe7a4ae
+Adata = dc5d7fd97bb3243ba585fa0d71a07191667af418e30a6b76bedd05b32c673403
+Payload = c247fa8d8091cd3f299cdacba7fb7af93549e9e3160f9cf8
+CT = 3097d2ec0f8bf00b22504ab03a75e740d3e59c269c3ee3f00b5419293a67eb008aef0f9f675201df
+
+Count = 36
+Nonce = c911348848fe67406dea
+Adata = 50d50a0b5ed4d6904ec3045263af0255a6494b7a7e2e95ea806c4bb788423dc1
+Payload = d846c170ae0111348362901503b26d58f5efc17b6d296aba
+CT = 5d72562f7dfb47bf34b90ee4ea11ff9f726c915b07f4d843dec5a554f4bbecbf6943ffdab8d8a26a
+
+Count = 37
+Nonce = bb921b46a16d20ae4046
+Adata = 7d17f8f60ad1e61a168b5b0e7fbbc90cee79b612b6d6c0d7ff6ede042341e8a1
+Payload = 71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae9
+CT = bac123320888b553666249756e6d63b3498760791cbe9e34e5b1162b7489a59a50c0f0f3618e6c2e
+
+Count = 38
+Nonce = 61a8b8cbfc9bdbadb2a3
+Adata = 51cf2a8949e13eaa087a34c9ec4d7fd92b862efd6a0b1fef8b016fa2c6933426
+Payload = 362f9a46aab59fb6213c83d791b2129b34367ac2de2048fb
+CT = b8a57e8714d8789f4ef2af29e0efec21b1ef67fdabc7cdf0ed5505f1f0ff77723771338585c456b7
+
+Count = 39
+Nonce = 6bc4cd23c32a913998a7
+Adata = 92fbc970b5e64198ce2a138de92767edff8d82f12f8832444b346d159657356b
+Payload = fa442383da234cf8f0c5fb667218bc3bea0c091b3a8e6b77
+CT = cdfe3e83aba43a9804c5a1832e0e47a9a153359cc32db907714025f485c7f40256049f16f859b859
+
+[Nlen = 11]
+
+Key = e6ab9e70a4fb51b01c2e262233e64c0d
+
+Count = 40
+Nonce = 74e689eb5af9441dd690a6
+Adata = 42f6518ee0fbe42f28e13b4bb2eb60517b37c9744394d9143393a879c3e107c7
+Payload = ba15916733550d7aa82b2f6b117cd3f54c83ddc16cd0288a
+CT = dcc151443288f35d39ed8fae6f0ce1d1eb656f4f7fd65c0b16f322ce85d7c54e71ac560fd4da9651
+
+Count = 41
+Nonce = eb118fb41284bfcb1bc338
+Adata = b5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d02
+Payload = 863da00c7accf45418d47c1eda72338734dcc49cd599f328
+CT = d64de7a56146b971e21bf5784d67bab32dd837cfb81591da4a0177883346dc896eb39e8a32bc1393
+
+Count = 42
+Nonce = caba2716d07e95de83855e
+Adata = 0e0ff2c73ea5fa8f8726a3514cf906ce1610a1a6dc19b22682f9e4619f762d82
+Payload = 2af6d5636ab65db2058b2ba16df257369fc4e8aef8b9481c
+CT = 3c9e006c7d8eff5f448b0cc9c27c964713241aa7fed3665d775ea25fb272981de8b8aa0a637498fb
+
+Count = 43
+Nonce = 314c136999e41d137bd7ba
+Adata = 366c659bc45d0a88acd54ef7eeaa3e140e1cafb1b01474a065a9d460c5e83bfd
+Payload = 217b19ea6a431a1f66bd9d02b718e8507a08ab8e6f603e3f
+CT = 33d7b672b23e8b03a39ff3fd1e7b0f2be67163e3e3bae072f2aaa211dec623947a50b1252bc5aad3
+
+Count = 44
+Nonce = 6fe51f5013f53d4e4fd907
+Adata = ff182f2e179d790e827cbfd0bd8b9297ecae57ffcef9e25ef114474a22e4ec5b
+Payload = c6bf582b49dd4ab6cb33f3f88e8a4d14fe32b308ee3b4682
+CT = 26cd5dc5eac2acda283ca03354260ad57af79e20c5e92f5775ed171bb0fbaa6f431c5411cf9b536d
+
+Count = 45
+Nonce = 24bc8dc1e2354667b79ba4
+Adata = d0d48d01fc79685c6bee04d45e40d06cdf1f4607542b1ece556fc2d1bb2b03f1
+Payload = 90f52ebb1bd5439386faeaa194623285f750672a7baae64b
+CT = a7f43f56c50705a1a101044b954414fdfbe32b518e934d38f391749ea3acd624c01e4583ab1506b7
+
+Count = 46
+Nonce = 89ce46b3de3afaf2518d41
+Adata = 5767202c913584d653f37d926a0c5ac1c67db3efd1dc58fbff998778a6856254
+Payload = b2ab379a0dd15baf91415eee3a4e56e7eca54d4c1c3094f8
+CT = 9f530e455a54b86835eacd8801b34c884a3b2ac819ba38f894e43a6b1cf73cb2d6a1dd8331549520
+
+Count = 47
+Nonce = d3208eb695e84c7a925037
+Adata = 91d8fa65a6885f162a795afe2898f391990a8b3a87c11f94734dcbddf5f58da8
+Payload = f15e39f0e4eaa5bf81359d8e30186522f1a1a415436668cf
+CT = 7f1d9fcd9e5cce3a81e3495bfecec817fd7180d8bbfe0abab27fb6425fcc3537ce471425a5b17dcf
+
+Count = 48
+Nonce = 067de2869333ed22c7b63e
+Adata = c31e441fd551b3fdfbe23ceec5ec1f838f31a5300f6055ad2a936a9d0c1c856e
+Payload = 1536d9c9a09302d142c85638202f5bbf0c287f68115d51d8
+CT = b1a5c7a7fd23228dc7ea26885802daa0719f6a23681e1d65dfb879c21b46f3307ef22f1da579303f
+
+Count = 49
+Nonce = 15f61b4526d19bceae1093
+Adata = b97b122af73e928e617e98684f845be4cb80566345739b7a884c6a3eec5102bf
+Payload = 37c81988c07a5b01e2b40ff9f9ada5f50ca764efb717ff9e
+CT = 0d93a5c77482d573b7f1b8c5e283f2571efc9f54216a4c01900504a73c8817ff2b55618b2602bf38
+
+[Nlen = 12]
+
+Key = 005e8f4d8e0cbf4e1ceeb5d87a275848
+
+Count = 50
+Nonce = 0ec3ac452b547b9062aac8fa
+Adata = 2f1821aa57e5278ffd33c17d46615b77363149dbc98470413f6543a6b749f2ca
+Payload = b6f345204526439daf84998f380dcfb4b4167c959c04ff65
+CT = 9575e16f35da3c88a19c26a7b762044f4d7bbbafeff05d754829e2a7752fa3a14890972884b511d8
+
+Count = 51
+Nonce = 472711261a9262bef077c0b7
+Adata = 17c87889a2652636bcf712d111c86b9d68d64d18d531928030a5ec97c59931a4
+Payload = 9d63df773b3799e361c5328d44bbb12f4154747ecf7cc667
+CT = 53323b82d7a754d82cebf0d4bc930ef06d11e162c5c027c4715a641834bbb75bb6572ca5a45c3183
+
+Count = 52
+Nonce = 6a7b80b6738ff0a23ad58fb2
+Adata = 26c12e5cdfe225a5be56d7a8aaf9fd4eb327d2f29c2ebc7396022f884f33ce54
+Payload = ba1978d58492c7f827cafef87d00f1a137f3f05a2dedb14d
+CT = aa1d9eacabdcdd0f54681653ac44042a3dd47e338d15604e86a0e926daf21d17b359253d0d5d5d00
+
+Count = 53
+Nonce = d8e133e7ff8e0a0ec6c4096e
+Adata = ef9e432c15d8c93a4b5c0666608e61c824cd466d7940d642acd3dc33057c0395
+Payload = 2836de99c0f641cd55e89f5af76638947b8227377ef88bfb
+CT = 5edb056d85dafeaaf74bdf4caa47339d6a75bf1ee998565e9f9cdf6ab825f6e026f5be2ad895033e
+
+Count = 54
+Nonce = 2fa8120398d1a946f391367c
+Adata = 377cd407ad28dc02bd3835a31d92f8295c9dbe597f56662ceda112c588dc73a5
+Payload = 7a37255b682766a0bfecf78e5162528885a339174c2a4932
+CT = 701f5f506fc7e9ea4a27a4db5cb890f7be3b4f6bcb20f97ed3021f6ad620648b8196ab1693710398
+
+Count = 55
+Nonce = 8d638ef43f56dece910139e9
+Adata = 87ea7b095388de70ac0ed23e86f502400910028a8ab5e3bbb91d05821c0d2d61
+Payload = 7370d9b453936955b9c9d336f4b283237986232de007bf41
+CT = be2f03f6ce1731418a5f53b6f6e467b73992a0c8102d8ffc2d236162688096d80b8733d2afbcd244
+
+Count = 56
+Nonce = f479ea8812b6b2f6ac78fe9d
+Adata = 20c2b8f5d3a65a66ba8a25e2ee339a779a32d45f5db91077efae6cf308feef50
+Payload = 59ff9f7581a781808d36fed378080963f35c00ea5a6e3932
+CT = d127c956349c16e2186f55b72254c677f03c61f1c4ada9e661bb9415b32d6a58f5f7647ed41de685
+
+Count = 57
+Nonce = 423515f7bd592d6a7a240866
+Adata = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032972c939db300d8c1
+Payload = 3c379f90b11c622a765756a15efc8fc3ca7b08b3281945f5
+CT = 15792e01fc17f5294c3405484291082c00a8f46dd9af8ca230ba95c4058501234a1b97543c998e9d
+
+Count = 58
+Nonce = c3f3da69e13c5733039744b1
+Adata = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc5731303fe0bd56b11e
+Payload = 9db6fe9adb8c0fee87cac9a7f01a7ed8a84f0512d09b1834
+CT = 9b6b829ca1dc4e90d4402188632ea3377cbec2ba60f0f072afca1b08b6dd589a17a32d49b6f7135b
+
+Count = 59
+Nonce = 0a57d59f21ead5b6d80cd2ce
+Adata = de5f2d413c98c6ea2a5640a7b1c424aebe75cbc78b06710b5bff8bec6afb5a76
+Payload = 0b5f6389f7c20f4ba326e8f05d373ca27b7ebe59e6d729f0
+CT = 0b704e14bc7d2977d89e0b2e7ed7fe3c9e0f2ea80d2d6165f344f2f1b2218d9b4283fe640a6d315b
+
+[Nlen = 13]
+
+Key = ac87fef3b76e725d66d905625a387e82
+
+Count = 60
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f3898390e90d0a0899f69f9552
+CT = cabf8aa613d5357aa3e70173d43f1f202b628a61d18e8b572eb66bb8213a515aa61e5f0945cd57f4
+
+Count = 61
+Nonce = 2a27257bfaadf23a87df082c57
+Adata = 0001dc666c9daf3560daeaf514270db0b5075d295068e6caf231c1de0e1a9300
+Payload = 6cbbfa6d736fbcc4cf73ab4d7be537420e0e574ee1f2d1b5
+CT = 72d525e6bb312bf2c20b91f41108779789c25720797ebffa4cd9d735f51430275387c565cf1a69bc
+
+Count = 62
+Nonce = b94ac8ed14895c80a91fda8367
+Adata = e1eaf35fb266f243a3fa407cd41815ae6432ad79877bfa59d8f196cbf19bfbb2
+Payload = e6ec561496ce18d96b26d594a47ffad02d68ef25d2d2edb9
+CT = c63500445239bbdf71a8dfe3f8c01061d659cfeb038b825dc89fb5f507f5aeefaa9365f0b18dcb3c
+
+Count = 63
+Nonce = bbae10aa491ac9c668a3ba8d7a
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 9c629c375f014e162895cfc25a972c29839f97407e7c7cca83d0a61d453d596fbc5c2e315d9780bf
+
+Count = 64
+Nonce = e0b10e78e9fb41ee970143e9e3
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf3c99c9d1a35bd8e4ed36596789
+CT = 867799b30558697d6efb4afcfe458cfad8da21139a0b43128e8f8e13b7896b244d0c9aa52ed31a95
+
+Count = 65
+Nonce = 17b61109f5e37754e4e92a28d7
+Adata = 0bc2fdd890c19882640f8d4188b88b9db99cc1934cc3e98a5df08589287968a6
+Payload = 347c1eb4aff917bc0012f005e74caadc93f4f18f2b614ece
+CT = ee19f3120991b67b2389e6f36543d99590f2e6d785c9c8ecc40eb85585cc3b7520a940a4e993327d
+
+Count = 66
+Nonce = db3ca9e80ab761804349379961
+Adata = ce01369d08d37dcda2c899c9fc0d11ccf94a0051b2816a1d6c3ad07fc8dd02d7
+Payload = f0e1af1276d2918be91a191814660bfe735463d3983de1ed
+CT = 0f1b1228729b181772d7cf55ad257fbcb19cd46f7b31a885401358c7b44aea27617b429583103a1a
+
+Count = 67
+Nonce = 1f57959cecbd377374477e33b3
+Adata = de1c7c83ac61e1f99ae99b198f4af5d24f8de60ea98fe637f3a801fab38b2a4b
+Payload = 42a42b84df098ceb43519c4cb86c14c2fafca39346159e13
+CT = 12425453de653d0fe8103013fde1ebf4a8fe18f76f0c9d60e93525fe8048c3b2147a149f12eaecd3
+
+Count = 68
+Nonce = c9db03e2efbab713b0b6404210
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918696a
+Payload = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c
+CT = 5cdc183c32b4c1878eb83e8473a17c55c88e2ad6b944ab1f64ddee42614aa737231207636c114575
+
+Count = 69
+Nonce = 89ed296a3ac03fbfb71422b921
+Adata = 1ffbe1aff0a1e7fa3e68be31a74612a1519b59397e7007ef61fc015f316d55b5
+Payload = bff42516e30c92ed46710013c656600406a48a84c1fa32ce
+CT = e08c1ab4ae7edb5184c30ffb3e74689ea855f50b0e890392f26b130720f75c422fdf66fb174383b5
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT192.rsp b/lib/crypto/test/crypto_SUITE_data/VNT192.rsp
new file mode 100644
index 0000000000..06e9ff5655
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT192.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = ceb009aea4454451feadf0e6b36f45555dd04723baa448e8
+
+Count = 0
+Nonce = 764043c49460b7
+Adata = 6e80dd7f1badf3a1c9ab25c75f10bde78c23fa0eb8f9aaa53adefbf4cbf78fe4
+Payload = c8d275f919e17d7fe69c2a1f58939dfe4d403791b5df1310
+CT = 8a0f3d8229e48e7487fd95a28ad392c80b3681d4fbc7bbfd2dd6ef1c45d4ccb723dc074414db506d
+
+Count = 1
+Nonce = 026a0b8b17be95
+Adata = 44caa8ecfaf38e5e773cb0366e1b04aa0b9fac5c34a362310f471960c4a1e1c9
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 3417044bad5fddd9455579123dda4fd342c273a57ff6333dfedf191496d88cbe17c6271b65096e66
+
+Count = 2
+Nonce = ea09fbe5da0fa4
+Adata = 1d9799f2bb0f7ab57fe3de27949ff64066131c81bfee172b308f9bb0b3171067
+Payload = 469ff9698cfc96b581d7115c822e4363d7355ec5daed2eae
+CT = 1dae7cc16f1b469290902cfad47b959784b4d6f48a79e690d47e30b635d10d1663477d61d7ffb55d
+
+Count = 3
+Nonce = 8d27bcbf9ebfd3
+Adata = a7070b85b7add9193c9dcd2e6c03f6e7ecc52ffe9e099866baf7472f20c03aab
+Payload = 225651d072dc9d93762dd79691ac2b6ddba00ec1252d69eb
+CT = 5da819adefbf794612eb458519debcd524c283763eb3d7252eca8766bdf0db6bb2dcc793e1749c21
+
+Count = 4
+Nonce = 13f560187b6077
+Adata = c4ab4244db75f8256e55c5b613a07b11c963c3cc24f66128aad4ba8b7ca99331
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = 3aedcf8347aa23fd3325ce08b6b00462536baed69968a753feab6761c55431bb5668e1f5b7505e89
+
+Count = 5
+Nonce = 61e0e28bf344a9
+Adata = 5f998952de70449ad46428f2ff8a01c5af43c0107a1bcc6930f19d4112598666
+Payload = db21b37e875d7709a02239ce6ea529cf37255d5b617c153d
+CT = b8f5fed39c723d7643d6dcf2efd3bbd1ba0da1ec901305fd64b2302ace4f66216ca8b4d776197692
+
+Count = 6
+Nonce = f6be4aad63d33a
+Adata = 18339be863fb8a887d04ae9ff3b4a7db095075cd5d113a9ec87b41fe85ea405e
+Payload = e53101e6eabcda32c13d7b1dd1d88e7c2ca3ddc2064f64c6
+CT = b758858ab60e1630a0883d4d330119a593729a3015c42525effb985b9c2dd9ec954bd25d9c464c67
+
+Count = 7
+Nonce = 2c1c59aa0d8eff
+Adata = d44af86b89fda8448a9b2fcae20ea156dd8738c8251699c02b785811c830bf72
+Payload = 1fd7188a43dee7b059420e8634d71d2c0658f6d0d308dc73
+CT = d046f845a67800a5a58f461e5a8641e8fc9b4c53b32e61d172adafffbacb297d67f6b5c02b982e04
+
+Count = 8
+Nonce = 48e4598edd191e
+Adata = 61588bdc980ea2310e87dec4c651e9a55c27e3858b6505cbf3bf85e51931badc
+Payload = c25868f390af5e59c035cb5830e018c62c5b96bd35b764f1
+CT = 0ece161bd77b7f969b3b20c818769a98c178d84524544664500ff4cfe66ade1832babc019778acc3
+
+Count = 9
+Nonce = 6d576ce3c5fcb5
+Adata = 92c598cb5ca2926c11f67c3b3cf25493d77606fa60d7290430e0e975091644a6
+Payload = bcd97479db934357a163a9e5f5a85999ca987f8243d8017b
+CT = bee185e11b3d42bac846b9d92c70a078aebfa630ab763840391031b3a22b2adeb9791ee35765c8cc
+
+[Nlen = 8]
+
+Key = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193d
+
+Count = 10
+Nonce = ad749d596d88a4b4
+Adata = c67219909828adef64422286008e1e306867a1c0b3da95444507a68b45c953e4
+Payload = bd92d6744cde446fc8621625658fc4bc00dcb97f06195ad7
+CT = 076cffd0ca978fe2bad411ced45a090abafb22a99896f6a75a1969276aa2b0cdb37ccaf2845dbf6e
+
+Count = 11
+Nonce = b1dc81d116d94f5e
+Adata = aa4b71906b6642f10f66c2391ec157c7cde97eb322db10045af4c5248807f691
+Payload = 9aa6dbe1cd3eb98d330c937d31ef93bee8938b6c5cfd38de
+CT = 720f6876ac91665f20147483f0655fdbe21963a01e36f1daa67e36d7cc8d54cfec0762514475127b
+
+Count = 12
+Nonce = e758738df5c89af3
+Adata = 5715fa238f432c926e62dd93708d0e3145428e0ed45e1efa8148d2c4ab6cba50
+Payload = ce80b99039a16e69018d1e3c239dd1bf06e94a78b0b1df37
+CT = acdf7ba3edca1563727ed85cabf085c2f0c8f27556c3c064ef50d85bc3ade6a773d956b2660ac367
+
+Count = 13
+Nonce = d586c4c67d535476
+Adata = 1e8dc63c6c54a540b6b02067ba7c719221cf289fa3897299722c9a2bd6eed05b
+Payload = 2f88305117f9a5d807d54b7e95ecfeb7327e52d9acac352f
+CT = e42b86e619be1a38973c934babeb4688243a9012c85d643d81e024aaf0a62b353f9bed36681288d2
+
+Count = 14
+Nonce = 77e83758f68d272b
+Adata = 25c80edef3d5bd8b049fa731215b80ca2ee9ee6fb051326e8c6d0b9e11e3d7ef
+Payload = 92e47b82b728d639777d5d5843de2a5c364956cb4b21cabd
+CT = 1b9177f5b76403cb8c690b39c3dd22b55da35cebccb9b64e05fe32f796f0b4a75a459fce6c7d740c
+
+Count = 15
+Nonce = 311dc245549206cd
+Adata = 87767f13bb4904d0df0d64eb22c9ddb65e81b5739baad86ad5e2c239ffde9f6c
+Payload = 8691c0301a216a5f3ed9123886d100309bd85630d6b845f5
+CT = f39fe3620a03b37a4bf457909e0770447b498ad2a2f0f9d7b75f9e4239e43bbf93066897e60f6fbe
+
+Count = 16
+Nonce = 2a17b70f10e120c0
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 92187955ee1ae702ef01a385537119b2bd4545402e8b2384a0c069a2439a2d8843302c6a9999e658
+
+Count = 17
+Nonce = e0b10e78e9fb41ee
+Adata = 9d072b8a3f1a496b2be6728a38b94a4f44c9be40c8793b69afd81d01696a6b4a
+Payload = cea28e7cd0eff0c5eafeec908d4aa8ba303e72ada33db087
+CT = c605e48f2e66e8e0a92471e466981ae5e31db3e4ad80b09f5005b06d15f63f2f015cfe447828da09
+
+Count = 18
+Nonce = 02d72dde23f9772c
+Adata = 2dc44c39940e2d9c94d2dbe40bbf5cca5efb4d4b250a31aa24f208b87e9c2453
+Payload = 809343e986f6ff47f54d4cac22ed39babd12271d4c7edb58
+CT = 0bb59581f22f6b15de76c0066645495a5c19e44381c349263ed92ebb789c314a89c83542b15ed694
+
+Count = 19
+Nonce = 28c4d6de3e2ce51b
+Adata = 913a8eda924589d3206ce0a951fef93668c6c0c454824b217997bff6b3026d54
+Payload = a19f65ffdafd6ad5ee43570f7e168f94a8b4a7b7402ac80b
+CT = f0c91a29f1222b906550ef5c7c0944c5c4236cb6c31122cfada8e796f2ce7f9449f42de504873868
+
+[Nlen = 9]
+
+Key = 8cc622645065c72d0d2aca75802cf1bbbd81096721627c08
+
+Count = 20
+Nonce = cd84acbe9abb6a990a
+Adata = 447b6f36acdad2d1cfd6e9a92f4055ad90142e61f4a19927caea9dbe634d3208
+Payload = 597b3614ff9cd567afd1aad4e5f52cc3fa4ca32b9b213c55
+CT = 2d7fb83e6621eed9073e0386d032c6941bef37b2cf36a4c6c5e36222d17c6fb0631c3f560a3ce4a4
+
+Count = 21
+Nonce = 1fc7a43ed124745d04
+Adata = c892b095173076a40e24522297be27fd3a765c8d417f24c71a9f03b3fe3d8e20
+Payload = 415cd8312dd20a1c26f4b90d98104cdfbe06739466fc0aa5
+CT = 7bebd6f55f15ae57ab73f92f7be6ff37ddd99740e988f01a7a2a13c22df4a156e6d6063235452c85
+
+Count = 22
+Nonce = 19ff5e7c1f2c594abc
+Adata = effcea4e4dbc57410426b39fcf51c9daecd9d310888590d77827973a29c4ebff
+Payload = 97fd2c259a4e672e9555a9a5b98f4c0ec8c4c49c7ade26a4
+CT = a460674c2f358762e97dfc958d90973e1e419dbc6a832e987579b2c4a6bcf0356f48cf8959cfa54a
+
+Count = 23
+Nonce = 64d9bd368ac2357cf2
+Adata = 62c5a16f946b4312517f67c80afe2614c822e3a01b87dc81538c00bbf3fc0108
+Payload = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f9
+CT = 8fb5e0954388b9b58519482962487e9b0768f0cee08afe9a92be2b06a0ecd2d00877abded7d9634c
+
+Count = 24
+Nonce = b4aaf2cd93efc0ce93
+Adata = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d1ae70413e4e43d14
+Payload = dd42449da4c95e858b796085b6b5b3b5eef484dbf3c2bc8b
+CT = 893f86e29972928c1f3c3e25c73947c8d677814bca7fff2cf8d301ceace678f9bf91fc361dff5812
+
+Count = 25
+Nonce = 132f3e19e12f462a74
+Adata = 176cc5a280f6171d00e247edacc81f05c1b9faa87fc831163ac9d76aae59a6c3
+Payload = 8ea05a5033ab8b009664fa2800c24e217488ce6888cad147
+CT = 4771d210ea678dbfab96e320e9c44b68f47cb05b01826ccf42ca4f4ccf986eb6a6b85b99db2fcd93
+
+Count = 26
+Nonce = de709ba64cb75704c0
+Adata = 0cf8e9ab95766b6fa85e88d86e4f349a17c0d90509939e343eede988e7462255
+Payload = 51dd9fda9549f25dd868245a6a54b8d59346d2f336adf9af
+CT = fccc3e44afa6bd2fbcfc5c834db63dc9d152c04c0dc0b43d393162252ae91ca46fb8e8338cbeb75d
+
+Count = 27
+Nonce = b11b4c1b7a26387265
+Adata = 14ed867cc909c0619f366918a7d5ae25279fb137e1dee7fd98ddbe3bd19d841d
+Payload = e35ea4a16e274fcab457fd4dc7886c3d81fc668c19e0f374
+CT = dcca8aa2eab8ac3f5db9cd9560ae0758d7df40d7d868d1f71f498ea6ec8251a6d149c7ca38b25fe4
+
+Count = 28
+Nonce = 20d03227a7fcaef1ce
+Adata = c5c15245e641687d0ca9e913406acd2de3f21fbaf2dc5e4e8963222da61d02a6
+Payload = 6775e5faffd0b13e78da70a789042245d5ef31eab5245380
+CT = 4bb8ed2207f36f40f62d3a2c90f8e3bd8f589059b69037118ce3ab864545ea81943ef0ea9489d223
+
+Count = 29
+Nonce = 267f76b9ec0f5e7c6f
+Adata = 2b421be47d07dcb12a0706f7490d05024fce8f433079e18ec78f4c8678f5f155
+Payload = 9330bb23428ab45f573923e977db74882282cbe1371da68e
+CT = c6ae24f82ac5cf9c18a2d98e610027eb2566a1ccfcf99945655e14c7bc8be97ea47388cb7b18bcf0
+
+[Nlen = 10]
+
+Key = ab72eef2aba30205c986e2052d6e2c67881d24ae5fceaa8f
+
+Count = 30
+Nonce = d7a46e726ed43f1580eb
+Adata = baa86f14271b2be7dbb37ddc7c95ce4857e57aa94624d594d7bd6ceeaada8d5f
+Payload = 2a794b84fc9e4a7e6d70a82b5141fd132177a86b4e8fc13a
+CT = 2d7f76464417613bb61d3657481346b74fc9d6abc6a3babd39365dce86859cd82395d11bfc8cf188
+
+Count = 31
+Nonce = d0afcbc1b2524a4a4553
+Adata = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4a36bf523e89e9da8
+Payload = bfc5ce1316ccdbcd8ac62484e7656c87947ff98cbba8e1e9
+CT = 4772c121367d0e8d3edade883342395f3ea065fe7dd7be8c8355b915ca2633fd557ca7ed41e00926
+
+Count = 32
+Nonce = 6eecffd227e8d5349523
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c122e0b1587302894c391
+CT = e2864c6e12ac089daaa1e94af4b2ed04060d7ef65d2f72f0e7d017514d498f1f3c07d650afde8293
+
+Count = 33
+Nonce = a67c0675753f725a8fd4
+Adata = 7dd546397a9a0129861fb6815d419a307f90d259d55f3503961754126cd1b776
+Payload = 80f1f1ea46c92d28f2d60eab39ce056a4aefe63fa688538e
+CT = 882c687c03eaaad9d7f591649e736f0c1c78f95e40d40cd77499a8544bc2a8fe95f55fefc7316f8d
+
+Count = 34
+Nonce = eb83928f0d5f7aa3a74f
+Adata = 060cd3e4aecdb03837dfa9f544318c0a16cdc37fa2a3135be7888ac67e7eb26b
+Payload = 81e9174e9472777b6b184707108c01d6ea6b5d108ec3c6c8
+CT = 243cfa0a0a36a4c20333968910e6f52acc04c6f74e704180623f3a13fc13db958cbac49f7421d6af
+
+Count = 35
+Nonce = 5757abe01f7a1183fdcf
+Adata = 744629263041f0eccfce4a1ebcc18c4c984010f9241d35966263a8b2f72ee26b
+Payload = 991049f26b529af8b0bee0cc83989cf817d248254182f332
+CT = b20469b5f33f0996e8de869ad10ce09924a0bdd7b67a89a09c447a3132fbe5213133650000d50b06
+
+Count = 36
+Nonce = d9adfc5b44ad7aa94b05
+Adata = aa6a5448c6ec87be75eca35725ad2e902dbccf840d25b2bdf7e62e4a8fa4a511
+Payload = 14682301a99bf680805d1ffe62e1506d48cee8c51ef1d255
+CT = 9b44efa185b0c10325bb4c3c0815e6a6e46eea366b9a416b5ae554cb440eadd875657fd5cecc214a
+
+Count = 37
+Nonce = dc3ca30782c9c0a7fe89
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = f9cb86f24536931a1b095b426a07e4621c000cf09b472bf8
+CT = 463f9124d1cc387a0f8b971d1e2da448f0efffc3956ebb2af8312986315522081f0989838ef0429b
+
+Count = 38
+Nonce = 9523f53f92b6e4ba86e5
+Adata = c3b123ccc916d26a2e6a8b5e30041ad69a944217e9b402b7acc0170c31e8c2e4
+Payload = b9bdcac80f64175836ab51bb1a1bee5ffe3a6b9b71afe3ef
+CT = c356b5a78cebd123808fb740754dc47a8ec7c9448bfacf39768e94f062e86129cc9210dfcd3e6128
+
+Count = 39
+Nonce = 16bdf18c09d60f3a2a32
+Adata = eedd0796f23612749e9fd282c864f3118d0683409d3bef1fda352e1422273c7e
+Payload = cc96133e473d197be1bafdfc1a21d58e57d0d89b2ba1c3ff
+CT = f9d78e9e3a41b3bcbfe756385a3715776eb84bb7d8d15432978757883f07802b25e9a5b15c43b451
+
+[Nlen = 11]
+
+Key = af84c6f302c59aeee6d5728ed5da2e3c64a5a781c52c4d1b
+
+Count = 40
+Nonce = df990c42a268950677c433
+Adata = a6ab5d78427f297a4b7e21f1091ff3a5b20caa3fe1cbcb09459d9df596a6c8e1
+Payload = 6db41aeb5f7c24df8929dbc30483b3c7934b3bd1cdce5bb9
+CT = 8c9328258bf71970d33e23a3ff81cc1c9cbe196a1294264bfd6a7255e4801963bb30a63de3fc5b82
+
+Count = 41
+Nonce = b7ea72641bbe2dca6d85e7
+Adata = 4e0f2ddf183281ec131693bdcea3fc9743733c07a486a42d5737735b3f6e3fdf
+Payload = 726844e41b1e4d883024b32fee0dcea38c889cb328885b7c
+CT = 9a133e4582c2ebc445862a9c6f2f4e39223c84081e322c8f262de30da6ef505fe640c53d765f672c
+
+Count = 42
+Nonce = 446fee1e75e79c0dfc9ddc
+Adata = 42b598eaee271e06d9e98dd94152b28ef10f506d65bd660b2fb8b1be9a2d7254
+Payload = 0cdcf348ecc9c3588001802c2106fb64be9c301adcc66e73
+CT = 0c2657b0482b6ca92e1b1c8fdf75eae3b0cd3af205e9bca396ecb1e46beb16000d585e1d9559ee22
+
+Count = 43
+Nonce = 2e6e34070caf1b8820ed39
+Adata = 8bd1ef3a1831fcc8919d736fb23111ca3ef4cccaf20264fab8eb3b071e56667f
+Payload = ca0860cc1e96506c2beb25b53d2947fbab634f0372afc8ba
+CT = 19e4774030e43e6853ab5bf176ba9c4b59f29f285977e3c15198cbe3e34c884c3f56a732974aa1d6
+
+Count = 44
+Nonce = 428542ecfb94a745980aa6
+Adata = 8efe01716b9018084e2ea7616f85b7333d945c0c970f8cdd400130b98db67cda
+Payload = bc6b59120ba2845b0e41f65a55e2ef1c45a81485c926c14c
+CT = cb48b0af6fad251d409d14ce0fbfae9cd9c40bf4a0c1e2b7e7cec415030997e1ac5db974b617b5a7
+
+Count = 45
+Nonce = eff703e6d72ddd23ff52d9
+Adata = d7fc74035e66709d2590b7bb3276245dd43824c9896fbd801ec1d07018b39b6b
+Payload = 1a5432e8085511ddac1be91be3e2945f85f0cdcc3a1c9f8d
+CT = c0a00cbaec65b7ca525fb26e80ee0cd18c7ef47c39c704833e59bfecf263bfdb24686627fd95e120
+
+Count = 46
+Nonce = 6a652ce21334a40a259dcf
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d34e141066f543526db6
+Payload = eb8f1988cb405041bf48d138ad41da7ef364d4ac59a9e324
+CT = d4f23166c09a15466c7e0e2b30627ee5a84f22d7e6135b4a0652b67d559a84b4a915ca6a420fd300
+
+Count = 47
+Nonce = 9382e12d447c0ca23cc9c3
+Adata = 239129eb760f8a770410c160e4e13a6b9497077c3e463b65397393fcd3cb5c70
+Payload = b40e80564263c7f450c53ef84df67247d72e8a04dbb284bc
+CT = 6de2ba26caa80874814816154784912c55e3d6da83488e7250f5a52f82211542b4e2661cf870c80c
+
+Count = 48
+Nonce = 2c3a4148cbb02504a2483f
+Adata = 33c3bdbf185b580353de79e51e675b03b31e195f19ba1f063d44def0441dc528
+Payload = 60a31736d99c3dcf25b349f6110e1c152b93506e85a01e67
+CT = 4d5e705d08f3ed1ca6f1caa74b46e4b1eee18a0783686f207de16aaa41d06bc071657dacf14da754
+
+Count = 49
+Nonce = 691cdf6fe9ecc2154d0101
+Adata = dc096596644c4e09c44078b86e5e0887c45094042eb0d74a6a13aa2524463076
+Payload = 77e6441ee017a93dd876ff2c7980540c77ee15edb0f23933
+CT = 24cecc81c8ac7ca9906372dc5263f2220b4dd162f1e08283f07f23e65475a20fd96e45c6c695cd83
+
+[Nlen = 12]
+
+Key = d49b255aed8be1c02eb6d8ae2bac6dcd7901f1f61df3bbf5
+
+Count = 50
+Nonce = 1af29e721c98e81fb6286370
+Adata = 64f8a0eee5487a4958a489ed35f1327e2096542c1bdb2134fb942ca91804c274
+Payload = 062eafb0cd09d26e65108c0f56fcc7a305f31c34e0f3a24c
+CT = 721344e2fd05d2ee50713531052d75e4071103ab0436f65f0af2a663da51bac626c9f4128ba5ec0b
+
+Count = 51
+Nonce = ca650ed993c4010c1b0bd1f2
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d50d344340c
+Payload = fc375d984fa13af4a5a7516f3434365cd9473cd316e8964c
+CT = 5b300c718d5a64f537f6cbb4d212d0f903b547ab4b21af56ef7662525021c5777c2d74ea239a4c44
+
+Count = 52
+Nonce = 318adeb8d8df47878ca59117
+Adata = feccf08d8c3a9be9a2c0f93f888e486b0076e2e9e2fd068c04b2db735cbeb23a
+Payload = 610a52216f47a544ec562117e0741e5f8b2e02bc9bc9122e
+CT = 83f14f6ba09a6e6b50f0d94d7d79376561f891f9a6162d0f8925c37cc35c1c8530b0be4817814a8e
+
+Count = 53
+Nonce = b4cadb5f9cb66415c3a3b714
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 22bade59214fa4b933cb5e3dc5f096e239af4c2f44f582b0
+CT = 2296e3f8a2245224d274f1b90ed1287cbeeb464c70a89ee475ecb546efb8872a3f8b0281b3901752
+
+Count = 54
+Nonce = 72e6cebdaf88205c4e744286
+Adata = feaf010f462ad40a38eefb788b648e1cc292cd4bb08ebeff3c39182862296042
+Payload = 30655a6b5a5965db992e7248d24141055e988d726abb8e72
+CT = 69b27f2bbaa61c4f24e1c25e0779147fef79ec1582486b4651cffa571570618e2ada3376bd9f3e5f
+
+Count = 55
+Nonce = d8030fb31eca2c43f3f5eb88
+Adata = 66704365ddd0145febeb33f68b228a3f09e1e5a4b68149e6e06d886301841295
+Payload = 9d014a02507a6f266bd1ace21b55ab8b73983ff503bb9adb
+CT = 233a883650538ab8c0da30b90527f880fcad5b16bd435e762beeeea7a638c717e63764b3a5118a0c
+
+Count = 56
+Nonce = 58038cc35ad3dcd75195e125
+Adata = 3da7a757e942409a3b39ccdc0669ce6401f7e133c07c4c42e366d70a8e9bdd49
+Payload = eccfd817fa5e3a0146967fae13fc2471ee3944cee37969f4
+CT = 415a36872a04f5b4b5372f63394ab9fb353e0eb9b430450133a87fa29e5fbfa9bc0430b0cac00b7e
+
+Count = 57
+Nonce = acd82ae31bfcabd90af5af45
+Adata = ce22126f01bde16249c47102b4da68ad3edebcd4a16c24a16ea7ccdd5d364d10
+Payload = 9d2126d34963d3ba12cd841bd321036cb82cfb78f2a6535f
+CT = 88a5b889e6fd74fc15336e23374b430988416c7e6b6e7248b336cbbeb64fbebf2e7076a98ecf5bbe
+
+Count = 58
+Nonce = d24457d567fd0a65fdabf219
+Adata = 0091d39f3478d2c59bf874b96db9ce0f7e8b85a9b805e07dc96b219819d51663
+Payload = 6da3ac85505e93c4f391ea367a9e15fa9b388ef7ae2693c1
+CT = 7039a8a49cfa6402b4ba3b840e69200c13ac4a3eb1c709a30ea909047af4998c660afbaf346ed65b
+
+Count = 59
+Nonce = 50c59ca54eb64575b82b13c6
+Adata = 5e4e42cbf172853c351d597c7d6d38b1a9cbb7ac92c00863a80ac4a2d9f0e7fd
+Payload = 25b2ba0a937b71f3ee68e7172cf2c4524b662efcd08ce2b3
+CT = e95fc44287ce39c5ad6b91c88582563fa68a9e304094deb8b193dd767f17783f0b51ac0fb7323301
+
+[Nlen = 13]
+
+Key = 36ad1e3fb630d1b1fbccfd685f44edd8984427b78deae7a9
+
+Count = 60
+Nonce = 3af625df8be9d7685a842f260e
+Adata = 308443033ecd4a814475672b814b7c6d813d0ec2a0caeecbcaba18a2840cdb6c
+Payload = 8b9db1c8f9b4892a5654c85467bcffa2e15e28392c938952
+CT = 6bc6890fee299c712fb8d9df9c141f24ee1572b8f15112c2f8c99ccf2d82788cf613a61d60dae458
+
+Count = 61
+Nonce = 24eaeaa437649e61b706942b8d
+Adata = fff75462f96157d9554bddb6aac156fefd88fd4a90a8536dfc28cc577f19c83a
+Payload = 49ff4ff85f7407ca383cfa4fd7177adb4dab26e642c8186d
+CT = 3647fae50c588d792442f43a20125e77ab5db3c469391d24d0a421bbbc002eb9ac9ad01f625f824b
+
+Count = 62
+Nonce = 7325932d6694aaf61a8204c172
+Adata = be20ceb8ca14e9bef7158b280a26bcac763da79cd0eba9b1833ea808c5e7a66a
+Payload = 2861494eb40b9d964d339797c1b6aac63c6674187768957c
+CT = 286dc74001e2a6000a23db164f4b2912de4afcf1df8c3aa5ee32a7ffd4e7bc303d3482fbac431828
+
+Count = 63
+Nonce = 61c9949df5853e42599e5ee0c7
+Adata = 243d09ceb16755cb58d62065df84890b840ad9b7eec1132c6427cd7c3d843fcc
+Payload = 943a49073db6ae94a88844ed895f8fd99ed25c3f42a2f78c
+CT = d3c56bd265a2cb0811dd218f248800ceade4f02b5403b9635eb30cbec49cbb51c41cd5032b7fd759
+
+Count = 64
+Nonce = 07b6c18dd3b0fd9e8ff026a436
+Adata = e85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b8ca9f321a178a2056806
+Payload = a18b0a4618063c0519818d113b8e5435aaf153f664058f1b
+CT = 69f933a2a5e774e8d013cbf78c6ab0b73e6ca323d0c52691acb5cf2631987d3d963349b035324aac
+
+Count = 65
+Nonce = 0c075df70630dec2fe81834945
+Adata = f3f5c5ffbfe8247bc0c33c793652f749fe91b6dd141cf0db56e71cef8a2fd266
+Payload = ddc4bac4115e8cb06d29d22e400674dbc615a667f933603d
+CT = 26bdd25c9f204fc7520d26c161464c28fb35e395b295b3db4e239d33283d18415b54c2aad4bde354
+
+Count = 66
+Nonce = 0c2d20375057fcd4241d290f6a
+Adata = 70ff1b9ff8ec08fdb18b0e7dbe01127ed0cfe0b0a449ca2ace4992b7b6248b71
+Payload = dacbdf1979e000d52b573e74800761b30acc26681f372acd
+CT = 6a642c389433a3464fc64783ae6a14a9a45f0998b56a5b9162d7e0320dc930df3640a786d7ea9ae4
+
+Count = 67
+Nonce = ea0801cb3dab853750a922dd25
+Adata = d83360d0896e022bf014bd33710ab212ddedda6d95a54996f33db304e5f12f01
+Payload = 46cc5653bbd8300dfb0df6d0af3fb7c7639a830bdc9f68c7
+CT = f1b0728920351d9edfdbe7df360b21f6cc5b628dcf43a3f10d06b4a545609a2128a95d4d73471559
+
+Count = 68
+Nonce = 97e6de379c90fccf3fa8f27013
+Adata = 539f8eb802bfecaa4fb5b19debbf3d4847db9c4e0473a308ab3f3c859e68fecf
+Payload = 8b013f52a828905013f250fb9c006a173f6c66a64b5ba317
+CT = 556a439bc979dac1cfea8c5b64aa78547f52a62896c19893f3512baf72cd79ba9301194be204bcc0
+
+Count = 69
+Nonce = e832b6330d3e5e190598cb9c61
+Adata = 093be516277e8b197ba5e9c85a831529befff0f3971510ab611dfe0dfb50a2ad
+Payload = 635d2d7894bb816f154210946a369df37ea492993ba23af9
+CT = d8e19c67e5aa7f14a16ecaaac414a2b15a15bb5f966932e6b0bfe9a5857fd36df94aeadda7f83a79
diff --git a/lib/crypto/test/crypto_SUITE_data/VNT256.rsp b/lib/crypto/test/crypto_SUITE_data/VNT256.rsp
new file mode 100644
index 0000000000..2817684910
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VNT256.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = 553521a765ab0c3fd203654e9916330e189bdf951feee9b44b10da208fee7acf
+
+Count = 0
+Nonce = aaa23f101647d8
+Adata = a355d4c611812e5f9258d7188b3df8851477094ffc2af2cf0c8670db903fbbe0
+Payload = 644eb34b9a126e437b5e015eea141ca1a88020f2d5d6cc2c
+CT = 27ed90668174ebf8241a3c74b35e1246b6617e4123578f153bdb67062a13ef4e986f5bb3d0bb4307
+
+Count = 1
+Nonce = 195c0b84baacc8
+Adata = c7d9557b2ed415652ce6faa8cff5217ac803530ec902890b31eaaf3eeb0aa98b
+Payload = fe012718481b2c4e1d7f9a7685e3daac43ccf22cad0df900
+CT = 893af0f130f1317de9f217234274b0c04fcc202cea9a0df882c00b5b463654adbf82888099a7d258
+
+Count = 2
+Nonce = 363e0e921c6f11
+Adata = 805678936d4e94746ab4818dc5f50c41e32cf32e7a8aafb300fb91af6406108c
+Payload = 7e7e33e1a07d4e8fde2f33304f21cb564d146860ccfeb49f
+CT = 645cdd11a1c232815ce1e07ca3ea83f372eba46cedafddd980adf2762a1617adfd4d8356bb48aa8a
+
+Count = 3
+Nonce = e323cc866af462
+Adata = 163c747f3ba4ffd68af87f2475f48f2714659a2ec43b9ed115e02fe0e3c8be99
+Payload = 2bfc76f3b108ba3118b07433c4d3d5f41564d22547c12822
+CT = 0db04c6b068e73e3c4d71059bdeee3d27622f99dfd07d868fb9c02753c57fec7e1a5fa8f3860501b
+
+Count = 4
+Nonce = 03ae777078b95d
+Adata = f1dacf9062dff9a6a3d0498f9d058782f891475684196bf2d8e7e905393acff7
+Payload = 38c4275a5f605fd1d99517e13deebf0c9794ef586070fa9a
+CT = df8f524872b5f06f3f219ba76524990b466409894930d7e0d104990e598eabd88cc8342ac16424b5
+
+Count = 5
+Nonce = 1c6c351d4fe9be
+Adata = 14285e97cc3cae452e1a52e2fa0bbe24df96abf2faf6b9779acc59764612eadd
+Payload = 9e2220f3c17532e1ce0d6f562b049fcef35bcaf9a7e196be
+CT = c274b28228a6b13b670c325080f88d188d40d78d385481eae004894b1861db5d2d8ae98ed8926c1e
+
+Count = 6
+Nonce = a121dc27479397
+Adata = 359421e9f78cc4a31f4f019977d7fd29780524e20288798c50002a682a6368b9
+Payload = d42b16b32e77637724144eaddb21ca8d7db4e7f73acbf707
+CT = 56e3e3e59e978161355e7d8573dc0657db400ca0b083dae8ed2ac2cb63e1b9d7dc598634198fe4fc
+
+Count = 7
+Nonce = b1f0e26b60bf1d
+Adata = 2ab4239fffd13762fb5391f5a4760d12d96ea12666a793b4d651e9f4891c22c1
+Payload = 9a2851083ad4e7b915bb0526bb4054e4c0b4adf8626edc90
+CT = 5b2e0215523ff37f0df46e84f996fc9fc779986c766fa51595b8a23ee377d5c2850f4ed95a385253
+
+Count = 8
+Nonce = 50412c6444bcf9
+Adata = 09cdcaa87ddf8bbe6db8411d14bb9064e4a121286cc8a6e97fce1844935f436b
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 05cbc32a6ca797684636dedd16ce65a1eed69bcab1b1bdbd514ef5cbf9991a919fb4974d55506ce1
+
+Count = 9
+Nonce = 225557b0faca3d
+Adata = 21611da060fa90cf7fd68b721caf303307a56e56453326495b628c7dc93cd175
+Payload = e831b739e8eb9f787f63c0bb071ddcc9f44cab8d5b447d23
+CT = a97e0879407eb3b7f93118ca73f17eb34e9f4baf43b07be2e8a3f7b848054cb235e1b58d6a12c5cb
+
+[Nlen = 8]
+
+Key = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+
+Count = 10
+Nonce = 790134a8db83f2da
+Adata = a7a86a4407b7ecebc89434baa65ef173e88bd2dad9899b717ca578867c2d916f
+Payload = 59eb45bbbeb054b0b97334d53580ce03f699ac2a7e490143
+CT = db4961070f528ccd1a5a0681ee4d0ce3515fb890bccedc2dbc00b1d8b2bc393a8d09e87af7811f55
+
+Count = 11
+Nonce = fb2441d1594a488a
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 1bca7b0d35a68c0ffc568ffc8221cca738b67b95e3ab26efee21c5738d1f7fddf3030d004a702704
+
+Count = 12
+Nonce = 0855263860043207
+Adata = c7fc24863c33f7e8cf97b337918495d52d864ac570c99cbb09d151758d6b504e
+Payload = 61fcd7ef9bf151b9d8a81dc1ba4f82c45e9c2e4784627acd
+CT = 9b939b6b188e1d0fe016f366fb01eb79a99ef7b1b57c6f7ab223454c57c714d96681cd4d55615afd
+
+Count = 13
+Nonce = 415cd251a5e36943
+Adata = 1a393c7e85fb286709f4eb50f09640e1d65ec1135cb4443820136b3cec69772a
+Payload = 66ae08d494dc9df9b7f8f53199fa37d0c88885458b168c57
+CT = 1731e260ae31b8068ad1099313b167d9e6cbe49f471da61a9af96d3ce4ea94213b60cb69d92050e6
+
+Count = 14
+Nonce = d95bd65242bb2265
+Adata = d0e20e1358be5cc1c45c1cf02c82d0a6d0824cfcb65774cf95f047b9f2cc1d3f
+Payload = 312c3791c64d79205a11eebfc14b2d7a6b00391793c9559b
+CT = c3fbe558ff9ea83ed86b7d66503ee38eee94e4a41fd53f0f627a352d056712e0d44404c61712e2ab
+
+Count = 15
+Nonce = 3f0bf0141dd3ace0
+Adata = 9dd4ed18209dd6cdf19cc76fee443827e7331aaf020960c15d7bbed0f6a3b1f7
+Payload = 08354480047eee3beeb5ab165da17d23f2f1a4ad98720611
+CT = 2db9d2c54134d37ebefcecb9e2076034b975677fde58ef6032645a322fa9bc8aace600f942a84db4
+
+Count = 16
+Nonce = 3fd8b3a3ff563a42
+Adata = e58327efebad3276a7cd1b1ccb56db0caddd02a303cd9fc7ea5c607a2ebefaae
+Payload = d1abd89351384e1a3c3366f77c3175f6390801554d7cd783
+CT = be284dcb357ae99ada7cc891730320ebb32ca627eb8c80623957a2a5b6164218fc83e12c42d5c532
+
+Count = 17
+Nonce = 14db1ffc1c87117f
+Adata = 6c2b091433833a0ed915354dcb70d982095b614dc51a95a22cec417184d8e786
+Payload = 0594307491f157821e63f50c94034f9284f095d5b897153c
+CT = a114c84a10071e359bba2b2ba4ea67f893e27e6ea880aa4b2cf16ce68a93f8839245baebb2278300
+
+Count = 18
+Nonce = 40b0f74ff27a3fc8
+Adata = 3b9e1f4e9b57a6dfb5e0ca7ef601fc6af30a1f8650228e51e0dc61180d0bec6b
+Payload = fc8b7dbceef6b0ffcbade789e09303044042cd671607e819
+CT = d00ef56074a8213740af8b8f974f778db560ac365d6ce916b8d191130e864bcfcd1dec94a1aaeaef
+
+Count = 19
+Nonce = 96cbe9cd19351359
+Adata = cf498fd042f9a07503e490cec4873d4df91162cfde60bd2cbb2b710c6681a9fd
+Payload = 315e81c9ce556dcf97a5b68503fd2228a7a6a174a15cd618
+CT = 7383c2de08bce3f0b7e504dc03d062f44396bcedd2180fd954e6ec9f6ae1e0976ecf04dbee6463c2
+
+[Nlen = 9]
+
+Key = 58ae7965a508e8dd2eda69b5d888a28a1cb3783bad55d59d5b0da87137b72e93
+
+Count = 20
+Nonce = caa3d928d2bf2b7f2c
+Adata = 304678b3ffd3200e33a8912bcb556b3cfec53ca17f70ecba00d359f9f51d3e3b
+Payload = e61bad17640ecff926d0b0238271ee4c9f8e801dd7243e9e
+CT = 7bb1137c14cb4d324a4a8f1115c619ebf74927f0bed60a8d5a9140ff50dc4da375c7d2de80de097f
+
+Count = 21
+Nonce = cf09ca67659a583bb1
+Adata = 5507c4c3107cb446d19975f91207dbf3e2a51d1dcfd7da2f082159dbc3f41547
+Payload = 1887bb0c02500093a30a44b99e137483704b06615d308c6b
+CT = 834d3b2e5f0915c2348c706b4d2ff2717983ab4490edcc63971f02b7122d1e4f78de9c3376520f5a
+
+Count = 22
+Nonce = 97f940d7c1230bd8d2
+Adata = 56be2c9e09b555373d58f6fe2a0ca9b4ddba899addddf12b0fda860ad791773a
+Payload = 5ac67c9bec9b95c54e187a4a6812f5d701c4ac8f847c005b
+CT = 9f372ba1c87a115847cd708aaf5b8a143b6981ffc2c61cefd30ece13481609809b218de04c4e5ed0
+
+Count = 23
+Nonce = 147c7ebb6c92245054
+Adata = f95d64a513a9f3e6c95c9ed27b22fafd7dd10da52636029523142149116aff53
+Payload = 08f199a8d7e3ea821dd3106e8947cd2e9d485342b25a6471
+CT = c438aa6d187643d030dfe4d6b5b578f84838f4dc5c396d700c0986ecd7dab44e5e97db37392a485a
+
+Count = 24
+Nonce = b9bad794d49cdac9b3
+Adata = de9ff2a43f49cdc502cd17a373989bafd13fa6ccff6660557ce05b6295186d47
+Payload = 40d1cd4063750184356a1d7cae1cf1824f552c5d59a62dc1
+CT = 9952b25f4f4f375440cd958456184fe61610381ba92ca48f38dd977042c4d97da84e4effa650799a
+
+Count = 25
+Nonce = bbe054fbef86db3ce7
+Adata = dcec76181e3b872a5a6e79f070354e38866c7f67fc428fbca29ae6d929b1dd7f
+Payload = 5f29808ba74b672a0f82b3b7581dc32478c6e790e2b8c61c
+CT = 4d176f48b09b772dde8adbdaef720aba128a8d38a902847ebf22c81a5d824b4916660be6f9b513e6
+
+Count = 26
+Nonce = 6a35e1a4307f6efc6d
+Adata = af28120505a84a75b0f6b18cc9d8c75c661bf143be29c11d8ede78b9bb98c98a
+Payload = 5e2f601395ec406fcf96785f768162e849f867dca77667ab
+CT = 4e305e26d34711c6aa775f490939cc6560d3cb6905f5b0f5588ace6fc303600abc8e5825cbaedc7c
+
+Count = 27
+Nonce = f6c237fb3cfe95ec84
+Adata = 038f8ed89444784417a9c23bf11e9b436174e6c10959e00faa1704ce2f7f2c7e
+Payload = dfd9cacbf7d73d688447ebab13d2e13f3613652379b386f6
+CT = fb16c17a6b22a8658f446203ad46a48b34808083b271cabb015a1f78abc287bd2a63381ead07c558
+
+Count = 28
+Nonce = 50d024a3e7455d7249
+Adata = 8513365786b7988b208984e11022c15573f978bbdc29e8a7a4745c8a81885a1d
+Payload = 400317786b7df63373ffe541efcee6318cfc95bb673aad3e
+CT = d33b3141fea3a9ebdeb80d1da32dae42680be78471fb3023721f714120162514555b60560afa4256
+
+Count = 29
+Nonce = 02769283d5a06c363c
+Adata = 292c0be3713c6c588cb4e29a1c43b3e6353e33556194e568e800e4e44e8281e0
+Payload = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb
+CT = b15b1789c323a68568f86f35483bd7e204beff8f318ae14351f5e62b3b923a937e6c307af202fab3
+
+[Nlen = 10]
+
+Key = aecc5e18088bf9fd7b17f089bdd5607b69903b04b726361f8a81e221b1c91891
+
+Count = 30
+Nonce = c527d309ab29ee91c5fc
+Adata = 8f9a73e7bc1c11e2919020ba3a404cbddf861e9e78477218e3be2cd4337b278d
+Payload = d4291c99901345afe29f58912a414a7498f37b44362bdf3c
+CT = 392784a9e0b14bcd37639ec5409d6ead3e75f855e5a92c33ffc040ef3977e0035ce6ea6d157c18d3
+
+Count = 31
+Nonce = eebc31a5813b4fb93b63
+Adata = 9c87ad77953bf8a811e001ddb946eefafbfaa598150e85f0701853fa307d77d6
+Payload = ebcfd71120b0f9a2cccb898e6dfa082998cbe10032de3e61
+CT = e38eaad1e2df77e85e7129a8ce0f82cfc32b0aef79ab651bade65aa17e4dfb0aafe18cf71a72b180
+
+Count = 32
+Nonce = 231b33dc406c9210f59a
+Adata = 38be46d271bf868c198052391f8a2147c663700d9bb25a0caaa36974f18dacea
+Payload = 9032f910347daf661092b5c1f15b5ffed1369b194d9e12f0
+CT = 868b85288828501cf1d06610fec25e8b8a4b437e2e4f5563b7f3b898a2356909784598f8a8916f5a
+
+Count = 33
+Nonce = f2a88c3ebc74e62f24c7
+Adata = 5f495c5da035cabeb77e8aef10e91a05bd5aa414d1a37fa1099af959b26e5403
+Payload = cfe8ee9b475e36058471e2984ae66f6ba1b3cb477b15155e
+CT = 22c16333ac651cd9c183e78aba3e9312fb3b77dd6f9199502788860aae5534cf84979e30c3327d37
+
+Count = 34
+Nonce = 9cbaf1c83ba60b1e90ea
+Adata = 7ef136bd9a5809676abbaa68016d6fc713e34ac4b768a8246b1198c959f43085
+Payload = c3bcb0aaea93893f05eeb6439c8619dec17670a6439e2921
+CT = ebd9fb86563aa8f10062624441336f982c161ce5717d990a599ca6ec1c61a14c37b5902389e47aee
+
+Count = 35
+Nonce = e25322845d87d8a76753
+Adata = 2a89b9f0e56a1cf87dd38ed78028b6286ef8b7141dd2b3c65c5a8e1ed79bf4aa
+Payload = ae622ff9381854f831892c318bae5c003e74b15199bc12c0
+CT = 144c920f0fe278f353d0b053563d907c7589e4f1479d7a93a0604deb3fd9cea2d89987833ff5c2f1
+
+Count = 36
+Nonce = f4d7978fad36223623cc
+Adata = 8671de7e994967f2521d263925e745af9273682d9c08ced07d4a98fc985f68a0
+Payload = ef9b4ff8da108cabc972192ffecd5f96594c6d0871ffa6aa
+CT = ae4948b3bc1e50beb9f5d005871fc0d3dbde295de1c9ec3cbc866ab47bea7a4d0070e52b492fb8f6
+
+Count = 37
+Nonce = 6597ffb9eaad0fd9d830
+Adata = d2967ddf69ef62a9e23c9118dfaa55df92b4116322f1c9275131e3875dc92faa
+Payload = 5015c894b2437ff15c46bca9236830ff4bb057cd5764f027
+CT = 0b1dcb3cb0b4c32f398f3c43eccfe8f4242f33c99a2a2283efcb3dacac25bed0304f227fd5b77b8f
+
+Count = 38
+Nonce = 80e376b87272d99cde28
+Adata = c9cc8f967dff45c05b9345d03813b6e30dace99556f7df75b7120bb6e5f55827
+Payload = 615f657e24129a3e0f119988959608821219ce8354c4be26
+CT = d3e8b8f7ff8faa666ffe2509187fa7befc7412fd4e3bdb06cd2f7494b1fb0a0c6a2184e5c4787fea
+
+Count = 39
+Nonce = 344cce96455541d403f3
+Adata = 748cce18fb40126ce125dbe341fbbc59d2aacc170ed5ef0293b15713c9184a07
+Payload = 828b6a4cd49f499a6e8e8508f9ab35255d8e9fed33ba4d91
+CT = b67e582a74d7f022a16ada2de7ec18caafdefa6b104baf4ed93b6f8c8a1bf72be75976e4ebe6dd1f
+
+[Nlen = 11]
+
+Key = 97bc7482a87ba005475dfa3448f59d4b3f9c4c969d08b39b1b21ef965c0f5125
+
+Count = 40
+Nonce = 0bcf78103ec52d6df28887
+Adata = 049c10f0cb37ae08eae2d0766563b7c5a8454f841c2061a4f71a0a2158ae6ce5
+Payload = b99bf4dc781795fc4d3a8467b06e1665d4e543657f23129f
+CT = 0d3891fa0caac1f7ebe41b480920ffd34d4155064c24f3b17a483163dd8f228d1f20cd4f86cf38fd
+
+Count = 41
+Nonce = ab6374c6b2faefd92fa3d3
+Adata = f19c044023e5cf339203738ee70e76527519763664c06ae00e002a5ba94c32c6
+Payload = a2e5c51f516db01688b64c173bb25645182a005018022ee1
+CT = f70c598df3c64d3527ebb7fc8408b7de2cfaa1da7984ec361f1ad61758d828b70d4881b7d6ae8cd0
+
+Count = 42
+Nonce = cfb89e7ddcba601e875110
+Adata = 052714010da516c896ac5842a839ae845324643cddb080e6206148432d0d0407
+Payload = 037f206cab78a6ca0745dc8fc137e22e14f3d7183917ef83
+CT = ccd675862502a2e2520a33250150b8b7b220e84db854888c316dd62075fc761e2bc80edc5c564bdf
+
+Count = 43
+Nonce = 967cb6f8530bf8a43adb42
+Adata = cf391a84d03e2e22aec1965cec821f99e7bf21a7c3580dffa531464b22d83225
+Payload = caa3d928d2bf2b7f2cd8a7f357055b6d6895a5e34f47972a
+CT = 4f4f509debe6e52eae4af8b1740dde0a5338f78711a3b4ebfc8b5aca6d606222d6af7cfea0d1f4e1
+
+Count = 44
+Nonce = f5b7b5dd2b5e1ec93710c9
+Adata = e7a6b228a67d37b9d29a38efc547e50b4a6d95d599b45ee189ece21101ac6b5b
+Payload = 4a74ff35418723f2cecec1012484b52114067b2b2393e7f4
+CT = 25b140922a9d4f2ce153a4ff86596a49d7de6a6184e931e8b2ff27a98029b23484e00c2a5d291887
+
+Count = 45
+Nonce = 713de00faff892977d99d0
+Adata = 14ea93488d4284d21d4c7ce14414adf45c1ed9d2d99db866d0e59accb6234dac
+Payload = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698
+CT = e4d92ab8d1ffb0976670d891cc8338da12f86d5d79b334103d2ae816edf857c810b6fdc7f2c71f1d
+
+Count = 46
+Nonce = ba87934808de09b2ae829b
+Adata = 30e2ea2a505f19e8760a0a84961000c7a0b7fe3460a9d3f5a38f54149be2e9ee
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 6df893eed2be958e5f542f8cb4adb392b34786cb4ce821ec93fc57997b977948d55bdb026db5bc48
+
+Count = 47
+Nonce = ea09fbe5da0fa4fe911e18
+Adata = 237dc8512b29bccdeb8ee39cf83b9b6dd203823d175c44d5f605b194e7ec136e
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = 2f204ebcf549ee2a800d870e6341b9a89a41ab4ae91b6902ff704a2bcfb8becd0226f76d68fbb08b
+
+Count = 48
+Nonce = 5b80d7affc4ab4a4b68bdd
+Adata = 3a38dd7da30f5c312fb1e978d87b7a39792fd9ea3e9ab1565874e99df587327c
+Payload = 5ff92f6d3ca791421363e10cc84b4e8e21e0ebe5d8c55d6c
+CT = 05472db7875d59f8bed45606f355a516de93740aa2baeba18df9400df42baee6b9a0d75b45840104
+
+Count = 49
+Nonce = 514bba483fe7f2b7e555cc
+Adata = ac8beb419099cdb42a39e9b46fd900cc52eec4b43a96ed18b37b899b63fb931c
+Payload = b0b11dfca9b3936d1b4a423c5acd3d012b399a487c19c994
+CT = fa20629d514c4ce7bf727629bca5aa1c0c7e7851fc1bfc5c847729a70d7b4cff5281aece37006015
+
+[Nlen = 12]
+
+Key = d6ff67379a2ead2ca87aa4f29536258f9fb9fc2e91b0ed18e7b9f5df332dd1dc
+
+Count = 50
+Nonce = 2f1d0717a822e20c7cd28f0a
+Adata = d50741d34c8564d92f396b97be782923ff3c855ea9757bde419f632c83997630
+Payload = 98626ffc6c44f13c964e7fcb7d16e988990d6d063d012d33
+CT = 50e22db70ac2bab6d6af7059c90d00fbf0fb52eee5eb650e08aca7dec636170f481dcb9fefb85c05
+
+Count = 51
+Nonce = 819ecbe71f851743871163cc
+Adata = 48e06c3b2940819e58eb24122a2988c997697347a6e34c21267d76049febdcf8
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 70fd9d3c7d9e8af610edb3d329f371cf3052d820e79775a932d42f9954f9d35d989a09e4292949fc
+
+Count = 52
+Nonce = 22168c66967d545823ea0b7a
+Adata = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4ac9f3b61e7e8047fd
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 30254fe7c249c0125c56c90bad3983c7f852df91fa4e828b7522efcd96cd4de4cf41e9b67c708f9f
+
+Count = 53
+Nonce = 225557b0faca3d6cbaedec5c
+Adata = c7aafe7d3b419fa4ea06143897054846ac4b25e4744b62ba8a809cc19253a94b
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb3
+CT = 2369b56f21336aba9ac3e9ba428e0d648842a7971182d5ffac57f6ae1080efab4ed93f8b4ce1d355
+
+Count = 54
+Nonce = 78912be1a35e156a70fb72f7
+Adata = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb80d77fab2c4900e0
+Payload = 113efd182f683596862ccd5eba2e2d4ffa709d9b85c6f1d5
+CT = 835a22eb8d718c0ee1531a2d1bb95f58215c997c612908eeed3ccaeb7a814f69d3ec1fbf2ee9792d
+
+Count = 55
+Nonce = 91ad90b58d2044abacf957e1
+Adata = 4fc795b9126c23dd7fd514c2e5a8ca583e88a783b28cbb2a5df09f8b520ba0d1
+Payload = ed55f6b9eb8fe74474c037ede94ffd84ada846ede4ecff74
+CT = ecb595276fd5d412a7cc3f5cfe960f47a0d0e2df0b08a11ac257d67143722a976c9d7f44b09a767d
+
+Count = 56
+Nonce = 4bbe4ca29122c4892ca09b5b
+Adata = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364449b2391230be846
+Payload = 8dd497bb777bbc3e56e3af25a43545007bb00f2b9e9f815c
+CT = 563d61fc0a5b82804a580a7d752a8e61d3342fb39372b39b6843a685bde3175695796f6e64f35901
+
+Count = 57
+Nonce = 218e7b8a8fd62927f90b70e5
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf001429122e46bde21735f63adba
+CT = aaceb16589b9de253c99d0d32409a631db71e8df8a7644bfd027e3466e8220144cb0552f9b2800e6
+
+Count = 58
+Nonce = eecc9f106a0721334cc7f5ba
+Adata = bf38d0ee11a796a517539bbc9ab00ff85a4ddbf0a612d46e2bc635180ad34c50
+Payload = 36cefa10af1a3446a2c8d4a1171144b9ddd8e33a7cd5a02d
+CT = 9bf3b2df93cf5b587ecc96f45fc75e6eb066cb286cb06f284c9027fc41bb8c848025fcf9d092a873
+
+Count = 59
+Nonce = e41af8ca408c4c12e37561a4
+Adata = e0b20892875f60b5d8763a04958487fa5b7cf8d67a456e430475b337245d671c
+Payload = 32a4da08bdd51336ed5798c7177b853a534bc98f2e6f7d4e
+CT = 95ffdc68f721cf2294d0d88002e3814167306fd906dbebdb7e6e0e5dc0a03826e51bd94269d7a41d
+
+[Nlen = 13]
+
+Key = 4a75ff2f66dae2935403cce27e829ad8be98185c73f8bc61d3ce950a83007e11
+
+Count = 60
+Nonce = 46eb390b175e75da6193d7edb6
+Adata = 282f05f734f249c0535ee396282218b7c4913c39b59ad2a03ffaf5b0e9b0f780
+Payload = 205f2a664a8512e18321a91c13ec13b9e6b633228c57cc1e
+CT = 58f1584f761983bef4d0060746b5d5ee610ecfda31101a7f5460e9b7856d60a5ad9803c0762f8176
+
+Count = 61
+Nonce = 8a56588fe5e125237b6cdc30f9
+Adata = b3aee5fbf409bcfe9b46ae68d570edbbed32c12d13926ffb5ddc60ff0bdb7f85
+Payload = eca81bbd12d3fd28df85e2cc3dcc2ecbd87408002fd00fe1
+CT = 9aad62a5443550d11f9efdab2de0eba74d47ae4f7d16adf4276664f6567f2f978bd4be4d80cd07be
+
+Count = 62
+Nonce = d908b04840caca2280e5293ade
+Adata = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+Payload = ad1109ea5c79bb55d22e9713eb2df42767cb29a2eba3ad2c
+CT = 61fdcebb158cd03151697ae7871c0a998802997e0672e5886e5a9df1b1d6284ef657cde6f74734bb
+
+Count = 63
+Nonce = 6df8c5c28d1728975a0b766cd7
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = 704f60f9cc3ef7bc00b4f7a271ca70a89f4d5605387b3e2f8cc80aa08572b90e9598d0a73712b720
+
+Count = 64
+Nonce = 6c6ebacce80dde9fefb7e5bb47
+Adata = 93f0fca0c8c84d5cc48160b25e246226d489225c0f8275e52856da592c715aa6
+Payload = 46820aec46ebd0d61706129584058a1498514928a87fe620
+CT = 00f6cccf45f046da1e6266afe61eed61c60c28515b2e1ab386b2c952055899184f0d95ffe3959f89
+
+Count = 65
+Nonce = b94bc20d8c9abca7645fc6bebf
+Adata = e1c083c93663f5a066ef337a61aa3fddde7c301a42463137c375cc2dcdd76954
+Payload = f1fca581d3dbbc61060c0c02adb47bc57954d25a283f66d6
+CT = 90c65d23e0e1786cebb95f9b1306d001b2e503842cdedb75e37a53d77b9e38605febdd7b2b666f98
+
+Count = 66
+Nonce = a4974791d417d7e9eea0f4ae8d
+Adata = 33602f308f3a0f7e1c75fc1e4321d545ffa278234958dbadd37f59a0f85349c3
+Payload = 41712c058d2d56b43b2c79278e790858a289320746c15a60
+CT = aab5656a1ef060c9b1ef7e2f3cc0bda40ff067900401182563ceb824708a20724c99c83f1caacd70
+
+Count = 67
+Nonce = 6003b771afe4e99e1ef1ed4a31
+Adata = f60d8362b2ebf523681bb051fd3ee13919ad86acd963c703c4178a5f01a84236
+Payload = b766022311c5e1d74a607fec7cb8ee805b8397a6c5f374c1
+CT = f73b2a6dbf8f798d4bfb489a6578c9c79152e42aa3b81b64a84e7af3116a18f7ce44ae93f420270b
+
+Count = 68
+Nonce = 27861168ac731a223dc35c03e8
+Adata = b7ba1c66282cb6092ba601407ff9578afdadf7ba7a4d08edef06dbbfd87171bf
+Payload = 0822e3e6ba982091d532cd5271fbde25305d1f6e71880f81
+CT = 5ab3e5296cd1f08704c82f6b42939702515b7733853d723d4009312bdae46958d844eca502bcb005
+
+Count = 69
+Nonce = ef284d1ddf35d1d23de6a2f84b
+Adata = 0b90b3a087b9a4d3267bc57c470695ef7cf658353f2f680ee00ccc32c2ba0bdc
+Payload = bf35ddbad5e059169468ae8537f00ec790cc038b9ed0a5d7
+CT = b702ad593b4169fd7011f0288e4e62620543095186b32c122389523b5ccc33c6b41b139108a99442
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT128.rsp b/lib/crypto/test/crypto_SUITE_data/VPT128.rsp
new file mode 100644
index 0000000000..f79db90b4d
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT128.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 2ebf60f0969013a54a3dedb19d20f6c8
+Nonce = 1de8c5e21f9db33123ff870add
+
+Count = 0
+Adata = e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603
+Payload = 00
+CT = 0ead29ef205fbb86d11abe5ed704b880
+
+Count = 1
+Adata = 98d477b7ef0e4ded679b0bc8d880f09823ad80e9732fde59c3a87da6a1fcf70b
+Payload = 00
+CT = 5b85d144bb51d4927074d3536a2db83a
+
+Count = 2
+Adata = 28f32de10b6c9d3c3f46efec7aee24006208a54c4d1c2bba4b8cdce166cab7d9
+Payload = 00
+CT = 01045de4a09486eea5efa33ecc6cd299
+
+Count = 3
+Adata = af397a8b8dd73ab702ce8e53aa9f0189995c6c9e920dcb75795149550b499deb
+Payload = 00
+CT = dfd75400b59c3ad387bc86dfbbfb52ac
+
+Count = 4
+Adata = 3fa956bfaa27e249bf0a1276468d808259f3b8e2687851d780885d44cc2f04bd
+Payload = 00
+CT = 2b11d2549b4e2f0a81c07ee90af4d081
+
+Count = 5
+Adata = babbd1b44cae3af06e0150bf0e3d898f6fe862b71ea9f6b727accfc18848fc79
+Payload = 00
+CT = 10f76ab445f4ec158ccc1f7c6fee3ede
+
+Count = 6
+Adata = 7fba0bfda3b03c736c121cf9a257db55060b621be5168619ec4182f13ef6a408
+Payload = 00
+CT = 59e02d6a6aa3fb2692b04e65a0e735da
+
+Count = 7
+Adata = 057354a29808f4ed77671ed3dc36f8b03f5cd952caac5cb80dc3b319f3333e29
+Payload = 00
+CT = 367a2ade4087964dcb0ca2984d44657e
+
+Count = 8
+Adata = ec08b618602d091e9304715cb552b357c16fd1d7f7f023a28d84a98ba21ca0ab
+Payload = 00
+CT = 47cb92cd40bc89328d4dd44fbd727032
+
+Count = 9
+Adata = 45622834ea658b09b17f32777d18b34b387ef957bd344468f68e7178417a7c24
+Payload = 00
+CT = f5185afb8359b5ef995483c0bc4192c3
+
+[Plen = 1]
+
+Key = 6ae7a8e907b8720f4b0d5507c1d0dc41
+Nonce = 7f18ad442e536a0159e7aa8c0f
+
+Count = 10
+Adata = 9c9b0f11e020c6512a63dfa1a5ec8df8bd8e2ad83cf87b80b38635621c5dc0d7
+Payload = 0e
+CT = 4c201784bdab19e255787fecd02000c49d
+
+Count = 11
+Adata = 73616a428f1a567b2e9af86b1fc8aec6d597b1b55f2aa2219b3b662fa6bd3407
+Payload = 30
+CT = 72f14519f06b63fac3d5b2d9bbfa0cb758
+
+Count = 12
+Adata = 6d62f4e15e8bcc9ba4993bc50a046737121016f0d15020b90068250551167b1c
+Payload = 34
+CT = 7676b581a28ca0a0ba5178eba7fe028da6
+
+Count = 13
+Adata = 8f0b8289a1834ecc2167b59ce3c9d3b58465c4cfaad50c728d04360cb7e5bc41
+Payload = ec
+CT = aed99b805c0a4785ff2913cab3e50f6205
+
+Count = 14
+Adata = 477b2a6932f838f0d1bc420c0ca306981d8e2dab945b6f259e15fe888667220a
+Payload = ec
+CT = aeb50e41cd7af84a8fdb6aee144e904616
+
+Count = 15
+Adata = d6518d409b1f05708d0b44f18fb5721f20f3220f8d2f2718650aa9932e4579e0
+Payload = d1
+CT = 9312639c863974f077fe8236c943b464c4
+
+Count = 16
+Adata = 865e7cde73b558e9bfd05356923f8a697970811fc484acad2d5b3528baf1f986
+Payload = 24
+CT = 66d7265cde50bc7a3989458437baf06db5
+
+Count = 17
+Adata = f0c3c67a935eace53ed32435655dd0974fafe283622e8294a15d70977398eae2
+Payload = c5
+CT = 87063144b25d2268063815d1b42ebbac34
+
+Count = 18
+Adata = 341e71b2ef26e9db03882e06d06cde2c0617326cd157d5984d22f6f3407a9c39
+Payload = 34
+CT = 767da45c10d0d6498716bcf3f13ca7e26c
+
+Count = 19
+Adata = 31fce6735ba9a3385df11c153179b8e4141a3c6b8ad6eceaa211f3f17bfd0474
+Payload = 7d
+CT = 3fcb0a6f562974cfb3fb7c8d5cafd50f2b
+
+[Plen = 2]
+
+Key = 3d746ae6cac5cefd01f021c0bbf4bc3c
+Nonce = 597b3614ff9cd567afd1aad4e5
+
+Count = 20
+Adata = 90446190e1ff5e48e8a09d692b217de3ad0ab4a670e7f1b437f9c07a902cad60
+Payload = 4360
+CT = e38fdb77c1f8bbac2903a2ec7bc0f9c5654d
+
+Count = 21
+Adata = 6bc3d30925c67371573271f1a4273ad76e91e07dfab65f7bce0b241b5e4cd00e
+Payload = 17c6
+CT = b72955210d62e1393e4fda647c2b2e59a47d
+
+Count = 22
+Adata = d1bb4cdfc3f2c16d92576068543692aa4b5a427d688387af0f1583e91a0e8b3c
+Payload = 6575
+CT = c59ad54fd88a47b9f6e39cb4606af86d13e8
+
+Count = 23
+Adata = ae6136df9ab43631ef143515dacedbe759b3459e951bfaf4712a21c86352f1c0
+Payload = b1dd
+CT = 11326de841af64b55bb7ebe3fd30ba493c7d
+
+Count = 24
+Adata = ffead34ac26e21158212d07c367c3a7cb6b795887ee2d3d8ae25c60556ea88d3
+Payload = cd16
+CT = 6df93a206339de534271f6469edfa5ed07d3
+
+Count = 25
+Adata = e768e7d867820d46c1cc62ee0e51d4dac6f5c4b5785b5ccfbf05236871bdce2a
+Payload = 12f5
+CT = b21aa8f65144f2ec5809e2ccb38c8760f7bc
+
+Count = 26
+Adata = 402e802885e4119df17fe85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b
+Payload = 39c0
+CT = 992f9af825957abe7d89e175b6e8c0b84b5f
+
+Count = 27
+Adata = 8a3a622b3d347c0c5210d484adf77fa33205ba02224ddceea71d89c9ad8429ae
+Payload = 912f
+CT = 31c025d6a12e91e84e355934547f6b5dceb8
+
+Count = 28
+Adata = 636114e5e5f83cec94e1df21d6babb9f6a14a532fcbfc3bcf649fbd79ac1abbb
+Payload = cb6d
+CT = 6b826db959a21e9e4ebf25ca4f98501b560d
+
+Count = 29
+Adata = 04e84f9156998c2eca9e96079a6001f2947dc49a081b3d75e47d75f71ed4a606
+Payload = 5bd2
+CT = fb3d2006ff22ff231a6646ae561923818a21
+
+[Plen = 3]
+
+Key = 3e4fa1c6f8b00f1296956735ee86e310
+Nonce = c6a170936568651020edfe15df
+
+Count = 30
+Adata = 00d57896da2435a4271afb9c98f61a650e63a4955357c47d073c5165dd4ea318
+Payload = 3a6734
+CT = 384be657bfc5f385b179be7333eb3f57df546b
+
+Count = 31
+Adata = 50f6e6dd57bd3a24f6bfdc8b1c7b5a36ebdd07fd6d194e6e82da47151d9c88fb
+Payload = 4ffad3
+CT = 4dd601b8ca97bda492546d82dccdebef441f8b
+
+Count = 32
+Adata = 70e132023acae1f88c7a237b68f5bdce56bcfc92be9f403d95d3bcc93b4477a9
+Payload = 8a594b
+CT = 887599fa0f3e397d9a580aa39c7028e1a508c9
+
+Count = 33
+Adata = 08d2b011f36e05dc728c1a8bda3d92c779a3d2f27c4b041810bd6222c852b14d
+Payload = 1f89df
+CT = 1da50d593460d335e2f7a6d40b8fe305b0f690
+
+Count = 34
+Adata = b207eb870aeeab27c6201ef04650bdc7ea30028a243420f7d198f1c9c9a43023
+Payload = 72e9c1
+CT = 70c513a2d49e1a113767ea4219107819d88b65
+
+Count = 35
+Adata = 74294088721fc9e7aabd5f1c66b5369b1e2d2cdb3e73abaa28ecd1c37d4ecea2
+Payload = 016083
+CT = 034c51dab1c819778be8453db163c882063af8
+
+Count = 36
+Adata = abbd347999a1c26368cdb17ab08bf57a8e942d1248296e952f5f42f2cabbf0e6
+Payload = 25f665
+CT = 27dab7537eb435df8d0e48c3f7e0bd1877c866
+
+Count = 37
+Adata = 231b33dc406c9210f59a5df1cfd595c803474db34b9b1848f0bcbe7b28df33c2
+Payload = 158606
+CT = 17aad4da549fc63d55b5910bbbf64435b95220
+
+Count = 38
+Adata = 69b851e63a78baef90637978e3dfe8c47be4b21e85bb89bf67051cf251004376
+Payload = b07452
+CT = b25880d5ee29fb2af47f8040fad585921057f5
+
+Count = 39
+Adata = 9b1f786c887d310b8efd3e8192fe504f603024c94aaa4ec9123736a40bf1605d
+Payload = 65187c
+CT = 6734aebc3ee43e10205f83143e0d3794a6734c
+
+[Plen = 4]
+
+Key = 7ccbb8557f6e08f436d0957d4bbe7fdf
+Nonce = bb8e2ef2ed9484f9021cda7073
+
+Count = 40
+Adata = fba1d18a74a3bb38671ab2842ffaa434cd572a0b45320e4145930b3008d8d350
+Payload = 4cabeb02
+CT = 32501f4235c4dd96e83d5ab4c3c31c523453c317
+
+Count = 41
+Adata = 78b3faecb2bdf6ed14ac2b86ded07aa791b60f5d54f9e24a965a8453f5131898
+Payload = 5ff73653
+CT = 210cc2137907d6a03e66403a7d9330d30d934a8d
+
+Count = 42
+Adata = db1239528eb464dd063e2a97ee83a87d6002ebb4fbafa77036f72c14f3fe959b
+Payload = 062fa9ca
+CT = 78d45d8a44f4bc78fbb969935076134437df82b4
+
+Count = 43
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cad710b4
+CT = b42ce4f459692911fea2e0034d06c3b2e89af3d1
+
+Count = 44
+Adata = 7381471a62b1fa6f5061c4c37e9721f07099d007ffaf8639aa2ae3f82da5a559
+Payload = 7ac716b4
+CT = 043ce2f468484e22381923bfcaed16e0cb85b0f8
+
+Count = 45
+Adata = 19bea6d92d5892216e8e4a30dda802387800bb046a6717817fc46c7edafe17b0
+Payload = 362da02c
+CT = 48d6546cd081de39c247df309c4b56c31c03690d
+
+Count = 46
+Adata = 8503c8eb9cebc6110f259e35e03a0740267768130ce6f61b1c7d1d25be942274
+Payload = de52b209
+CT = a0a94649c6c6bd7b3a9d7c4dfa2738847ea3cb33
+
+Count = 47
+Adata = d2445db6efecaa3f426b06de8d496ceed54a1d0171384cc762e21b31e265c6d5
+Payload = 8fe8b383
+CT = f11347c32ca874d18d0b790856837555f4d4699a
+
+Count = 48
+Adata = 8cda7d1e135cf5fde1ec9473c4b42c1bbb445c27fd87b5f73df61ceb2d0b6f75
+Payload = d8d6b2c9
+CT = a62d4689932c2f8d78e322aaffc90846025190f1
+
+Count = 49
+Adata = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5a4c25393ecbf2025
+Payload = 6a029e53
+CT = 14f96a13c346a4084918081b4bbe53b50d896788
+
+[Plen = 5]
+
+Key = 3725c7905bfaca415908c617b78f8dee
+Nonce = c98ec4473e051a4d4ac56fd082
+
+Count = 50
+Adata = 11bc87f1c2d2076ba47c5cb530dd6c2a224f7a0f7f554e23d7d29077c7787680
+Payload = f5499a7082
+CT = e378b776242066751af249d521c6eaebdff40b2642
+
+Count = 51
+Adata = d54219ef4fb851bebd1c546011ae3922b8337e19c28d4d58428efd66f80edcf0
+Payload = 513c46fcce
+CT = 470d6bfa68e7258df363e0e9af67a543c86db3c994
+
+Count = 52
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = 9d62e557c3
+CT = 8b53c8516572b7573e5b27a1d0e15cdb7b06c8857f
+
+Count = 53
+Adata = 77d9c306aa257379053cf1f2043c388a301dac2a9e2bb89eb8bab6eb3f150fe3
+Payload = 7a05db235f
+CT = 6c34f625f9de691a412ad54bbdb6ceac45ed45902b
+
+Count = 54
+Adata = 081568ae0b948aa647b9d4dda5d42641ad5de72aa9874d8d0717d872007720a8
+Payload = 30a22ca0fc
+CT = 269301a65a8a1bb8ba3d6763dcb1bdd3400e3459f7
+
+Count = 55
+Adata = 695ba4dea0f84baf190ec25a25fc00cb9898902d7a17e6f5ff2df323b974f7c4
+Payload = 35e25aa51f
+CT = 23d377a3b9403897d496cabcd5bd9de3282199a8ed
+
+Count = 56
+Adata = 1f3ba0336a634efdd11f8168c0fe25039f9403bfa70b3898f4dbe577dbd52957
+Payload = 8bde704c74
+CT = 9def5d4ad270a81f7cb0ab7ab2b495f51d66abeee5
+
+Count = 57
+Adata = 097b9ebff3ff93a143678d59721fdf359e95cbc82585ae47727a773317925d38
+Payload = 428542ecfb
+CT = 54b46fea5dce68e9b01a4462a2221bd2f3cadf64c0
+
+Count = 58
+Adata = 76d0341dd44c39e43a23dbcf4cb602f15d5fb9fee20c3d0d262d539c3fd1dfd5
+Payload = bd6866ded0
+CT = ab594bd876f2545964ef3978cad3387d61104bab84
+
+Count = 59
+Adata = 7e7c40ad64b511005b4546f9ec61ca24829390fbc4bd8507225bc348ae0807d7
+Payload = 5822755a3e
+CT = 4e13585c98002c41938a935d51905b2a708a2c5194
+
+[Plen = 6]
+
+Key = 80bead98a05d1bb173cd4fca463b8fa3
+Nonce = 8a14a6d255aa4032ebff37a3d7
+
+Count = 60
+Adata = bb4e706e73d21df66f64173859d47e247527cd9832e20dccff8548ed5f554108
+Payload = e479990bf082
+CT = 89c9246238878427f36b1f6c633e4542f32b50ca8edb
+
+Count = 61
+Adata = 9db2182c8a4f5471082bfa1a8496602cbcdef2790f7e8f71f791303bd48dcb05
+Payload = 017a7fd1aecb
+CT = 6ccac2b866ced76fe54da69af5edf8309c7f013bb07e
+
+Count = 62
+Adata = bf483f59fb73681f27b68168c998c90ea8ceea997654c6fab2bd737dcdc884f9
+Payload = 512fc5e4973a
+CT = 3c9f788d5f3f662f53d17f7cb6673415bb2324ca0666
+
+Count = 63
+Adata = b91e641d8210e1ef705fec2beb9f58a391c7d1a38935cd1d13f2c00363388ff5
+Payload = 06212e989616
+CT = 6b9193f15e1340c86156b1065b64af1e4d6c89b32603
+
+Count = 64
+Adata = 5cebf908e232d797fcce8453c4c3000868d4172622a4ee0d6a1bdd876a0b7c96
+Payload = c45629069ebc
+CT = a9e6946f56b9c07ef5349903b928e39e99e2e32625de
+
+Count = 65
+Adata = ab92cbc97f3aa6f9ea4dae5d8c3d9e91231f43ffff548da7b668e61c183ac2cf
+Payload = b949ced37725
+CT = d4f973babf205e40654ea16e83cc6faeaad668c416f3
+
+Count = 66
+Adata = 2c3d2f9c7e89c2b9e07317c4db6e9f00f5faadfad531c5bea79d164ac24d4543
+Payload = 517ff7b383b7
+CT = 3ccf4ada4bb23102a502dbba0c280e1d5fc627fe3a9e
+
+Count = 67
+Adata = d798e77ab0f3697768f23014fd31b9e8762ae65b6aa8a4bbc17ecb8cbe78461f
+Payload = b40d863ca4ff
+CT = d9bd3b556cfa6745fd4c954396e696697731e1f9a262
+
+Count = 68
+Adata = 45b44e3dec57e24d960fd1767797ffdbbab81e38bab37e6974df262c3d932327
+Payload = 56e00289a003
+CT = 3b50bfe06806bdf2b2dd47077c98234eae5d47c3b594
+
+Count = 69
+Adata = 645d27970ccce096d082fccfc1183955bad2611af0dd7c58c9d54430f28bd992
+Payload = aa22bb1de579
+CT = c79206742d7cea66649ad7e204a344d3234125aa324b
+
+[Plen = 7]
+
+Key = dc8ec91184ba18eae31ac2d3b252673f
+Nonce = 0da4c988f521f5648259f2bec2
+
+Count = 70
+Adata = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024b3651eb227e73bb5
+Payload = 2a5775986551c8
+CT = 4f259f2a718faea852a7c4358dfa9f5467357638acac90
+
+Count = 71
+Adata = ff0ab5021ef466e2e898b0993d691145168be558682c74914c172f2b5e863754
+Payload = 8db3c1ca0580f9
+CT = e8c12b78115e9f8767c76e707d48a2144e090812e0192d
+
+Count = 72
+Adata = 2ee03cc28f79773af139c4ea55ec4daa48bb2885b8adcd5f066eceda5c4ec27b
+Payload = 3c69e2e83236b6
+CT = 591b085a26e8d05486df740083c959fb62ef7e2e221602
+
+Count = 73
+Adata = f041504d4c1b3d5be358bd6d350af42921205d29ab22b44ffe221358adef5bb4
+Payload = 777828ab5ccb68
+CT = 120ac21948150ebdc4d2b86b2528f75db4a7f5423f4395
+
+Count = 74
+Adata = 81ea116832d69542ac8d3d22c16c82eecf2ccac39264dd933c4f9c13c8d0f1d4
+Payload = af556fef3584e3
+CT = ca27855d215a85a7b06d1b710baa15daef19069ecf46f0
+
+Count = 75
+Adata = 8a0a120ed290a62456f002da1c250a0ddb1ebd57185a733d8fb562aad482679d
+Payload = 98f26635351f14
+CT = fd808c8721c1723811129add52e1406d50cbff4aa82802
+
+Count = 76
+Adata = 12b5a76faedf6f855e328c2cb87be8aea78c5e926b32d828e167b46205c86de5
+Payload = bd22c1ec05dc26
+CT = d8502b5e1102401563d3da8a6cabb7515f642e42fb4b2e
+
+Count = 77
+Adata = 8dc32f35ef4bcbfd040ad25dc36d0bd2486f93d0cabb7704cd1582dc99f65449
+Payload = 2a87c0d64806fe
+CT = 4ff52a645cd89817609a21f703253e5e56beef4ac71759
+
+Count = 78
+Adata = 83ced632359a11eb0c4c99baad84df5cac15bc5453b6593d9ffb4c5e8c84037f
+Payload = f05f39eb0a3d64
+CT = 952dd3591ee302236c72f98da859b54be7c598d85c37eb
+
+Count = 79
+Adata = 771a818a24e7da7b98f4b4291ef34bec7e1656b0c6c6e9474a989a04ea7de385
+Payload = 59dad755af92c2
+CT = 3ca83de7bb4ca464c8cd38cbcc46e7f09bf3e1c6590c71
+
+[Plen = 8]
+
+Key = 19f97ef5318b8005fc7133fa31dd1236
+Nonce = 01ce9814c6329dbee1d02b1321
+
+Count = 80
+Adata = 85853f120981f33cf1d50fde6b8bc865fe988a9f12579acdb336f9f992b08b89
+Payload = 6d972a673fbe1ca1
+CT = 2f12a7e7acecae5d2563309efc19368cdee8266538ca89d3
+
+Count = 81
+Adata = a4ec5aee89e2cce2115b6c1f42570bc5062887cad08192a682d0b4508fcd936a
+Payload = 68b1b6367a15fe49
+CT = 2a343bb6e9474cb528096a5fec5e5359c369833eac3b7efb
+
+Count = 82
+Adata = f5499a7082bf1e6e2923211271f5f7f6d7c7b26db7963071705a58ddc4dca0dd
+Payload = 707023615563a40e
+CT = 32f5aee1c63116f2754a65863efb60c98dbb536e2b5a69d8
+
+Count = 83
+Adata = 765f267befe6fcfaaa4b46eda32e7bfab87f12ceb07fa3b37be74965bb664a21
+Payload = b56454bc50df3e28
+CT = f7e1d93cc38d8cd40b6e9b7f3b3541ffee66a1f668f67d28
+
+Count = 84
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154c55e40
+Payload = 962f765da3565bde
+CT = d4aafbdd3004e9227018c9db8baf6be349d93d4eef7d7c9d
+
+Count = 85
+Adata = d0125e30c36232a8c07cee9abc53453b276849a7c04ade80ad586ed8cbcede51
+Payload = 4f18bcc8ee0bbb80
+CT = 0d9d31487d59097c501b28887f05fd66f050525943d101f8
+
+Count = 86
+Adata = 90dfd9e7bb7bf8fb70c22a879ffa760d14cda7b79ce4968f69b8a7f2b7a59642
+Payload = ca293c9e1780b401
+CT = 88acb11e84d206fdda53dde2e1aef96b3658a7635ee54188
+
+Count = 87
+Adata = 58f518710e6b282482a7f1950fa353b13bdda10c9aaea6d5f0d7ea0a965d31e8
+Payload = b9df9fb4a6b299b4
+CT = fb5a123435e02b48b62a5ec234f1efd1b52c8fad1cf09890
+
+Count = 88
+Adata = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb07545e6802de7e807
+Payload = fb2441d1594a488a
+CT = b9a1cc51ca18fa76bc051ede6f37cf67543a7252d7d9b203
+
+Count = 89
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f266
+CT = 07948ca59d94409a5be4be6bc6b18104fac167b6e3fc15f7
+
+[Plen = 9]
+
+Key = c17944bfaeeb808eed66ae7242ab545f
+Nonce = 910b3db64df3728ca98219e01b
+
+Count = 90
+Adata = edf64f98b3ab593cbcf68ab37a8c9472e49cb849d4a744deae925a5a43faf262
+Payload = 7caae2640e734539d3
+CT = 0dae8b3ccf0b439f6ff8ee4a233dfb7753f6bfe321b3e26959
+
+Count = 91
+Adata = 29ac8fd6a20a5df4ec79660c44d373da42de7d7c5fc35982b6c29b480723b484
+Payload = e574b3a37af3bf2251
+CT = 9470dafbbb8bb984ed63b1477d9506a51ae23abbac179d8b02
+
+Count = 92
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b227
+CT = 5f3899f74deec1149bdb0986198bce2e486581c041029a81d9
+
+Count = 93
+Adata = cc8e789462879e348d20be4e1161d7b7fc6f8371d8f8cb2d25d13f0e07de47b0
+Payload = 16f22817c5b79f9fa6
+CT = 67f6414f04cf99391a0cbb2df2079a6eb964c3469f4f326122
+
+Count = 94
+Adata = c63061f2800228269015693336f78bb535ae8b88869e4ccf4ead2f3b0ea4e48a
+Payload = 64fe8076d4e8538e18
+CT = 15fae92e15905528a4a40ca7622acf7266b7c24cf0c3202e4c
+
+Count = 95
+Adata = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b787660e7b1a581af11
+Payload = 4814aaac48bdf43c92
+CT = 3910c3f489c5f29a2e7de20e98586cd5d684bf015a7abbe82c
+
+Count = 96
+Adata = 8f4947f8588ed866ed7477d7f1a28046430c6470806a50e3c9e80958c61f1b42
+Payload = 392a692b57a8a97f60
+CT = 482e007396d0afd9dc8d503f5d87818f7c0e173b857cef4288
+
+Count = 97
+Adata = 9d44f6df58c2b43db67e3daa95b176c81daff32e996d670e86405e15eae72e93
+Payload = cba1e00e345b0cb7eb
+CT = baa58956f5230a1157c85e2283d9e80700268a6459d1451d00
+
+Count = 98
+Adata = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f93006c1ca2ff66f87
+Payload = 22f5b6752582919dc1
+CT = 53f1df2de4fa973b7d1056aea3d3e4f7a5219170aaa52465e1
+
+Count = 99
+Adata = d6411fd5b25433f67ca75e4560ceb809d3721266beec358dde126b2f6a514137
+Payload = 6e1b55d6f5288c5451
+CT = 1f1f3c8e34508af2edfbfcf8200a8a3f8d995f50284a7280c8
+
+[Plen = 10]
+
+Key = 0fb9df6f638847f5de371f003dd938f4
+Nonce = c9ddf61c052f3502ad6b229819
+
+Count = 100
+Adata = 4f9938d5bc3dcbe47f6b256d5e99723d0891e50c6175aba41b011e4686113c49
+Payload = e10cc36bc1c5d3c646ab
+CT = 7f797367de50be6dc04e4cf0d8c24189affd35060cb7ca3dd136
+
+Count = 101
+Adata = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304a643141855adac10
+Payload = 15841284c959febe63f9
+CT = 8bf1a288d6cc9315e51c4148ef85caab151488c1a6b3df540d21
+
+Count = 102
+Adata = 147d77d509f642189594df17574a0ce62b52a838feb62310e11533995ba4c851
+Payload = a8b4e5829069c335d1d8
+CT = 36c1558e8ffcae9e573ddaaa1e7c22b3efa8362abb3d31ee8884
+
+Count = 103
+Adata = 0bb09658e23fe8a08c01a6994ef36cb8dcc9a806297a09c67efe3558ca56bb5d
+Payload = 1bb2da0f1ae7e044deb0
+CT = 85c76a0305728def5855317b141383ad38dd78569d5f846f2520
+
+Count = 104
+Adata = 34eb2e6149bad764837f6f25ddd96865e5b05d5cbf233c4f6cc2aa654dfea3b7
+Payload = 63af538196add9b3fad2
+CT = fddae38d8938b4187c374e6432971aecf6bf7cf5244d21f7f173
+
+Count = 105
+Adata = b69f26fda6d1cd92897e03758cae020c4e1beb019ce5ad987f872940780a9468
+Payload = 6ef2df5a1688ae795537
+CT = f0876f56091dc3d2d3d2e4d0ffc0f0add38a80c7ffe6b4701e54
+
+Count = 106
+Adata = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117d25f6d4ef9c2fcbc
+Payload = 3f46c83021069ac488a1
+CT = a133783c3e93f76f0e4447fdd0b2f29f39094ba5a7375e278349
+
+Count = 107
+Adata = f9b91f7298b4e43843fc739a2f41c57c3f2cf36378fe4c34b574a43f9cedee7b
+Payload = 86c10a6dfdd6a06ef638
+CT = 18b4ba61e243cdc570dd57500f913ee3f46801e1bba9d4db7ecf
+
+Count = 108
+Adata = 9d35876d9449a1642b5062dfbfc7a26a7ac080b7198f4aeff2c79e463565cfd2
+Payload = 196c80d02b663bdd89fd
+CT = 871930dc34f356760f1856a6b87519b4807a2114ced587f72189
+
+Count = 109
+Adata = f2d5e927eb507f889efc6f21d783851f638f978c74960cc347f89f2703476114
+Payload = bd27ae3ade0781a33d5f
+CT = 23521e36c192ec08bbba2101012808adefe9b8166e04685bd537
+
+[Plen = 11]
+
+Key = 006ff7d3153caf906ec7929f5aef9276
+Nonce = 57db1541a185bd9cdc34d62025
+
+Count = 110
+Adata = 7d9681cac38e778fba11f4464f69ed9ebfea31b7ffcaf2925b3381c65d975974
+Payload = 31be1b241cae79c54c2446
+CT = 9dd8a4244fbdb30b624578a625c43233476bbb959acd9edebe2883
+
+Count = 111
+Adata = 1b0012c468009bd2851653013782c7b71ef43c393afd4dc0aec4d6d0c3fa11c5
+Payload = 8802831e22092b30110cf7
+CT = 24643c1e711ae1fe3f6dc9d477ca066ec2befa854a1faef018ea8b
+
+Count = 112
+Adata = 48b216375c00ca7e9c4048834b37944d2543e24fa091fb3c7290e11c53a6b6a0
+Payload = 3b3f782d637319d7fd161d
+CT = 9759c72d3060d319d37723eb6be9a78dfbd9e16181679b782969ad
+
+Count = 113
+Adata = f3e06a45fcf1f6abeb00727bf2c9bcea00ce621d38f7b7eba17c27e51f04c793
+Payload = e98f5e5a20d02c80372d6d
+CT = 45e9e15a73c3e64e194c533d9574d95b821a5170e9b61d8e6b2ff3
+
+Count = 114
+Adata = b36e27729f9a139d8ec4f61215b7bf1149cbb4d93a5c14bebd7cfb7c6fe585cb
+Payload = ceeed4fde3406ec40f7ac6
+CT = 62886bfdb053a40a211bf8aa193d257907be1330abaa56bc4f431a
+
+Count = 115
+Adata = 8886ed7fa414d74aef704a9751b197cbab02c41c6aedcaf65cda019dc2d2d815
+Payload = b38f03449883773135c0cd
+CT = 1fe9bc44cb90bdff1ba1f31d92029a6428748664b5c815f15ca1b7
+
+Count = 116
+Adata = 816d81af167d2294497d9b06a39fdf75e37cbacf4d10c3a444068c891b361bba
+Payload = 8efb141db7b77c521003cf
+CT = 229dab1de4a4b69c3e62f1386e4ad7c72ce0081a85d4cfd34254c7
+
+Count = 117
+Adata = f427c47e10c45bb3c7e75e9e604503b3560427691470358efdef48ddaf3794d2
+Payload = 6dc38e37d1379732df4dd5
+CT = c1a5313782245dfcf12ceb98eeb05bc376a1042735569d5b63f8fa
+
+Count = 118
+Adata = f3df712b5e8dd8e4aa8b7c5f41e93bd11b0df66a3456a01f3d0094ad91482cdb
+Payload = e0e358aff203369dd5960c
+CT = 4c85e7afa110fc53fbf732065b03ebeb68a9153cb4ed152ce0d64c
+
+Count = 119
+Adata = 264f2c7b095a296eb8ff6b5151ab3d9497ea8dc0002a9e5b09c2fd0ccd32b6ff
+Payload = 57b940550a383b40f3c308
+CT = fbdfff55592bf18edda236fcd16c8360a408e2787f930ed275bf3f
+
+[Plen = 12]
+
+Key = 026331e98aba9e8c23a9e8a91d0b0c97
+Nonce = bccfe69bba168b81cbdf7d018a
+
+Count = 120
+Adata = 26e011143a686a7224ddb8c5b1e5d31713fa22c386785e2c34f498ae56d07ed5
+Payload = a82200ef3a08c390dec5cbf9
+CT = adf4fc6f9be113066c09248fcb56a9c1a1c3bb16fbb9fbaedacdb12b
+
+Count = 121
+Adata = 97a720ae4720546e31263a1a538ce1d35c198c23bd4362e0023a67536328ab9a
+Payload = 7fc58d1bb450b396b9161f53
+CT = 7a13719b15b963000bdaf025002120b619a391fbd23402e5edd4949e
+
+Count = 122
+Adata = aff6c8cefda055c67262e9c68825d1ad2a7488e5b09640a111fabf6254d96cc0
+Payload = e9ea182d7f895f312b9738db
+CT = ec3ce4adde608fa7995bd7ad48b6e9a8de0099a28cebbf5c2bad42ff
+
+Count = 123
+Adata = 35a3963b43f47855ef3df12af5de3626e0c5c8d9cd2a534c737cd695609b05a9
+Payload = cfbc8bcbb5e5bb744bb1f340
+CT = ca6a774b140c6be2f97d1c36df80fd62e751757bb0a32a987980afe6
+
+Count = 124
+Adata = 46a2e6bd3fd5336abf02eace3cd1e1f6dde505ab976a9fa596edd6fbde7175de
+Payload = a334f8f41897cbcaeb5cffdf
+CT = a6e20474b97e1b5c599010a93b211350c70adf9bab5c01081bdc6a99
+
+Count = 125
+Adata = d110651c00ac5540f9d1ed9eb175e06b97163fc36d43f048565e5d0c30a069b1
+Payload = 3f781267290e8e73c6355e75
+CT = 3aaeeee788e75ee574f9b103d7f65690d9a2fb6759d658c9bdfdfc37
+
+Count = 126
+Adata = 978644dc4e36f1d98a2a63e19bbf8af11785d09fce58a95c00cc6bf6cecf6161
+Payload = 3dc39dbb91efe8b16396d488
+CT = 3815613b30063827d15a3bfe0d5df472f49e7f713cd1373293810906
+
+Count = 127
+Adata = 5ae7528c5e965880b1533cbd78c1e81a8187379327a2fc3f76ff45829049e183
+Payload = 6caa8c0764512baa39dabac0
+CT = 697c7087c5b8fb3c8b1655b64bfca9ef00b0f2bbb03c1a3f7a0862e7
+
+Count = 128
+Adata = afe754828be6e3731d3eee54b021b4fa182247bd958e9074fb0094a11030f5e8
+Payload = b19bc92e2305883580dd7742
+CT = b44d35ae82ec58a332119834a03be1d1d262b03c0ab425d533fe4ec1
+
+Count = 129
+Adata = 0650859c635654ca4d815963c0a99f9d2f47456ad37f739c425e924d4360bd7e
+Payload = dab87e79544df1cc98096b91
+CT = df6e82f9f5a4215a2ac584e7da61ca8461925996880e2874393232d6
+
+[Plen = 13]
+
+Key = d32088d50df9aba14d9022c870a0cb85
+Nonce = e16c69861efc206e85aab1255e
+
+Count = 130
+Adata = 0eff7d7bcceb873c3203a8df74f4e91b04bd607ec11202f96cfeb99f5bcdb7aa
+Payload = 4b10788c1a03bca656f04f1f98
+CT = 89f15b1cb665a8851da03b874ca6f73242f2f227350c0277e4e72cdaa6
+
+Count = 131
+Adata = a533b3279db530eaed425842b0d3528f5c5e4c16acfa0f49de43d6491f0060a9
+Payload = de6ea86d3641d916c4394fdd31
+CT = 1c8f8bfd9a27cd358f693b45e594271cc06f81d510075728cfeb89222c
+
+Count = 132
+Adata = 8e6c1cde142e18635c1b4f0cb54d3cf817f22ad7c25bf6a022501682f6a7da1c
+Payload = 6f3b32adc8c0314872947f3d31
+CT = adda113d64a6256b39c40ba5e5ab1aefed75400a41447b2bd8f0605542
+
+Count = 133
+Adata = 248a4389da2d51b87907dc11c46253515503ba80de5d06c9b505cb89906614a6
+Payload = 0cc992a8c736b44fedb4ad498f
+CT = ce28b1386b50a06ca6e4d9d15b46b3a6463876f1a43a287748f339e913
+
+Count = 134
+Adata = 2e2c8244a2cbf53816b59e413207fb75f9c5ce1af06e67d182d3250ea3283bcb
+Payload = 98104fd3f3413ad1f57ef4912c
+CT = 5af16c435f272ef2be2e8009f8f625786bdc58af24b17c1ba34fa87baa
+
+Count = 135
+Adata = 4ada86d88d5f49dfcde13fc30ba9a1af58d5254b47fb1885a20fad915c87952e
+Payload = 3b4fec79d52d8b2a533917b75f
+CT = f9aecfe9794b9f091869632f8bd4a918290cf97208232c76908514b07a
+
+Count = 136
+Adata = 9e3b23232e5a9e69747f8bcb148cd6d282fd9b7ecd6d97e8bb5cdc261b2fc86f
+Payload = f10c19c76ae7ed55e1651155df
+CT = 33ed3a57c681f976aa3565cd0b01d6306bb91c315bb4a23fe23d496d09
+
+Count = 137
+Adata = ccea2c815ea4efadc3007f511d633e98f9fa38b0e0fb572b282ed6a610adf7a9
+Payload = fa34af376868d9a49aa200f59a
+CT = 38d58ca7c40ecd87d1f2746d4e620d9d3004587c5d510e2a857fc857ea
+
+Count = 138
+Adata = f7277fb296e2c0d2c9ceb7013ea8b59fe37e26b3b42a0b8cd01aaaa8d35283d4
+Payload = abe2fd996bb6804ed3286c057d
+CT = 6903de09c7d0946d9878189da982d2438a5138977bde5f514e2335c28c
+
+Count = 139
+Adata = 14dd1810df3eeee78ed3836c77edf510d91ea28f119bf57111e580d70da94b74
+Payload = 395ea6979b77dabd2042aee4ff
+CT = fbbf85073711ce9e6b12da7c2b78100a05448fa6e74bd3ed16c3bd364e
+
+[Plen = 14]
+
+Key = 7301c907b9d2aaac355c5416ff25c59b
+Nonce = 7304b65b6dab466273862c88b9
+
+Count = 140
+Adata = 2c5d114eff62c527cc2e03c33c595a80fe609bfc0fe13ce3380efe05d85cceac
+Payload = 484300aa3a506afcd313b49ead8d
+CT = 928ca58b0d373dc50c52afac787ce8eeb5d5b493661259a9d91ea31a5f7e
+
+Count = 141
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d778da52c4
+Payload = 8b318f75ed79a7978adc17c4d2d4
+CT = 51fe2a54da1ef0ae559d0cf60725552193439abfedda67d765d030cef30b
+
+Count = 142
+Adata = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7ea337e548cb706780
+Payload = 0256b0d154c768c85070da6ea8c7
+CT = d89915f063a03ff18f31c15c7d3615013c2bc9338868fad0d2fac11df019
+
+Count = 143
+Adata = 08afe10bbfbd65b948a6561bbeaf3ab46a8e3d0a861f1cfc46584156197f30a3
+Payload = 89ed296a3ac03fbfb71422b92117
+CT = 53228c4b0da768866855398bf4e66c3c4cb8c50891d6523245e4c619aa99
+
+Count = 144
+Adata = 7d653792bb8683e07c7d2c800db6f7f08343c85af2377115df4fc86ff7d8fcaa
+Payload = 414b6acb1db479028f5cc8800f2b
+CT = 9b84cfea2ad32e3b501dd3b2dada792d2cb93e45811a4c897ae9d907c9cf
+
+Count = 145
+Adata = 4d73c1484f9429eb15742f29ab05cbab6552abf40e127b93427d649d195ed25a
+Payload = 163f67b3766c3c650ce26c5bd8b5
+CT = ccf0c292410b6b5cd3a377690d441983a87812eaa7b66c5a0e54a01cb882
+
+Count = 146
+Adata = 2fba7a881f019a8745691343d79ef3656e25bb37b93fb5ab7311889f92010a5f
+Payload = 9c5b4aa703c27d16d82013853e16
+CT = 4694ef8634a52a2f076108b7ebe7b0afabd23b33765a63753cad66b0e6db
+
+Count = 147
+Adata = a640343fd4a866aec07b667d25176e11a32fb4d8bfc08fde2c46dc9b492fa010
+Payload = 99eb86b3202c7ce68a2339065f47
+CT = 43242392174b2bdf556222348ab639b8d0f97540373a7b9061aa3b2f7044
+
+Count = 148
+Adata = 9efd58d3ef5f74f663b2b5ca5e96c5a2fe85ca5eac1495d7f1751c7d8b412b3e
+Payload = 3f5c1d038161e65c9ed955c961af
+CT = e593b822b606b16541984efbb45e312c803e29f7be7c5eb236401037a320
+
+Count = 149
+Adata = a7d7ba684c0903323f7efc83dc32815195df325394162fb5a18f201047be7999
+Payload = be8dea2b4e602a787ecd28f2f7f0
+CT = 64424f0a79077d41a18c33c02201fd929c717d75388387dc25bfcf90b707
+
+[Plen = 15]
+
+Key = 38be46d271bf868c198052391f8a2147
+Nonce = 6758f67db9bfea5f0e0972e08b
+
+Count = 150
+Adata = c6de3be97f11d0e2ab85c9353b783f25b37366a78a2012cecf5b7a87138b3c86
+Payload = 61bd1385be92097e866550a55278f0
+CT = 7c9fa8d99b38f825315ece6a2613f55e902f296dcce870263ae50cda4fadae
+
+Count = 151
+Adata = 7c8cf9c650511f33af82e807e60336ec086bd2d9400a5f35652b8c3fcf968ead
+Payload = 7e5e51301fa44a21f2734731ee3710
+CT = 637cea6c3a0ebb7a4548d9fe9a5c15cae8a9e4b606f5fbeac2b829b42a150a
+
+Count = 152
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75
+CT = 81c8805a3bf6b176ff72e06be0e670f5419c6085e5434f056162cf80f6729d
+
+Count = 153
+Adata = 238d3c9d9de32f2040b1dd0dd040b921e456c3653263f4020cffdc552b948a46
+Payload = 20660408d6890aed84aa65dfe23032
+CT = 3d44bf54f323fbb63391fb10965b377fedcc743389a9d48e6b871dc0dd63b2
+
+Count = 154
+Adata = 3b5d61ca21953fdd22280747dd4ae908a511750127875da84dfe7d0063a318c9
+Payload = 9ab83c81f2d2c896c6596660c3974d
+CT = 879a87ddd77839cd7162f8afb7fc488137e0a856d3d911af9f420b68d8110d
+
+Count = 155
+Adata = 78c1751e86144a78285a30dc04f51742bd47e3d36b607bab48d91cddabfff4b7
+Payload = c1ec469aa9c73b677af225a9f5f6f8
+CT = dccefdc68c6dca3ccdc9bb66819dfd5644448fa8445b6cd185bdf9b3718033
+
+Count = 156
+Adata = add33e9a1d7e91e2c160c1123537e3f7e3535881cb4aac1a80ecbe367379212c
+Payload = 9df1d6b6debffdd316aeb27143508e
+CT = 80d36deafb150c88a1952cbe373b8bbd38e4dc44f768cef0c51344e3a7f7b8
+
+Count = 157
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c12
+CT = 04cc4b4b35a7397491d696dab137172e7f2ec918099898b843a34c385f2a57
+
+Count = 158
+Adata = b40c8d22069b8a65cddb51c1ea3571160cacb19fd371552436b19c7122b28d08
+Payload = 2af5db43f2a5fe8b494b40661510bb
+CT = 37d7601fd70f0fd0fe70dea9617bbe94c2709685b0827cc42f3a25b579db28
+
+Count = 159
+Adata = 9de5559ea8ccc70f4375a436ce0b72551a75960ad5ed6a1949ee8f6c47548558
+Payload = 5de41a8ca8ed8011304fa9e9f36498
+CT = 40c6a1d08d47714a87743726870f9d63bf4b40ce7e672587816fdcda16efbe
+
+[Plen = 16]
+
+Key = 70010ed90e6186ecad41f0d3c7c42ff8
+Nonce = a5f4f4986e98472965f5abcc4b
+
+Count = 160
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f2
+CT = 8e4425ae573974f0f0693a188b525812eef08e3fb15f4227e0d989a4d587a8cf
+
+Count = 161
+Adata = b6fecd1edeb55a9a4148b1aefb716a1e162779a5ab2a682e4adce4479c527bd2
+Payload = 0e6118d0409751d36cb642504678535e
+CT = 3e171226f809dde516bc264351e47cbedf7f186e8d3d7c21c549c41ebcc7f505
+
+Count = 162
+Adata = 5c3933c30bf9d4841eff4000aaa1cb4d39cdf8ef1240e2aabbf9da95bdee5270
+Payload = 5c8a5fb36f860d00c21ae9e3f24097c4
+CT = 6cfc5545d7188136b8108df0e5dcb824810a68be1814f53c09aca4066527fef8
+
+Count = 163
+Adata = 7ca7ef30d3ac08aa51a9e5d3d84e8b6bb7fdde921e72b98ad6a93ebf2efc6b04
+Payload = ebd1cb4b35257790c9806be476bd25a3
+CT = dba7c1bd8dbbfba6b38a0ff761210a43cc30245a6e64625c4f6531d7497fb144
+
+Count = 164
+Adata = 90f1416768fca7dd48d01230dabf95f2f1a0c044bf2d755448aaf72316c8448c
+Payload = 842b7e5f22d921b2b8ab3131684b7eff
+CT = b45d74a99a47ad84c2a155227fd7511f10d85725dacc274034669acf7f34fed7
+
+Count = 165
+Adata = adc5c36849283d57acb2bcbc0e12465cb7c1830cb4e314b9ce6e25acbd8d460c
+Payload = f0c2cc5a1b4c4cbe839338fa0d7a3435
+CT = c0b4c6aca3d2c088f9995ce91ae61bd5f731b465eb59c4989e42020d86102a59
+
+Count = 166
+Adata = 80a7a483d1dbcdf00ed02a700e93d8b87fa6ac5c7368d1e81bd1b32cd1621cd7
+Payload = 2c1a5f906f2ae0373cc25e3519df2ba4
+CT = 1c6c5566d7b46c0146c83a260e43044484bcd2775448447ed801b3b0ff071c19
+
+Count = 167
+Adata = 13c02992992d2708250184a579c43bc29a3a8cf1e02dade4496cbd8b1214f97d
+Payload = 1da5190517546f1ad852f64263e1f679
+CT = 2dd313f3afcae32ca2589251747dd99901d1919f1451ad16f115cde863f15303
+
+Count = 168
+Adata = f6f18dfe093e4c0c3fbfa8a5b1f4a703c08addc2ab959741611a594b93d08bf7
+Payload = 13ccb08a580efea53dfba6a59626bbe2
+CT = 23baba7ce090729347f1c2b681ba9402ccae4f6ec07bf73d6f086cf09e2e14ed
+
+Count = 169
+Adata = 63708e12dfa14f192ec5ee5856dc3cf2403817d9628c31899b4613f65e1e61c2
+Payload = e0b5fbc6c2269d445a60273bf844892b
+CT = d0c3f1307ab81172206a4328efd8a6cb2bad8bf67d32a855c3940ac908397a5f
+
+[Plen = 17]
+
+Key = 79eae5baddc5887bdf3031fd1d65085b
+Nonce = 9da59614535d1fad35f2ece00f
+
+Count = 170
+Adata = 46603500af9e4e7a2f9545411a58b21a6efd21f2b5f315d02d964c09270145b3
+Payload = 001343e6191f5f1738e7d19d4eec2b9592
+CT = 2162e27bfbf1d00f2404754a254665fd9270f0edb415993588b2535e2e0e4fd086
+
+Count = 171
+Adata = 278afebc604bb7d87bed3574a2c5053de17eb8ca7e18ddc7892f2c54b38104a8
+Payload = ba47d5bfb36f6150a100e36caa116405c4
+CT = 9b3674225181ee48bde347bbc1bb2a6dc4778e3c4a11f3f9dc42554d45796379ef
+
+Count = 172
+Adata = 3239b2ce4efe4f6a6255dc53347400a6446ed3280c65422386fab471ef09eed6
+Payload = 96eccb7f9b0e16c6883de0a381e4767f5a
+CT = b79d6ae279e099de94de4474ea4e38175aab5540cc01d867f641c9b196fa159291
+
+Count = 173
+Adata = e2a5488d5f7930ea4ce399f2a6c0810265f7c0dc52fe824d19a0fa0d9ffd55e6
+Payload = d68f5990da1a2fe39ed81af145ab834fa4
+CT = f7fef80d38f4a0fb823bbe262e01cd27a46366fbe302e142dcf6aa16337d98550f
+
+Count = 174
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cdd4d8b3d8f6e4742793b456cefc9e686d
+CT = eca5792e3a186b6c3b701081a556d0006df88c07797267bf5a49b3d0f601a225ce
+
+Count = 175
+Adata = f5d6989587e463969d97aadabea9538511f8d109cc2d3cecf09ba7cc346aaea0
+Payload = e7d7fc60ae852b68102e01b506f9dab986
+CT = c6a65dfd4c6ba4700ccda5626d5394d1865c9fbf69d81cef238ac513562d4a0dd5
+
+Count = 176
+Adata = e0b5fbc6c2269d445a60273bf844892b26fed03b82869edacd6dd7a63fd69e8d
+Payload = be9f51abfbe2da5a56db0f9a31b67c9f83
+CT = 9feef036190c55424a38ab4d5a1c32f783e2c748c8c9e3190de095de8eb0650203
+
+Count = 177
+Adata = e6bd0010c98e60b9af7cf905c58e0653bc425e2ccc809bd4f9cd7b1f95c18786
+Payload = 81b9c73029cea1936ef8755c80ba8d4093
+CT = a0c866adcb202e8b721bd18beb10c3289305cf563c5b4ba4ebd5bf107f2ad3555b
+
+Count = 178
+Adata = b1688cbc058816974694cd26c0f28ba9418e9912867fc8c5f4e7bd9c891a8d2e
+Payload = 618dc26853ee339689467ffbc2a77be69e
+CT = 40fc63f5b100bc8e95a5db2ca90d358e9e60dbbd8f46343c8442b03a472da4e23f
+
+Count = 179
+Adata = 469e004fee9878ed40621b41d04ec34af175f213d64d16e2f77d0bb2b6efe2e3
+Payload = 4f18bcc8ee0bbb80de30a9e08629323116
+CT = 6e691d550ce53498c2d30d37ed837c591643352e46995e8c1aee43dbdb26b46c30
+
+[Plen = 18]
+
+Key = c14eda0f958465246fe6ab541e5dfd75
+Nonce = 32b63ca7e269223f80a56baaaa
+
+Count = 180
+Adata = 733f8e7670de3446016916510dfe722ce671570121d91331a64feb3d03f210e6
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb
+CT = b2dc1e548b3d3f225a34082f4391980a0788b4cc36852fd64a423fb8e872252b248e
+
+Count = 181
+Adata = b6ec659856866959ef6fd4e71ba930f0e3e5fd49d7465fd65f6813ab4ca1a770
+Payload = b8b342c49c28bffc2a1c457db0b537ad46bb
+CT = 6b17343e86e28518c5abf8af8d3aef21e08895a66eb5b902bb23a1a8584249409fda
+
+Count = 182
+Adata = 89eb3636fff80230352a3582be5698e3401c9e0579d48f2680c6e5e24d99f74b
+Payload = 37d694ba94d0af8df662134f20d142903839
+CT = e472e2408e1a956919d5ae9d1d5e9a1c9e0a7fa792fb7246218f7d56d5fa4a5476bd
+
+Count = 183
+Adata = 03434f3709e19a1e37edfcaabc215116763b71ab1c5e053dbdb599f86959f25d
+Payload = 90e4c0550cb7b279ef61f9140b7d94b8003d
+CT = 4340b6af167d889d00d644c636f24c34a60ea83dc3f0012ae6da32a15fd1684835ef
+
+Count = 184
+Adata = 0e2ddb65fcc72094ac388d53a1055c7e902285c4c3c33c13bb6fbb4f1956414a
+Payload = 69b851e63a78baef90637978e3dfe8c47be4
+CT = ba1c271c20b2800b7fd4c4aade503048ddd7f09d38d3dba01995e36bd685c8ea3371
+
+Count = 185
+Adata = a42b2538ee2fb5f6a85d4d00524b01ad3331f61c404069243f35f28e2c2d0a82
+Payload = b7dbf8382115199dd2a2d87938c6ae6c4241
+CT = 647f8ec23bdf23793d1565ab054976e0e472c89becf8d2bb935cb17f44b950df3ef5
+
+Count = 186
+Adata = 09bc5c426dc1faa4d71f50908bd6f297ec8e754d4d20def005585b4bc1fa31da
+Payload = d53698d719c51bf9eae346269c6a1da07162
+CT = 0692ee2d030f211d0554fbf4a1e5c52cd75196e28badf0202097e80561451796194d
+
+Count = 187
+Adata = 2ac87e59c2c86532cf165af3e8ff4871d730f5e742cccca38bbcdffff4472c93
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb3
+CT = 1c7f059982909afe194f55f140306f0bb880710d4d7f66660891ac655d6eca4a3f3e
+
+Count = 188
+Adata = 05d2fbc3d0ec81f52f31cb0c4bf960c2076867f6d9f0174ed9176e20177b2693
+Payload = 56fdf10dc0c1dfd10965b83938e557459c61
+CT = 855987f7da0be535e6d205eb056a8fc93a52f90ab18925fea6964490f364a975a473
+
+Count = 189
+Adata = c2c3902cfe8622254b3787cc13e79c5a3c388c2357c29f1c1ab5539a10bfae5c
+Payload = e7c9812eda2ed7dcfc80fc5fe0d43e1e5982
+CT = 346df7d4c0e4ed381337418ddd5be692ffb168a00e5e7a39b371024927d3ac98fe43
+
+[Plen = 19]
+
+Key = c5e7147f56ba4530b8799ababeb82772
+Nonce = bdd38e173fb20b981659c597d6
+
+Count = 190
+Adata = 3a069a2bfda44abbb0a82a97e5e9047258c803da2c66190d77149e0f010b3af9
+Payload = 2f3bf0b566440912a1e47a0c07f1cfd39cb440
+CT = bd6265dcba9e14c59e515e395dc60bd053345fa6d7568c738e3a7fdf142d8f2d1562c0
+
+Count = 191
+Adata = 7709132415c94960025cc39c950ead208703a9d5a71e224fd022dc0a1817d0f4
+Payload = 7c880d787726c4ddeb2304b5d161b4a257298e
+CT = eed19811abfcd90ad49620808b5670a198a991f22337efa5cb7db7240e7518b67ffbb1
+
+Count = 192
+Adata = aad77595f87a27f2c7995fc7149317f4cbebcece8336db2068380070784a4283
+Payload = 08c43bbfa706512aa39e2bfa5c365aca11e22e
+CT = 9a9daed67bdc4cfd9c2b0fcf06019ec9de623140bac6094528f02eeda093312fcf716f
+
+Count = 193
+Adata = bdb1b82ba864893c2ee8f7426c7b9a8460b00a50f164fc8f2ff2ae9cddab8657
+Payload = a531c0ed8840b2fcf08d76eca71036153b6e11
+CT = 37685584549aaf2bcf3852d9fd27f216f4ee0e0c041d86dd483c1d6da366e91bd826dd
+
+Count = 194
+Adata = 38b3b9f45041ceb743fc2655b409213fa081427e41c833a2321a09fbd566c80c
+Payload = 177946b4dc3b0b825a505f097a0a203eb21c00
+CT = 8520d3dd00e1165565e57b3c203de43d7d9c1ffde45ca2a83dec2f930bb652a6fcdc5f
+
+Count = 195
+Adata = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878742de83154a578da
+Payload = a2634ef20a2a418b2c3be64f0b5f79d7ea9b7b
+CT = 303adb9bd6f05c5c138ec27a5168bdd4251b648b89aa22cd7d0170a975565cd3a33dc1
+
+Count = 196
+Adata = 8f6c1de4efdc5ac2d6e5452b5b4f58416d618da672f521332fd297ede8350134
+Payload = 40e52edaad5acf2d4eedfb3f9ac2908112e9b1
+CT = d2bcbbb37180d2fa7158df0ac0f55482dd69aed960b33c3df5cd38a82980dc0950ada4
+
+Count = 197
+Adata = b0f1dc85fe223bcf29cdfa9319866bacd0a0a79c554e24d1f10889279e31c0af
+Payload = bf97780f498c23adcf1c49f60873780a235969
+CT = 2dceed6695563e7af0a96dc35244bc09ecd97638fa273c4102b5ca050b23044ac2064f
+
+Count = 198
+Adata = 7d02a323aa769a8201549bf48a520d940bf6f69ed6106f1ce68856c22a594216
+Payload = 58bfe1eb2d38d91f80b3467db94fdcb84ff5f3
+CT = cae67482f1e2c4c8bf066248e37818bb8075ecc15438af1bafac3eac61e1c24ed00ab7
+
+Count = 199
+Adata = d4b90ef8abad08c552c8c3b080b8c37df314d514049d45e27ec4527cb06cdf85
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59
+CT = 305f3482ac73cf9c8a520b04144a55ddc8cf464422d9e2f4f84fde49e9701296294d5a
+
+[Plen = 20]
+
+Key = 78c46e3249ca28e1ef0531d80fd37c12
+Nonce = 5de41a86ce3f3fb1b685b3ca4d
+
+Count = 200
+Adata = e98a77f2a941b36232589486b05f4278275588665a06d98aec98915cc5607e06
+Payload = 4802422c9b3b4459ba26e7863ad87b0c172cfe4b
+CT = daea2234ea433533bf0716abe1aa3844b6d3c51e9d5ca3d8ec5065630d2de0717cdeb7d5
+
+Count = 201
+Adata = 5970a836de1f1e91d94d7eef79742cbbd46a759c413715eb0224fd6a27145333
+Payload = 796a69ad0e9379173ef6b66f44f5c84fa70a0e28
+CT = eb8209b57feb087d3bd747429f878b0706f5357d0ff0648ddb07f42f815b38bfc95688b1
+
+Count = 202
+Adata = e3f08834c4894f6fa66a55a280c0e677a79e97c1ef9488b21384e74e57b1b51f
+Payload = 98e1f8cf250183b13ad418024dc40c1a6a7ee8ac
+CT = 0a0998d75479f2db3ff5e92f96b64f52cb81d3f93ddd9a6977ea8e7adf5c5234346e560f
+
+Count = 203
+Adata = 18349be2894d49290339b97f4db28c92b3e112ffac77100abbf9c093935b1a46
+Payload = 4a856d9b50a5b40d6566b38eae6a53ed0c192805
+CT = d86d0d8321ddc567604742a3751810a5ade61350bdee05328a7ea8cc6c2e42bf3faeeda0
+
+Count = 204
+Adata = 7355e34ad13880de17a1d66b02672ea5c9f51774019f64ecbe36747ffcd9b671
+Payload = ad048eb2ad75266b43b59d9d1f073c44e4cbf25e
+CT = 3feceeaadc0d570146946cb0c4757f0c4534c90bafb1435cf929db35ec5986aabaf4a7d1
+
+Count = 205
+Adata = 4be21ba2eb26234ddcbb6aac6b4c3be7ef644af64edf51b7c29ffc3ddd80036b
+Payload = 5b527ac6cc6d1b4c3c56f8315bc96dae91632df9
+CT = c9ba1adebd156a263977091c80bb2ee6309c16ac736be6563cf9f5bce97486b7cc6f1c18
+
+Count = 206
+Adata = 266e0e3365e06d3b1e864c6e5897145df7bdde90eb744013a7b36632d4cf6580
+Payload = cee059cb0fe91a39faccc2914340baeab4b644ce
+CT = 5c0839d37e916b53ffed33bc9832f9a215497f9b2e90335fcea56b969b4fce65442768dd
+
+Count = 207
+Adata = 55a723883a340877d85ad1a5f264f2c834d824c7bbf207cdd8500c9d11ef9225
+Payload = 85321fef6a2b7d31cbd079c4bf2bfbbc979df90b
+CT = 17da7ff71b530c5bcef188e96459b8f43662c25eacd6afdb3578ebc75e8a408d32758931
+
+Count = 208
+Adata = 773864475a1a60a778468a66cbe13dfe3458094e62abb593f50c8495e3a8b81e
+Payload = e227b8d44320bd3ce9d3f7d688f3de887947b1e9
+CT = 70cfd8cc3258cc56ecf206fb53819dc0d8b88abca19fb73fc0488d9f29a09c1b47e3e066
+
+Count = 209
+Adata = f64f3b00c9117aed3c486aa4c8d574b44d679be4069e1078bb7100af38cdb190
+Payload = 206e9eb2bc3f8534d844a38debf1306df808744a
+CT = b286feaacd47f45edd6552a03083732559f74f1fce2c5ef8cdce76b358739e2a1b173fb3
+
+[Plen = 21]
+
+Key = 8883002bf13b3a94b2467225970df938
+Nonce = 818a702d5c8ee973b34e9acda1
+
+Count = 210
+Adata = 545aeac737c0ca2a3d5e1fd966840c3a0d71e0301abbe99c7af18d24cc7e9633
+Payload = d516bbff452e7706c91c7ace3e9baa76d65ff7050f
+CT = b85242fdc06344f2bd9a97b408902ebcd22aece3d42f2da4dd4d817c9fa2d44bc02163a0a9
+
+Count = 211
+Adata = f032db01da60ca078d35c3fb5d05d6750fce1c01911a0422e827e8976946e4dc
+Payload = 590d1aa655fed50ca2e402299f2da6fe20eed56071
+CT = 3449e3a4d0b3e6f8d662ef53a9262234249bce86aa180f41bccbcd47c8b7890754c032269b
+
+Count = 212
+Adata = 71ecb4252518997b53491cf42a3e0fe1496a2af2329a16f9fcd9c4f249900341
+Payload = ecd86cdb7d78d310dca5b477cd9da2612f5a05ab39
+CT = 819c95d9f835e0e4a823590dfb9626ab2b2f1e4de21d6ba58cc2eb474401851bf9502c3413
+
+Count = 213
+Adata = ec7abed9bda4a52fdf1bf278b6bdd6b0a27d4688deb9ff5ca9c8c865a4d2f730
+Payload = 0024b14c283df032cf80c22ad8d2c96289ee229092
+CT = 6d60484ead70c3c6bb062f50eed94da88d9b3976499b94d4b7a2044696c72322e850537b6d
+
+Count = 214
+Adata = c2c77d7ad7b27d7c0f976a1e28881ea4ec7ad03b63a4e67f47280a40b8f58086
+Payload = bc6965d8f62d066d118c14044c1fd2a224b9d95110
+CT = d12d9cda73603599650af97e7a14566820ccc2b7cb9d8da8e718570caf8bed7909fbff3ec6
+
+Count = 215
+Adata = 28929286bd1391468ac75f5c03689f74780ddd7585fc16f9a9bf7b00357a72e5
+Payload = da4a630cabaff0728a1cc3e6a79721a7176b708f1d
+CT = b70e9a0e2ee2c386fe9a2e9c919ca56d131e6b69c6e671012690c61fe3c9abd50a78eb4736
+
+Count = 216
+Adata = ed360d22081b019dc979420a3a45c21c8903c59daedd9f1b4ef2bfdedff0ec1d
+Payload = a95058f8e1f6bc0f143a9ca7e4425a2a63eb2f7e33
+CT = c414a1fa64bb8ffb60bc71ddd249dee0679e3498e8e657e2250427130acef7032454cde7b6
+
+Count = 217
+Adata = 2b4022d0b951fe48635d04fb3e2fa032c07c855fdd73f45670953bb9ddc77cb4
+Payload = fcbbc7f9d1ace60e830ca56ec84814fbd2579993d4
+CT = 91ff3efb54e1d5faf78a4814fe439031d62282750faac6ff0a264b8199550d93c1f06063da
+
+Count = 218
+Adata = 48e553a87a7d3c1bd68af39f96aca67583da86e06701d5e4c4ed404dc66d70f3
+Payload = b95d298d391c6b893c6cad66f9780534516e71455e
+CT = d419d08fbc51587d48ea401ccf7381fe551b6aa3857e68bf636e81c332f72063dc0d6fc2b6
+
+Count = 219
+Adata = e8e2835e47144365a2f218d4c95d7522e824fb43b66d4727ee570f8303dd6dd3
+Payload = bc79d444dff9d9e722effab07b068cb7723ae8fae0
+CT = d13d2d465ab4ea13566917ca4d0d087d764ff31c3bdf3af9e9c4e04bad261dc17cf00a00dd
+
+[Plen = 22]
+
+Key = 5cea00ee44cfb9cfbb598d3812e380ef
+Nonce = 948788a9c8188cb988430a7ebd
+
+Count = 220
+Adata = 50422c5e6a0fb8231b3bb6e2f89607019be6ad92a4dae8e0fe3f9e486476004b
+Payload = 33bfd0713f30fcac8f7f95920ac6d9b803ddd5480dd8
+CT = b168747dea3ae0fbede4402af9a3dc3185d6d162f859d828101682de32923788c70262b84814
+
+Count = 221
+Adata = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192eada64ae00c726b2e
+Payload = 5576d94b577ed26820fb13c00ab0e2d1a1c3589bfdc4
+CT = d7a17d478274ce3f4260c678f9d5e75827c85cb10845bafc4ae4d31907def6f648b081174e2a
+
+Count = 222
+Adata = 5140324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+Payload = 13303e14068205cbfa992d4ccb6a265804ea64a15d7f
+CT = 91e79a18d388199c9802f8f4380f23d182e1608ba8fe314e378e9ed6e725a14c07632b02bdbd
+
+Count = 223
+Adata = 74da07d324060e590356988f27d9879fa3a3ade0fe71e2a0e49054211cfa1fe1
+Payload = 567e6d14b446add630d53ea86a537c0938537c4604a8
+CT = d4a9c918614cb181524eeb1099367980be58786cf1295bc2f2f9331536f7f70be09c41bda0ad
+
+Count = 224
+Adata = 0e403cff47adee3ec5bb6b178dabfc7d53b60a04eaad33a2fedd9db705358a4c
+Payload = 9f3d165d44cf1c5770346d211d4ff34ca2ecd6b28549
+CT = 1deab25191c5000012afb899ee2af6c524e7d29870c86b59cc9c3c008bc5876ef86327859cbe
+
+Count = 225
+Adata = 211e6ce3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a
+Payload = d726e599db6a6d40629bc4bda5e3fa2e5aeda229cea4
+CT = 55f141950e607117000011055686ffa7dce6a6033b25135e6d59a5385a78658d60d254f99962
+
+Count = 226
+Adata = 3c5c67b083322115e1b3112c2b6968efc050094e23e646dce982eac9d6e67d10
+Payload = 42646cfb8a99e48a35cee3f5f9b3e6175695973f6de0
+CT = c0b3c8f75f93f8dd5755364d0ad6e39ed09e93159861e234e83d9a0570dbf2b2fa59ce3cdbd9
+
+Count = 227
+Adata = 37a931f1dd05755b376d1a164aa36b8de802e39f8108a0453c1114754665fe46
+Payload = e814c7b5c72d973a9bc7ccd463f107325ffa3321783b
+CT = 6ac363b912278b6df95c196c909402bbd9f1370b8dba2084e352b1b157267228576dd056c1a3
+
+Count = 228
+Adata = f1ddc2c49da7363526ba36c600c589b4c3121fbb8c5b9a8aa0de0e7453b30568
+Payload = 4f7a5618870945b89f194e31b1aa802c5350326dc691
+CT = cdadf214520359effd829b8942cf85a5d55b36473310bf88ad35ee338e489e55bb49732447cf
+
+Count = 229
+Adata = d14b3d3803df432488b5d66704abef6a500d397e855bc2c2574df746a515cf70
+Payload = f555216840a1f40b411d44128e567617e2694caf1621
+CT = 7782856495abe85c238691aa7d33739e64624885e3a07ab67f9397a81371ef6ebc775cb7007b
+
+[Plen = 23]
+
+Key = cb83f77751e72711401cbbf4f61aa0ed
+Nonce = c0b461b2e15b8b116ef9281704
+
+Count = 230
+Adata = 2bd112231f903fa0dff085db48a2e2a96ec0199249b005d5ab4c2eab753f9ad0
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06
+CT = feb114b7bd3b43497b62454a675a632c3546d2802462c6af57647efda119c59862cd5dd3904efc
+
+Count = 231
+Adata = 864e0e728aea856fae6c6daa6357d1542cef7177f441ba21a563f6c4f6fdc1dd
+Payload = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0c
+CT = 9a394d88d7405656df1a50e7e45fa8ddcca85e9ed5a3cc2af4027ca5824b41c7bb238d3e8eeebf
+
+Count = 232
+Adata = dac7f3cba0b5a47f67f85b226b66df695a8ae2501355e36aad105375bb95f732
+Payload = 66e34540d7accf377877aa2d3e6d2db0cfafc608a1eb3d
+CT = 768c5047e50dbc42dc0126fa23723db5882ffb7a2452fdf7fbd7044ce1d7b266bdf545247a3c2b
+
+Count = 233
+Adata = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c930905aadd156b1dd56e
+Payload = a9ebd04fba7155c39b5c29c5571b5354c9ae228f5e5b13
+CT = b984c54888d026b63f2aa5124a0443518e2e1ffddbe2d3afabc559b552cf7c7730c7dca25bc3ed
+
+Count = 234
+Adata = 2d24e79abd157af2c21b60932947fd9f9d6478f09ec56fffd341ea04a17b8e5f
+Payload = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381
+CT = e116203ddd955c7acd6a23c8d69e0e3a2284dc3fe82a41488ca99e0f85ac388f981ce25560b8f9
+
+Count = 235
+Adata = fea280f710379e4665b5ed3d1620729a7bc164899dc83e6aee3612d538fa20db
+Payload = 6c19a18eab544acc883c5886eaa89f54d61ae5f1f1368c
+CT = 7c76b48999f539b92c4ad451f7b78f51919ad883748f4c9156faae3d8860bed216e8d497a75962
+
+Count = 236
+Adata = 18f2e3457127c35f2e0cff2d821af8178028fcc7803bc795c49f4a435b37abeb
+Payload = d0df1bdf1df6203241722fb9c9c1cf7405017497ae1545
+CT = c0b00ed82f575347e504a36ed4dedf71428149e52bac8588cd7791c544d1098b2de49d04b1e0c1
+
+Count = 237
+Adata = 35221f0efcb109cb93c38a62c58b5ab8b236437e171e8507cf417a569af1767c
+Payload = 479526b33c42c240b9a4549ca70cbfb691f16ae3be8888
+CT = 57fa33b40ee3b1351dd2d84bba13afb3d67157913b3148c523fd8a2524717f63dac75c22268fa6
+
+Count = 238
+Adata = 95f2ab02af01aeacce86b02cf846f9fbd516963d06e350e8b7f6df2778765a01
+Payload = aa6761148b254a2ff202b620c2ec2c5e623bf61f05e483
+CT = ba087413b984395a56743af7dff33c5b25bbcb6d805d4392904f05dc2397596543df73de5aa708
+
+Count = 239
+Adata = 3746a36154e42dd600049d506f5ce4d034864263b1a65cecd24c8e25fb9c82e1
+Payload = 2f298f106703b8a994cbb20acf47f9442e44f6b5e82c38
+CT = 3f469a1755a2cbdc30bd3eddd258e94169c4cbc76d95f8c3cbfecfa3f75fb111ef0011222b7948
+
+[Plen = 24]
+
+Key = 43c1142877d9f450e12d7b6db47a85ba
+Nonce = 76becd9d27ca8a026215f32712
+
+Count = 240
+Adata = 6a59aacadd416e465264c15e1a1e9bfa084687492710f9bda832e2571e468224
+Payload = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5
+CT = 14b14fe5b317411392861638ec383ae40ba95fefe34255dc2ec067887114bc370281de6f00836ce4
+
+Count = 241
+Adata = e82fc3ffd276218a82aede65fe5abf4fd35c7059a26923f8dbb97a59c903a7f4
+Payload = eab8cef576816a82ed036f158e5036f5987b195e60582a6f
+CT = 4b0f27aa559a3ad6b7830e7e46db62a2e578476540f489460d2d30268e9f1ce0e7c762993297d828
+
+Count = 242
+Adata = 776aae7f62225556b6da522c0c9432ac70fe72ac6f3f361071ef3deb4a6715e8
+Payload = 566ef9ce1d397be2547c385639507a9e7d6f9eed9a3b1055
+CT = f7d910913e222bb60efc593df1db2ec9006cc0d6ba97b37c0939e56f0b7200d1b1409f3f8e8179cc
+
+Count = 243
+Adata = d9aef0955922f89747ba4a8ddcdb8c1c7579aefd3c2eb8ad0589c66576a8504c
+Payload = 8c28b6d93b23f1ea031d5020aa92f6608c3d3df0ee24a895
+CT = 2d9f5f861838a1be599d314b6219a237f13e63cbce880bbc138e3b817023993608be06fe92efca8b
+
+Count = 244
+Adata = 13c222a65ce30570ecac85a185a2a0922a8c96d633339a1ca067ce57ae426e1d
+Payload = f0c1cd60f5fa8d1efd5e2e1ab37c4f7e6aef76d15e8d6ac8
+CT = 5176243fd6e1dd4aa7de4f717bf71b2917ec28ea7e21c9e1f3ca13b4ab7fd0d4badf158972570c06
+
+Count = 245
+Adata = ce40fb0cbfdf07676ed55b040ae6be5db8f0a0f28816ae8ea71da3cbd71661d8
+Payload = 570d5f79aa8db14b1ac99ee567cc105ae9e238e482b52628
+CT = f6bab6268996e11f4049ff8eaf47440d94e166dfa21985010a79fa4e8b27a31ff360a1b6c05ff844
+
+Count = 246
+Adata = 446b01d09cbc41b6393ef81ca65ab7e099018187d5f9d22f5074dfc491e72077
+Payload = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4
+CT = dd919b7c2761a912eaef0b2e37551e09b99f76833c0e8e8d5d34ef0ca0b47d6a2ec7442cbb739504
+
+Count = 247
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2398e86ac3fe48bc7
+CT = 6a46fbbbd89e7738148905f4f56971e5448dd8971f4828ee8f607d154393e35fd1efc1ae8cb244e4
+
+Count = 248
+Adata = 5032b818d202872f3fe2b08fc7940696df02cf393a6d6247f5c6f5f2125cb08b
+Payload = 4324a89788e8ddae5d560cf937df701743cbbc3bf980558c
+CT = e29341c8abf38dfa07d66d92ff5424403ec8e200d92cf6a5617d9cebea38591a00c9fba4ef9c8e71
+
+Count = 249
+Adata = 27b661861717f00a3ae22ead78f4dc3f32b40e8fcb8ed58167a31a61f2becd77
+Payload = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad1
+CT = 7ac530d240e740f8a5fdaf87c6adc5ff73cdbb312e39d9f897062a1ec759a515b938780f902fa7c2
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT192.rsp b/lib/crypto/test/crypto_SUITE_data/VPT192.rsp
new file mode 100644
index 0000000000..abf1775dd1
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT192.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 086e2967cde99e90faaea8a94e168bf0e066c503a849a9f3
+Nonce = 929542cd690f1babcf1696cb03
+
+Count = 0
+Adata = 58f70bab24e0a6137e5cd3eb18656f2b5ccddc3f538a0000c65190e4a3668e71
+Payload = 00
+CT = 3bf9d93af6ffac9ac84cd3202d4e0cc8
+
+Count = 1
+Adata = 760d065275e345900a7bbab451cc9309fb161e6cfec526538b98800e4102e14d
+Payload = 00
+CT = b0078a769ab68db44e723993da382abc
+
+Count = 2
+Adata = ffedc67efd355ea404fcbcb3993d3bae81386ded86230270771deb747163bf44
+Payload = 00
+CT = 31fbff2d715a2eb9af54e8320a8e42e1
+
+Count = 3
+Adata = 55153ff5e4d208d2e647794f382c788e0e36f293e63e7290ba9ff2657ae0f167
+Payload = 00
+CT = 945839d62c9d1b899f6dcd0ca9517e68
+
+Count = 4
+Adata = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe6ffbad084f639915
+Payload = 00
+CT = 903f90d23321a6882d6c4c1955b14847
+
+Count = 5
+Adata = 7b95cd827ab93507f1819ae76627d6e2a31d29890c092e5c300f0e2f9e4ef4d2
+Payload = 00
+CT = 652ec5ab43088eb568186d0d9887b30f
+
+Count = 6
+Adata = bd144c9bb974729aaa1188ceefdf85e1d9fddc0b0c8afe8828ba204aa9293feb
+Payload = 00
+CT = e6c1455d1117eec49338c96f51007309
+
+Count = 7
+Adata = 92b911cdc3137a6f7f32651b788eb82975660aea52b2c03b4759755a6da4a0f8
+Payload = 00
+CT = 1cf3c32fb229dac209523eaa517bb59a
+
+Count = 8
+Adata = a8200dbbfe4086015cdbdec2fc8e4934d0d663527430c424627ed44065ade091
+Payload = 00
+CT = ee10bfeb1cf9b3cd5a0faebd4d8f3fe1
+
+Count = 9
+Adata = 3b7f37b6b8e3c1390a99d59c47f7c102cf659d361a132ef8b4e70b9585bafebb
+Payload = 00
+CT = c51ed994253adb9bb5b9a8c34a27f225
+
+[Plen = 1]
+
+Key = 992d38768b11a236945bd4b327c3728fac24c091238b6553
+Nonce = b248a90b84b0122a5ad8e12760
+
+Count = 10
+Adata = 27cabc40da0e1eda0ea5f8abbb7c179e30776250a7b30d711b0e106c5ee9d84a
+Payload = 1c
+CT = 1a96f58c3f38c44d1a345f3e2da6679f20
+
+Count = 11
+Adata = dc2e28d5ae726c1beadb1e7e92ae7d14f5546320deb81a910bf170cbe0210eaa
+Payload = e9
+CT = ef0579aee7c17482691f3f832d867ffea7
+
+Count = 12
+Adata = c579f912ac1b45d5aa8cf20f78f0a1ace32abd3dc7fd0b3f3a7182a008795c7f
+Payload = 97
+CT = 913452d8ece38ffa1d4107d6a053acd8c8
+
+Count = 13
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9fd48894c9b55e6e8eb360a6211
+Payload = f4
+CT = f20d760b9fe29530738157db0ba2d253f0
+
+Count = 14
+Adata = 622835dea57b2c70cca8f7548d6210714070b55b36adde7a4c547269c07aba9c
+Payload = 9f
+CT = 996fc21f24dee7b52f51d69eea30819f4a
+
+Count = 15
+Adata = 67ebda0a3573a9a58751d4169e10c7e8663febb3a8cf769d81bc872113f0720f
+Payload = 43
+CT = 4594c5b8db0064426a77dc536814c56147
+
+Count = 16
+Adata = 255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1
+Payload = c1
+CT = c76d36c0b0d699a22da3116dfb8f453181
+
+Count = 17
+Adata = c7c8e7151eb6844a954d091b460f83add0f0a634aa5ac213b774f2451aa497fb
+Payload = 31
+CT = 370c3a1690acc3f0eb09c9cfd3396c7fa9
+
+Count = 18
+Adata = 63f00b2488809fdc49ca5f05d54e98468906308115f7e702da05ddfd970b5537
+Payload = a7
+CT = a1ad45070fe4c61270c13cc52247fee411
+
+Count = 19
+Adata = 8e2c5e55c0bf70014e9897b6f6940e4e738b1e84e8269b6382f0b1fe59b0e162
+Payload = 40
+CT = 46b2a2a8b283ff7eeff5c2670f77b8809d
+
+[Plen = 2]
+
+Key = 5012db40ff6ae23c1e1ce43768c5936c4400b0e79ae77f30
+Nonce = b67e500b35d60ad7264240027c
+
+Count = 20
+Adata = 40affd355416200191ba64edec8d7d27ead235a7b2e01a12662273deb36379b8
+Payload = 0c6c
+CT = c996ef3d6ef9f981557506ecc8797bbaaaa7
+
+Count = 21
+Adata = c5e12e17e02bcc12b3a4c14cf837250e2886db3ee1c717d28bd11e8a3b764ddf
+Payload = 23df
+CT = e6254405257a837c5343b59d5689d6de5269
+
+Count = 22
+Adata = 213b5b6015d472bd593be5acf85ebba6d6a09f3a962be302ba83c6d70c61f241
+Payload = 0dc2
+CT = c838e93e67d37d2367bb1f27f71b54b29317
+
+Count = 23
+Adata = fc1b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+Payload = dc88
+CT = 1972ca3744a4ab375af9060621a9dc4f4c32
+
+Count = 24
+Adata = 5b2eb1a6fa585d61d1fb3da68f5b93829c8e2d5e4fe03782617553d7a130ecf1
+Payload = 8179
+CT = 4483172626e930d24052bc056d8609c4175f
+
+Count = 25
+Adata = e2b3c3bf33cf847660929e48cce51d9d9289945169651aaecb1e939756e93105
+Payload = 01fd
+CT = c407852310207be8d3417de800b372700da2
+
+Count = 26
+Adata = 6051f12cd8aae68b4023aaf7178fd086aa582b8d8821e36637abc97025f5e858
+Payload = ca18
+CT = 0fe228553bc037954dbf4ce5db99792c2c7a
+
+Count = 27
+Adata = 2d3555faf285caaddfe95c010c2a7f233e09c2fc0cd30d644035269280527ad7
+Payload = a855
+CT = 6daf904725668634d6345bd8f90a3831b452
+
+Count = 28
+Adata = 4fca820dc545bf93bdffed33a04b67eb45384e696f092c2197e5d79cecd09913
+Payload = 5555
+CT = 90afdf6098cb3135c3045a54ffce88efaceb
+
+Count = 29
+Adata = 1789ae403e183d2225f431f001d475b53bccdec66572bb027340ae592839ba8b
+Payload = 11dd
+CT = d4278568e8c08ff5ee5ea0a608589c2fc029
+
+[Plen = 3]
+
+Key = fa15cc7f0de294d7341b1fd79326c8be78e67822343c1992
+Nonce = e5257aed2bda0495aa44591db4
+
+Count = 30
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+Payload = bcb898
+CT = 68f08298d9a2147776dca9c1a42382bce323b2
+
+Count = 31
+Adata = 4863dd810ee70ef0f5da81f60c5ce550abb96454619032322e34657af25207de
+Payload = d1da2e
+CT = 059234a9a77755b324f3a557217752ade14ed7
+
+Count = 32
+Adata = 173594fc26b167f044aeaf9bfe920cab99a27eb2b01827d61f7553cb2018b5fe
+Payload = 394f31
+CT = ed072ba4441a79a90e228a28069fe109d5d876
+
+Count = 33
+Adata = 71cdd16eca9255aeedc23bd623513918ea97da21485074415fe75bcc42f454c0
+Payload = 868bda
+CT = 52c3c065f272f44c5210b5bcc571e819580910
+
+Count = 34
+Adata = e84418d332d16d2298e69e7ff3c37bc7b6e030cc822e73b3f4a0029bc2ea4d80
+Payload = 52d6bf
+CT = 869ea559c5f7f73a1b5f419c9f63ca401894a8
+
+Count = 35
+Adata = 42d962109bea1d50be0f3d83b4c2a6033d53b3d7112591866b1ae52dc84cb5d0
+Payload = 6f8d58
+CT = bbc542220b828cf5365137fb3f1df67cc8d2a1
+
+Count = 36
+Adata = 943b4327b5c70dba63c82f27e0412b3ada012bc0f7dd39ebb13db2f864daf80e
+Payload = fda286
+CT = 29ea9c422b0f41075ac79a0afa2d1047cbbfb5
+
+Count = 37
+Adata = 6076b94caabfa476ab7e6482e4fda9b29f2e2b2883efe44d668c7c74628505bb
+Payload = 8651fb
+CT = 5219e1ae68cd6d6815ecbfd01293d160d4d38a
+
+Count = 38
+Adata = 3e4bb5781f84b4bbd23583e3dae561c6ff4af8eff35e2a4f35b50d2f360d3469
+Payload = c3e179
+CT = 17a963fbaa81cfdbcaee476860cd5102f556e4
+
+Count = 39
+Adata = 364008acbad330d0b8d574641a97b0682c49279cfdc80ff309b7514514d18a44
+Payload = 4a97d5
+CT = 9edfcf7ad1520564b68824a3a939371c21a336
+
+[Plen = 4]
+
+Key = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf
+Nonce = 2ef29d62b40d8643848797cde8
+
+Count = 40
+Adata = 1225b036e6044df52314016760e92750de0936120395de750a2c54a7fa0cea82
+Payload = b46b343e
+CT = c2c39d6f9344e2de064f269d065a2a6108605916
+
+Count = 41
+Adata = aaa6257d6783936a4445833c2ac3bea8cb7334f22ade9c035d515bbc91d6a78a
+Payload = cb216301
+CT = bd89ca50693d90b8297b90bc41c231d08b0204fb
+
+Count = 42
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c1124797e564b63e008e7b8ab
+Payload = 697a8696
+CT = 1fd22fc79d0146fe373437c529fb2eeb169e4bd7
+
+Count = 43
+Adata = 864d0f786497c7ce283762ca0959ec9c825ed445a5dbe5b4b2e5772fe88ce7f5
+Payload = 6bee3db9
+CT = 1d4694e8e389c549bfc4ede936d7896e544b23ad
+
+Count = 44
+Adata = d5388b0b548c58886dcd335dff2b1ed23ce3eebbb708fb5bbd831c83e959d3fa
+Payload = 85d95855
+CT = f371f10495177a9fe6d9329a585c8737c92a4d29
+
+Count = 45
+Adata = 83cddd189736f224cad6a29efba45e43c75450a14f1541713b7fb926ffc768c6
+Payload = e8b23340
+CT = 9e1a9a113914431a10b1f94a2b99b9e442f3dca4
+
+Count = 46
+Adata = 8fccbd1fc5240691cf24e8807bf3416c1b2d87fc86dbf3955fa2e52b9a3a8457
+Payload = 595c4d7c
+CT = 2ff4e42d383d8dc98b22010dd93cd0cbb396d9e3
+
+Count = 47
+Adata = 513d45f6f37f3f051667dc743215059e06e4fdc8945789b16d50556a2e839368
+Payload = 314e0c7d
+CT = 47e6a52c40c513bfc92d1a7db5ed7cab2d8212b0
+
+Count = 48
+Adata = 70828be102e554f0d4b07641fa3254bc8db06eefaf5b85a7c97e01c217fc8f3f
+Payload = 35753e32
+CT = 43dd9763ea98f4ac6b3eabd483f1e6ab92f3b83c
+
+Count = 49
+Adata = 343d5a4ad39acf81adcf24e9807618932abcb3bc076734f179174c77c8cb89e9
+Payload = a531c0ed
+CT = d39969bcf99fb67b1e2aba2d232db2445e6aec2a
+
+[Plen = 5]
+
+Key = 30419145ae966591b408c29e5fd14d9112542909be5363f7
+Nonce = 27e6b2a482bbc6f13702005708
+
+Count = 50
+Adata = e04e81e860daf9696098c723085d8023c240ebe7a643131e35359ab04bd650fe
+Payload = 8ceaeb89fd
+CT = ec9d5ed36243ddf77b33d8cf2963ba76fd4e19f3c5
+
+Count = 51
+Adata = 6217cd581d4b3b2f7bcf1b8dad9ad6430e2e3a0063cad52260e0a1cd6fc9e73a
+Payload = 7e51d6f870
+CT = 1e2663a2ef6b73fe9e638e205b27f78ed1bb9b0ed0
+
+Count = 52
+Adata = 8aa7847e496f5e9f1f87851442de844f27a21c1b48f82fe525f0dd5a88b8ec38
+Payload = e0023b674d
+CT = 80758e3dd25936115e23158aff1916edec241fad56
+
+Count = 53
+Adata = 3612abc865a4d8d7b86a84109388584df6526525adb1006ec6c8d00048d725bc
+Payload = e2b5b6f36e
+CT = 82c203a9f1f15aae4b70dbee244be1daa74475d7e2
+
+Count = 54
+Adata = 849a99c6f1cae0ad4bcde4bd0811e87ca5ed7b913de1a8285a206e980b4b7043
+Payload = 9a17e4a22a
+CT = fa6051f8b5bbff424487848385f8501ab5a77f327c
+
+Count = 55
+Adata = 9066367c784de0a4d1116bbe95ce55ded85edddb6273c2049ee24e0fb3429352
+Payload = d4e765fc78
+CT = b490d0a6e772d8d5da6f593a8d9956731b42645aa9
+
+Count = 56
+Adata = e7aa9f767fa8920f96f91c41d9e86755faaedaeda596a444b65f99b7a9e23e85
+Payload = 1074349e10
+CT = 700381c48fe3eca12b835dcfd08166ac8831585626
+
+Count = 57
+Adata = bc0db1ebf910b6f4dcad5401401d6bc2272e23130947dc236ca664d5b5ed6d66
+Payload = a46dd7fb58
+CT = c41a62a1c72bcce66018e9e552d2c8a229301361df
+
+Count = 58
+Adata = fcbeba2d0d73239d05f691a52b08152c9dd871f8dc76c2c18b8a638a74460d31
+Payload = 2e0ca09221
+CT = 4e7b15c8be3e41a50a28ea3be14baadf12964a37c4
+
+Count = 59
+Adata = dcdefce64ae4339f46c0759a4a10b29d59daaaf1e5dbf75cf11b4e4f73c5025f
+Payload = 2e108ce0fa
+CT = 4e6739ba65bee2ab25bfafa76dc3e54832b2f76864
+
+[Plen = 6]
+
+Key = 748ad503388a34041a7bdae6361d57894357c333bacf02ca
+Nonce = 518b79d194579b19f2d8845b70
+
+Count = 60
+Adata = 691dd98f61fd213b0840ec5a6f06ef9a1420be0d59bde5e43546347a2a865a94
+Payload = 24d6880aed7e
+CT = 270120f9634ec15536e21d961c675070ec4cff9037bc
+
+Count = 61
+Adata = d1fd047cdb18463766841abb1fcd25257f1458b595bfcf24066ff9385232fa97
+Payload = 2298028d0213
+CT = 214faa7e8c239b303af0b098f902dc24e66fe56adc6e
+
+Count = 62
+Adata = 65a480d120a0459dab69e8f23094801e10092666cc56f9fb2549662982bda6d0
+Payload = f248e5225e3d
+CT = f19f4dd1d00d1b657925a9740d6828bd85cd12205764
+
+Count = 63
+Adata = b738a53fbc9689dd49f68f97f5a99665258cd52e74dc653b594cffec045508aa
+Payload = 611dade00cec
+CT = 62ca051382dc395a1c49129ef6cce0ad5f6ef378aa1c
+
+Count = 64
+Adata = 7006f54184f0ff0ab215ca408d46325b86c1cbae6da7838435b1826ff81f55dd
+Payload = 5871a8300471
+CT = 5ba600c38a415e68468d1b2b516be3d688567d84ab80
+
+Count = 65
+Adata = 9e6e6675d4c6b1e0f3894aac071f4c99a364708edea12f319cbc27b40fabc0f1
+Payload = 3ca8a7520e94
+CT = 3f7f0fa180a40ba1af163049d16817021665d183bc9e
+
+Count = 66
+Adata = 10ceef716f54b74d7c8a435d6aa38a10ff23939ca29e2de7b6c3e0a8269a23c9
+Payload = 9c2a0070fbba
+CT = 9ffda883758a670f35869da9821b6ff1fab3e6062ad4
+
+Count = 67
+Adata = 3ee0865f29be50160273b4a94ec078932b9cd10a858e31838d5b607867e1ce69
+Payload = 436179c74fd2
+CT = 40b6d134c1e208f395250fd79087c858b83755411114
+
+Count = 68
+Adata = ec2b8bfe1ccd491b02aa4a9178fd6f099556963e39e2ca5fe6ecb6b5d2a46085
+Payload = ecfa41c614c5
+CT = ef2de9359af5afcbd9af2d584a0f638d066f2496d9be
+
+Count = 69
+Adata = 5b6f6369643d83b1db33d75257d7dea761e574e6e1f1ecead64e5e354a2f4235
+Payload = b48c10105dbc
+CT = b75bb8e3d38c17861882b8930296fd51d969a1e9489e
+
+[Plen = 7]
+
+Key = b930cca30a3fd230c237c8f3cc6792d0c4084dff5c18d775
+Nonce = 7574802fd82fe96c05431acd40
+
+Count = 70
+Adata = 1cf83928b6a9e525fe578c5c0f40c322be71b3092239bff954dd6883738d6d71
+Payload = 2a755e362373ef
+CT = f06238b0450fd1f4b6cab1383adb420c4724aa7bdfefb7
+
+Count = 71
+Adata = bb5450f66273f63b2f79dce177381ce846584ce4f7a0ad5a0171a56e149370bb
+Payload = fab43224bf8989
+CT = 20a354a2d9f5b7a1f99175d3dff5a73f0053a95c36fd8d
+
+Count = 72
+Adata = 3e5e1037bd2922eb20c34200c470b76e537baf7e7f1d8dd2f7a184a593c66554
+Payload = e3aed6715aa429
+CT = 39b9b0f73cd81734b4ad0e41117940abf530093dac648e
+
+Count = 73
+Adata = 3cc88a096a1a440827f5b7da675389e50b5cce35fa2cc36674d6bfc5a3a966b2
+Payload = e78db0f83997cb
+CT = 3d9ad67e5febf5663a8324014550430c7eaeffbd8568f7
+
+Count = 74
+Adata = 2cca33a10b9da7ba99a6b552d1405f2df3fdfd15358d8fdab5e15296b38f9135
+Payload = 726557906845b1
+CT = a87231160e398f34ab635c4eb5b38b86e71da8af3840ae
+
+Count = 75
+Adata = 2fe5dd58b17914187e29029c53cfe5b015ca74cab750d8f95e05f818c3cdf947
+Payload = 043a759b578be4
+CT = de2d131d31f7dabd9961766e03eaa7e8888227c98d1f42
+
+Count = 76
+Adata = 8b8e3d7c88fa16d70130cee290b7e2eecf0ce711118cd9265093b11467e63554
+Payload = f31f2fb4b3fd80
+CT = 29084932d581be637842d96d13c4aab97e296458745a9d
+
+Count = 77
+Adata = 6341370e126097f9721a13c977eb4875cf1286e15c3adfa4e7597e0e13d93b6a
+Payload = 7e3c8224104669
+CT = a42be4a2763a57a51ac46611366c666cab6bfd3d1baaa5
+
+Count = 78
+Adata = 227926b62f7cdd90e4d3b0cb5457e71fb087d329671f0fa891ec06eb8edeb58a
+Payload = 26a0528ae6f9c1
+CT = fcb7340c8085ff8c7d7e5aec14845f844ad38544a2f11d
+
+Count = 79
+Adata = 05b50c40b02e79b74b94d726a7ce8b2b7216ef8af6e7a42d041d2a692a58ad83
+Payload = 61dcf53d1a184e
+CT = bbcb93bb7c6470f1605ab8a2332012b759ccd2eedbed24
+
+[Plen = 8]
+
+Key = 314c136999e41d137bd7ba17201a9fa406025868334e39b3
+Nonce = 65f7a0f4c0f5bba9d26f7e0ddb
+
+Count = 80
+Adata = 5c7ce4819b30b975ae6ce58dcc1bfa29a8b6dda8f4b76c7e23516487745e829c
+Payload = 4d54d8b06b204445
+CT = 2baf90c490b11f9607482362ab3f157c42d0e9c6c5cffcf0
+
+Count = 81
+Adata = 90257ed88679197b8219bc4c2434a71a4e3664d5859c4ffb9a075654898ffedf
+Payload = b2a35df881cd63a2
+CT = d458158c7a5c38715389509b5b6f2df1faf7e8c39203970f
+
+Count = 82
+Adata = dff8ad83525d8235eacdccc91abeb80795e6b5f463fd28af35c46199f646ceb8
+Payload = e98f5e5a20d02c80
+CT = 8f74162edb41775395328747ca544e987df28883d0377b35
+
+Count = 83
+Adata = cde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f59285
+Payload = 90c3e48313cd4fe4
+CT = f638acf7e85c1437a4ba841883a0d7aeda398c043161966f
+
+Count = 84
+Adata = fa88cf5a08be4fb0c1a7960f45726c303eb559861fa60d17aa8dfe8bb5795382
+Payload = 8ad6d5a28ec075e6
+CT = ec2d9dd675512e3509195efe66c5faf413e0f68df8cb647d
+
+Count = 85
+Adata = fe9e93a9370b43efa1560aeb017ff04fca7f207191e6f707c1c35b2e90c44eb2
+Payload = eb83928f0d5f7aa3
+CT = 8d78dafbf6ce2170b51af067ad69ad96009e50ead3d03f02
+
+Count = 86
+Adata = 35792c854fdf1c8cf7f3f8ed2b8ec4f31fe17bf8d4ba49caec03f954bd8bb17a
+Payload = 4cd74ed2fd083011
+CT = 2a2c06a606996bc26b1cb03ee76587f84364825f7c1fcbe9
+
+Count = 87
+Adata = c084108f9c0a74cbf70f614dceae592546865006930db0401828a0eecff98671
+Payload = 52365f94579e0646
+CT = 34cd17e0ac0f5d958fa70c5e195f1f955d64892f532b7683
+
+Count = 88
+Adata = e8045949de61c5c18a63e628330a4d1d12782379a8f9187755409d1825f453c5
+Payload = 8fb85c857a3e38e7
+CT = e94314f181af63342ddf297bdad58083645a052815d29a83
+
+Count = 89
+Adata = 53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1
+Payload = 43d2828e86f7856b
+CT = 2529cafa7d66deb81ad3b2be41dbc39df4c0145dcbae3e76
+
+[Plen = 9]
+
+Key = a19f6be062ec0aaf33046bd52734f3336c85d8368bef86ab
+Nonce = 7f2d07f8169c5672b4df7f6cac
+
+Count = 90
+Adata = d68d5f763db6111c5d6324d694cb0236beab877daae8115ecb75d60530777b58
+Payload = 13511ae5ff6c6860a1
+CT = b3859b757802ebd048467fd8e139eb9ee8fcdca45ed87dc1c8
+
+Count = 91
+Adata = f6e219b29884dab9ea9bad34d9ef8a50ae389c9a908de7154a1f2e894f27141f
+Payload = 7e7e33e1a07d4e8fde
+CT = deaab2712713cd3f3789d0ee8323ea2ee7a68aaaa9c49b98df
+
+Count = 92
+Adata = bcca002d69d9d1044c40ae741ea33ce6b8463f5a28d0514e044fdae2fe7d3c3b
+Payload = cc88980c73e6c5f0cd
+CT = 6c5c199cf48846402437c9fe3d9feb0485e6d7c04423b77a53
+
+Count = 93
+Adata = 39cac8f0825ffdb0668455933ad1581263a23b9e5f1305340528f0320d4b1269
+Payload = 34cb528f50d073cfdc
+CT = 941fd31fd7bef07f35b87e90a71ffe6c30bee1771078a701ab
+
+Count = 94
+Adata = 510a02a44d142c8e975d1d933f828fd7e47d28b88223f1698cf009dc3b079be6
+Payload = cbce3df86438a61065
+CT = 6b1abc68e35625a08c9e9c5be0657649448c38692e8d703d30
+
+Count = 95
+Adata = 40e0418cd52f74d78a8e18ed86210e3661a86d8574aedcee540340d8996d9852
+Payload = 80a2b835f8b0729a4b
+CT = 207639a57fdef12aa213e5f2bfd33101597cfae7cf334a8528
+
+Count = 96
+Adata = 1f2938b3bde19e1af91299c08638061dc3c1ea3284c259d415e996477cb37b0e
+Payload = dd04794e65ce34127a
+CT = 7dd0f8dee2a0b7a293516a7310fbd4ceb90d8db9a86cb6311b
+
+Count = 97
+Adata = cbae5b46e35fa2a279dcaa4c724b923805d4707412a84252b64228c91cedd019
+Payload = 00c4101052f54462d5
+CT = a0109180d59bc7d23cef6165af65f3522dfbfed0293db39ecd
+
+Count = 98
+Adata = d0f27c7f42892f3ad4c0029c5b698abb1d035ba5869a665b1de8861db6c055e8
+Payload = d0865445d3b26b6f49
+CT = 7052d5d554dce8dfa00726434c1349e3e874a2d6bf598d05fc
+
+Count = 99
+Adata = ab0f5a829a9319a74d5d5179aa0a410a0fcf52f344a7a896aeb1f7a6c5d398ea
+Payload = 7c7c8580b944ed3fd3
+CT = dca804103e2a6e8f3aab491e60fc97b3cb5248291e4866dcab
+
+[Plen = 10]
+
+Key = de1c8263345081d2dfa9afdf37675971135e178df554a4d8
+Nonce = a301bb82f91a582db01355c388
+
+Count = 100
+Adata = 9ad52c041390d0d4aaf65a4667c3239c95e7eae6178acc23fb4e70a852d483c6
+Payload = f777aba1fa70f94e6de9
+CT = 9d8bff6d2dcde77104ac6aba025abc01416a7ca9f096ab2529cb
+
+Count = 101
+Adata = b49c7e7b47870c1cc339c7c09aaacfd6115fa8a0f04990367eea10cfacb9d23c
+Payload = 349feebfbe58f93ea3c3
+CT = 5e63ba7369e5e701ca864acb200e85a0d4753a8ba226aca72f98
+
+Count = 102
+Adata = e61ca7310172eec16745a73e34516f65844eecd0dbc5566ac5213626b9096ef1
+Payload = 678a40b4c2c7df0e4c9d
+CT = 0d761478157ac13125d87869784e3321183d8c044657a020e9b9
+
+Count = 103
+Adata = 690f5e5d8da6cdb0f492e80449e152ffe88fea9742564d8383c79cef739a7f74
+Payload = 2b81e0533313664bf615
+CT = 417db49fe4ae78749f5070634d00b1facf0e9e9979ca257a71e2
+
+Count = 104
+Adata = 78e34b0a1d61ccd411cbfd306ea2ef3ce89c0b085deb4cfbaec2ab72ce16daa9
+Payload = 1ac63aa38a206d8e7d68
+CT = 703a6e6f5d9d73b1142d994630ed92e2973b22773f229b45bdad
+
+Count = 105
+Adata = 51bacfcf87ea11da34b76acba8c444792ec3db3c8ee6e600d69679975a682a54
+Payload = 027a7fd7897808ec7a56
+CT = 68862b1b5ec516d3131304571b015bb6b4651f1eb9f6fb3a7b74
+
+Count = 106
+Adata = 5159357a133e4743f903d05bd641da369a3675337760fcd2424a99221ba70b78
+Payload = 1086953d352e94a51a6d
+CT = 7a7ac1f1e2938a9a7328bb0e11ac4608081fd0702a137da0aea3
+
+Count = 107
+Adata = f567820865340314d46a17f520ff315efb6b33bdeda590ca9c4fad604c2d8e8d
+Payload = b8b148aafec4a035e9a7
+CT = d24d1c662979be0a80e252c9ec1317ce30dffeb4c9bf3fd0bbdd
+
+Count = 108
+Adata = 0cfec933831644b468724e808bb3d25fe8f15850ce513fc341da46089c845208
+Payload = 884242a87779d3921f8e
+CT = e2be1664a0c4cdad76cb691e32be3cdd9721a13aabad26dba58c
+
+Count = 109
+Adata = 8edc2b85d44297ac66bdd90d05d8df38124033d6a583bb8dda18a2246ba096e8
+Payload = 25c32770a299020d8500
+CT = 4f3f73bc75241c32ec45333a381be77800654aac335bf9220ac9
+
+[Plen = 11]
+
+Key = 248d36bd15f58e47fcf1c948272355821f8492e6e69f3661
+Nonce = 9e8d492c304cf6ad59102bca0e
+
+Count = 110
+Adata = 9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f5
+Payload = 33709d9c7906e2f82dd9e2
+CT = 9114d36b79b1918b2720f40cddce66df9b4802f737bea4bd8f5378
+
+Count = 111
+Adata = ba13974d95f2eeb367b63850609c53dc66c2710f682f10bef0142d48f851b430
+Payload = 84172985e7d194ba28a87c
+CT = 26736772e766e7c922516a12c94615be2bd81bd598f3022f5775a4
+
+Count = 112
+Adata = 5f16180bfac9b7483774cb0e1d57a43e9bf3cf03bf6fe758293aadcbbef25b80
+Payload = 9a34d32070c71d7de8f512
+CT = 38509dd770706e0ee20c042758e936750e335702542bc598e211c4
+
+Count = 113
+Adata = 4352057bdd1735a85dc0fc4dbeedc73279c27eb24a97641236f03f11cdafb8c0
+Payload = 2054a268b1f6fae4f15d91
+CT = 8230ec9fb1418997fba4870762bb2a7d04ba2ad251d595d0619dc4
+
+Count = 114
+Adata = ddf118ae403b2509e75eb7a26d17e73e527acbacfbe49a56fa3210169030144b
+Payload = f71afe9a60f08a0ef694aa
+CT = 557eb06d6047f97dfc6dbc27d85594da3fd35bd8498d7e389ee7cd
+
+Count = 115
+Adata = 973904409e8154132439926f0dc45c0d81bbbd5793f7f81e20eb818bfa374d58
+Payload = cdf5b47ff73306aa55c496
+CT = 6f91fa88f78475d95f3d80055936db383a8ad10b152046d721d3f7
+
+Count = 116
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f3
+CT = 3cdbdd9338e3992f9d5de5d57e228369e24fe955fd8924526af6e5
+
+Count = 117
+Adata = 8321f65baf9dc856ac1c24f3fee5c74d697eb0b50470d59d8f4a14b506e86c53
+Payload = 685116faa5cc527ac8bfa1
+CT = ca35580da57b2109c246b76c23abfb3b4eb39deb8da2064390dfa8
+
+Count = 118
+Adata = a4e7738038a5116592bb9d92d6d4ed191ab774310f6409e4e45fe907674c006f
+Payload = 9e8c4f1292e8d7e5179b34
+CT = 3ce801e5925fa4961d6222b4272c0639e8e6a1d356fb4fea86762c
+
+Count = 119
+Adata = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005adfe9faab253b572
+Payload = 3ecc2ba566c723462eb0ea
+CT = 9ca86552667050352449fc0633a0f9cdc9490231ec2dd69f6e35db
+
+[Plen = 12]
+
+Key = 77a67fb504b961028633321111aac2c30eb6d71a8cf72056
+Nonce = acadc0330194906f8c75ac287f
+
+Count = 120
+Adata = 8c18486d52571f70f2ba6a747aaa3d4b3ebc2e481ee1b70907dddb94bdfa0ca6
+Payload = 10554c062d269ff6dcd98493
+CT = 7f8b0cad79b545e5addf0b04ff4b0f2b2a5067283210aba8630d0306
+
+Count = 121
+Adata = 4e0b4771c7f6c66f9577c430611fdeec5702296ee3691b6bb8c6a81217edabe4
+Payload = 1c9e7875cf02129ac52daeb0
+CT = 734038de9b91c889b42b21275b16dbdf0b9be3c8c82ac652992d630d
+
+Count = 122
+Adata = 4a687e1d0a95ed2efb95b4c6b040999fcd35136811cd665f934d10224b6064c2
+Payload = 34575694dde459d195b7357a
+CT = 5b89163f897783c2e4b1baede629274d654ef5a4480e24f6bef3bc8c
+
+Count = 123
+Adata = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf823641a12bfce9f5
+Payload = ab20c8e8aab1aac1e4f64206
+CT = c4fe8843fe2270d295f0cd9142ab5407a08b648ce24e9955e28fe47e
+
+Count = 124
+Adata = 4f19bbc3135d7a216465b4c1df2616e8bfc3cc64af0bf52bdc42543f4d2448d4
+Payload = e556ca05bcd1991d2c9836a9
+CT = 8a888aaee842430e5d9eb93e151e94d311c7cd2c1b9048575076ceac
+
+Count = 125
+Adata = b6ffc7387b19786282bda7caad52eb37fbe7e557afcb80faaf57767e2a0f178a
+Payload = e5b665600a2aa413e117c538
+CT = 8a6825cb5eb97e0090114aaf61b71330d72506050368186a5619f180
+
+Count = 126
+Adata = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731203ba3f25b52497b
+Payload = 870864a611aa0475d120bc40
+CT = e8d6240d4539de66a02633d7ea21e36f99e5aab6ffa85994d13d5bb0
+
+Count = 127
+Adata = 8215753d9efc51325f182199e39f9082cc3fe524400f2a7434c68df7eb2b06d4
+Payload = 71afe8d00c6f2ea8c8b050d4
+CT = 1e71a87b58fcf4bbb9b6df437cc93a50dea11c5e0b19f14b9c8f16bd
+
+Count = 128
+Adata = eb8f198da6ee92a03913c6575343f6c749d2377a09430eb751b13c041e6edbea
+Payload = 7021f18b8f398a5999fcdcd1
+CT = 1fffb120dbaa504ae8fa534699cbfd1beafa2d2942f6812b8dfc88e6
+
+Count = 129
+Adata = de2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add794
+Payload = affca856eb412f0b3276ae6e
+CT = c022e8fdbfd2f518437021f9337405235dce6161441caa25cc6007c6
+
+[Plen = 13]
+
+Key = 0d423519e4110c06063061323f8c7c95387776b6ee4e4b6e
+Nonce = 39abe53826d9b8e300fe747533
+
+Count = 130
+Adata = cdd9bf1b4f865e922c678ec4947ea0cb02e78bd5c1538f33aeb818ad3f47e519
+Payload = 4021ff104ff1dbd91e46db249f
+CT = 7953d3cd66d093785d123f65ba37f16761dd6aedbfc789ad96edf1490d
+
+Count = 131
+Adata = 342de5fe61e05c2e58ac2978a871fbdf186a7294ec5f85c4631c21b584231211
+Payload = 95050ca1d494bdb561d4840f8a
+CT = ac77207cfdb5f5142280604eaf8f8e855ae975a1fc64bcce3e7492e9d6
+
+Count = 132
+Adata = 7871482948d8d09d0a7491d915543082cb5fc7d6c1e82ee2218279f54c15c154
+Payload = c45823203b20821a48502f9c67
+CT = fd2a0ffd1201cabb0b04cbdd42017a6515156691b3161b747576078da4
+
+Count = 133
+Adata = 65781d018f27ca0c72a9fa9ab4648ed369646dd3ce45d7ad3a54f6b051f1b6e9
+Payload = e901661b7d47c9918244ee1077
+CT = d0734ac654668130c1100a515225cec7d2566a07cd78181ae94577befe
+
+Count = 134
+Adata = 05556b04dae5cde8525633d1862aa200c54af534e302d2cbd34ddc2b78532a60
+Payload = 5556f799d6a6cffb343f28c1a9
+CT = 6c24db44ff87875a776bcc808c133f51dac00f973fd42e0948fab70ea9
+
+Count = 135
+Adata = 151304e3e4f3c2d4d3227e035d849e0d3841ba00cf6cab1cf2e3e4d6cc760623
+Payload = 56bf26be81c7b55ef898e23981
+CT = 6fcd0a63a8e6fdffbbcc0678a4fe78bdeaa8d408ffe8fe64811aa87742
+
+Count = 136
+Adata = f870cc1fe67d6169279f905b0fe5fd9a0436c36498e4b7c6f584f00f7efe8784
+Payload = 36b304a72dbf4acfffa1d7d624
+CT = 0fc1287a049e026ebcf533970197228d155dda2bc814ff33ebeb9a7ffd
+
+Count = 137
+Adata = 5692c9d452ea1c067e62fdc554ddd2b18c8433d59067f971316797fd9853ae6a
+Payload = fb529eb5ae79a0830474ffbc98
+CT = c220b2688758e82247201bfdbde7ba03e144e34a4ab34791a372a2b8ab
+
+Count = 138
+Adata = dcf7fe16b7ca9e27ec3291103398eaa2e77c7b770b67f8858c215af4c523822d
+Payload = 6218c778955d9a56360f06c704
+CT = 5b6aeba5bc7cd2f7755be2862103c2eb5ef0657306d12b753a0694efcc
+
+Count = 139
+Adata = b0f1e2668611dca86e8d0f58c2a4cf4a9472d81ba013e271800b75841fe5ffde
+Payload = bf6b143fb713a81c965c5a9d8d
+CT = 861938e29e32e0bdd508bedca87cc6119151393461ecf65bfe06e0163b
+
+[Plen = 14]
+
+Key = a60cf7ceb62bf3118532bc61daa25ce946991047f951b536
+Nonce = 7499494faa44a7576f9ed5580d
+
+Count = 140
+Adata = baa482c64eefd09118549a8968f44cfea7a436913a428e30aa4ab44802a4ba35
+Payload = d64f9426febce6a84c954dd5ded5
+CT = f7580f17266d68237747bf57c7ed8242ac1a1979c5a9e7bc67d7698c7efa
+
+Count = 141
+Adata = 2ad8ecc5ac9437ace079419f17e6018625b10490120fbe2f12b41e64b73b653c
+Payload = fcd9b67717bcadeceddea336c671
+CT = ddce2d46cf6d2367d60c51b4df4918abced491c063d8bfd0e7341febddc3
+
+Count = 142
+Adata = 7585ee95e74d7a869bdc0b59ca9939dd57e7b09afab179079d467bfe0668416c
+Payload = 18232d7c792fb80e6ca1c8f2c3cc
+CT = 3934b64da1fe368557733a70daf4659ecbb3dbfbcdb0f913abedf8afab05
+
+Count = 143
+Adata = 41be6ca6188f34da1ce83fb8c27652848dc2a71e32bd3631fb9b33ae69e5d879
+Payload = 764dbefb42644d18d23e5e456868
+CT = 575a25ca9ab5c393e9ecacc77150a220d5ec0b5397d6b4e323b5dc7d1b63
+
+Count = 144
+Adata = 197cee3b15320d57996191dd13106fbd4546a5cc3d2bcf0c886af52ea3d9a855
+Payload = 8003586af34bdd0acae4f5547394
+CT = a114c35b2b9a5381f13607d66aac3a5f713f5d0793b732c6e114805cc9b3
+
+Count = 145
+Adata = ee0b647a47656a6e9e09c2d64f734a2cc3fd45b7ee52fea51c24af59ee22a006
+Payload = da143266516a4145cde92c93f961
+CT = fb03a95789bbcfcef63bde11e059ed90e8650bc16f590789dcc625b9e63d
+
+Count = 146
+Adata = 9f5bfffa01f1425d95465723735b49fc1dffbad06cf37a00ca4b59efa21739c1
+Payload = 3842b033f3ca31a6f8e5a638b39e
+CT = 19552b022b1bbf2dc33754baaaa6bda183dda1aef021d92210e27cdd7c5e
+
+Count = 147
+Adata = 64e92ba2748d07f602808f7c5ded15cb0e43140400d37107e59a01e7d45b4c9c
+Payload = cedf60b17185fc71b957cb759260
+CT = efc8fb80a95472fa828539f78b585e4087fb314f893937e95383e66745c0
+
+Count = 148
+Adata = 6ebcaeb4bd44ff4c990305ac64264dfe2ada5f7cd4b294eb9f492865cd28905c
+Payload = 035f449bb28f43365f4a0556096a
+CT = 2248dfaa6a5ecdbd6498f7d410520a71ce5813c578532b742d704fa92276
+
+Count = 149
+Adata = db617207dccd1f6baea5f2242d5e577adb8d69af3bb1707a7a53a8b75452455c
+Payload = 9a2a45424f4965a71270e77cc403
+CT = bb3dde739798eb2c29a215fedd3bb7fc45d15d6939668065d2282fc589c7
+
+[Plen = 15]
+
+Key = 82d4bc9aac298b09112073277205e1bf42176d1e6339b76c
+Nonce = 70325ef19e581b743095cd5eb1
+
+Count = 150
+Adata = 6d14bb2635c5d0ae83687f1824279cf141173527e1b32d1baf8a27f7fe34a542
+Payload = 25a53fd3e476dc0860eeeea25fcb0c
+CT = 4a1cfd0023557a184b929965b0a445cb3993ca35acf354cb2b4254ff672e7f
+
+Count = 151
+Adata = 9f8a56fecf32fa7d50f033b2524c3d798e254bc87245cce57e38edd6ee5d5f1a
+Payload = 797dca47597947c057789433309b67
+CT = 16c408949e5ae1d07c04e3f4dff42ea25b5eb103bac224cad66ec0f100875c
+
+Count = 152
+Adata = 86f15b8b677b7655f358a2c7fd5785bc84d31e079ed859b6af88e198debd36fc
+Payload = e61f9a663d3a2b50ea2f9475971270
+CT = 89a658b5fa198d40c153e3b2787d39b598cc6ec2295c586e7ae270a01846d1
+
+Count = 153
+Adata = 4de6bd43c28143ea5d40919cb5330a7e674f5bd8aeb7b178343a2851281c8668
+Payload = df990c42a268950677c433555319b3
+CT = b020ce91654b33165cb84492bc76fa97ff732093f7d0a96b30d8cdfd1bd583
+
+Count = 154
+Adata = a5c3a480dea1b2a1e3a0ce416148b04f60104217c9d24a5b267b4aa6aa07a4dd
+Payload = a7e72fb4bec3768594a2f6f5b4379e
+CT = c85eed6779e0d095bfde81325b58d7ad98e32a9156e125ff021ef6951b0c40
+
+Count = 155
+Adata = 51b041f1666c59045d333fe63d43457107e1adad34fcbf965e0d191f3e414776
+Payload = d3d1550047cf90eceaea7000d8e280
+CT = bc6897d380ec36fcc19607c7378dc9390f10df08a84c21031626861b201fbd
+
+Count = 156
+Adata = 22f8a3c9d85b2d53ffd92078d3c94373f855ecd01a8ac521d1abd0f2c7cba9ff
+Payload = 756412c4ee6416f2f4e0342011cde2
+CT = 1addd0172947b0e2df9c43e7fea2abdd5d840bb8c4348a9a548482e6b93043
+
+Count = 157
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 666e4a4b3f6cf598aa763cdada4109
+CT = 09d78898f84f5388810a4b1d352e403f0d49927cd6103e3705ba201e8f73c6
+
+Count = 158
+Adata = 2db3ded385ef9c82fd39ea5782d9befe66e8a070066269b2aa7c4bbfac3711c3
+Payload = eb9013a74352b0677a88bd73052477
+CT = 8429d1748471167751f4cab4ea4b3e2d97f7c2b3b42bf570cce79bf30ccc50
+
+Count = 159
+Adata = 194c9e1eaa8e376f9c41bf33823efa28ee60a9213438665b7002cf0fcad7e644
+Payload = e3126400e3c571a4d39b37bc938a22
+CT = 8caba6d324e6d7b4f8e7407b7ce56bd3c2a4fc45d014a0c54edab2930a5bdc
+
+[Plen = 16]
+
+Key = 6873f1c6c30975aff6f08470264321130a6e5984ade324e9
+Nonce = 7c4d2f7cec04361f187f0726d5
+
+Count = 160
+Adata = 77743b5d83a00d2c8d5f7e10781531b496e09f3bc9295d7ae9799e64668ef8c5
+Payload = 5051a0b0b6766cd6ea29a672769d40fe
+CT = 0ce5ac8d6b256fb7580bf6acc76426af40bce58fd4cd6548df90a0337c842004
+
+Count = 161
+Adata = e883dd42e9ddf7bc64f460ba019c28597587d06e57c3b7242f84d5e7d124ab81
+Payload = b31dfa833b0cda20eaa84d2ecd18f49a
+CT = efa9f6bee65fd941588a1df07ce192cb8707b1a4d9ce3def33703e19eaab6dda
+
+Count = 162
+Adata = 409401eb49cd96b1aad2525c5124c509766ff86f88b2011c67a1d501d3485e31
+Payload = 24bc8dc1e2354667b79ba4d7061448ff
+CT = 780881fc3f66450605b9f409b7ed2eaefd9041ddce37d88e79fba28e385b2327
+
+Count = 163
+Adata = 83bf5c063bf1febf71688a832d615e09d6f14badedeaeb6ffbfe343fc7274e78
+Payload = d41d95a1d2326e12cba636910ddfca53
+CT = 88a9999c0f616d737984664fbc26ac0291d971893543868bd8c69078fc2bdb24
+
+Count = 164
+Adata = 8cdd70524e24318c64d681aa27752d4c86c5348c05c9e48f06ed41594785a6e6
+Payload = e8a4b80e081919f1912542d3136764f2
+CT = b410b433d54a1a902307120da29e02a3866b23e4c991f4007e56a1ee9265c6cf
+
+Count = 165
+Adata = 615985f63571c0f94ffcd4df77326abd41e84f388f061d97573a181da7ee5695
+Payload = 7fca7388058d6d1438b6eee0292131cb
+CT = 237e7fb5d8de6e758a94be3e98d8579a2abbea637996b954027efa9464ced6b9
+
+Count = 166
+Adata = 17aa90f2bff0419011b01dee62be31354431cbc89f22332704b096143d4743f4
+Payload = aa540554ee80dbffa475f702d862d6b6
+CT = f6e0096933d3d89e1657a7dc699bb0e757bc8d48d82ebefc76f17323c518ecc2
+
+Count = 167
+Adata = 85288b2be612e42335c144fb058a7dcd567c382fbcee3962bd5be4cc7a7000a8
+Payload = 6d745581831edba437e70ea89cad217d
+CT = 31c059bc5e4dd8c585c55e762d54472c65470c81e487a26cdc26830f2b51bd1c
+
+Count = 168
+Adata = 288f9f52824b54b608dd7226a0a89d43ae8c05107dbae761e1c756911a003b74
+Payload = 811a61869c7a6b2aa9ac0fcc523ef784
+CT = ddae6dbb4129684b1b8e5f12e3c791d5a3043722be9448c3ef144f2288066f75
+
+Count = 169
+Adata = 51dbaba180d4746edbb3420461919b5b735797bf7dd19f84d80475f5efc2748d
+Payload = 378a4e39817f308ed1e639f943b694c4
+CT = 6b3e42045c2c33ef63c46927f24ff29549aba95e04e11cf18ddf73773d395c1a
+
+[Plen = 17]
+
+Key = 3cf8da27d5be1af024158985f725fd7a6242cbe0041f2c17
+Nonce = 07f77f114d7264a122a7e9db4f
+
+Count = 170
+Adata = 30457e99616f0247f1339b101974ea231904d0ef7bd0d5ee9b57c6c16761a282
+Payload = f6dd2c64bf597e63263ccae1c54e0805fe
+CT = ce3031c3a70600e9340b2ddfe56aa72cffdc5e53e68c51ee55b276eb3f85d2cf63
+
+Count = 171
+Adata = 42370f115bbd4b31bb99fe82cca273b3c93072f96b2e09bdc6718d926d48db69
+Payload = f45fee3e086c28a7c590ec0cc05b972664
+CT = ccb2f3991033562dd7a70b32e07f380f65c6328a7476db2c10ec7bca3f6bd3df42
+
+Count = 172
+Adata = e2d692c5678124998a7862b8e87276b0a19e293a609103c99583b36305bcb2b0
+Payload = 4ad69a8ab433ed8909825c71f6081f64a7
+CT = 723b872dac6c93031bb5bb4fd62cb04da68080f0d51d3b8841683eff361984f7e4
+
+Count = 173
+Adata = b5b38791160959dd2836ec1ad25286c1ba410d7212347a95b5738a3d725bb651
+Payload = 3d47071c13f994cb42fb2887e5c6e53a54
+CT = 05aa1abb0ba6ea4150cccfb9c5e24a1355c1428ef5d40bc9e363817f219af2ed56
+
+Count = 174
+Adata = 02691171795a77d1e3bdad513b6fab5b50d1def81bcc1df15012de3433a6aa78
+Payload = e8a4b80e081919f1912542d3136764f264
+CT = d049a5a91046677b8312a5ed3343cbdb65fdfb37dfd1236198035c8461b304152b
+
+Count = 175
+Adata = 7371d8ae79e628f53ffede174eb068db2318c05e2f6d94ad2233a59369b16db0
+Payload = 549aa84bb182312dd016e3107f3b1f9c5b
+CT = 6c77b5eca9dd4fa7c221042e5f1fb0b55acefde0e84a3ce0cb702ceb73ca1dd9a5
+
+Count = 176
+Adata = bb1e1f51082e470f7245458ec902098e1e41d0ed28efa31be71d21ce86527ff7
+Payload = 31a12ca6d69db2e6e252474d7d59ed6552
+CT = 094c3101cec2cc6cf065a0735d7d424c53f8441d46dc5456a587b765e1a820c11c
+
+Count = 177
+Adata = 7584f57b49e95bbf5a67153e18b9b8c4722644e8f611613c39cbe8c679aba5b4
+Payload = 5bb121e70452a954f420a56aca8cd5c059
+CT = 635c3c401c0dd7dee6174254eaa87ae958d0daddcfcc92349ef059149c54a25cd0
+
+Count = 178
+Adata = 505687182c06e6f4effe7fe03c1f436199a9015380ff21d0b2aa9453cfa10b1d
+Payload = 5b80d1cf745b14cb71cbc8dfe0bc7c7358
+CT = 636dcc686c046a4163fc2fe1c098d35a5948c1242b89490c6ee69dedc1e91286ee
+
+Count = 179
+Adata = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee451bd1429cbb33fc1
+Payload = 79ac204a26b9fee1132370c20f8c5bcada
+CT = 41413ded3ee6806b011497fc2fa8f4e3dba2ddd54e509bca0a45dcf2fd514e1496
+
+[Plen = 18]
+
+Key = b46a3a24c66eb846ca6413c001153dc6998970c12e7acd5a
+Nonce = b79c33c96a0a90030694163e2a
+
+Count = 180
+Adata = ea9405d6a46cac9783a7b48ac2e25cc9a3a519c4658b2a8770a37240d41587fb
+Payload = 56d18d3e2e496440d0a5c9e1bcb464faf5bc
+CT = 01baba2e0d5b49d600d03a7ed84ee878926c0ca478f40a6fbde01f584d938a1c91bf
+
+Count = 181
+Adata = 72340d595f3dbd23b46513f8f2b73b6249328c705e7968084bcb647fe734a967
+Payload = 7a76eac44486afdb112fc4aab939e4d1eedb
+CT = 2d1dddd46794824dc15a3735ddc36853890be4646492b6f4cb169383c075756073b6
+
+Count = 182
+Adata = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e06bb90e07460172e
+Payload = 48348c5ec996f7a97ef0ba2cd6885572fe64
+CT = 1f5fbb4eea84da3fae8549b3b272d9f099b4f584289f560cbf76606942fe1a92dd63
+
+Count = 183
+Adata = ffa6277395d31d5db13034d362228a87610e441c98ca3038e252a9db12bdbcef
+Payload = d5c58f10e1a03d8a2501d1eaf5fcdfff3ae5
+CT = 82aeb800c2b2101cf57422759106537d5d355964f5f5532d7cddd7207f0e9a6aace9
+
+Count = 184
+Adata = daf83d02a9bd992ea58c23e7ad18d41796314bae20e864e729f40ccc215454fc
+Payload = da2a863ab1c58ddde320ecadeecac9c5d2d8
+CT = 8d41b12a92d7a04b33551f328a304547b50890ae047e35aecfc38ffdc07e7d8f5705
+
+Count = 185
+Adata = 21ddad5f550044dc5cb123ade17eeef549c4e0173b216bcc602c1e736764cca8
+Payload = 4573969afa831c244817230406fe51183091
+CT = 1218a18ad99131b29862d09b6204dd9a5741b2bdf539ceaa35015712dd15265ca476
+
+Count = 186
+Adata = 9228265ae5c3daf1485ff8011738da508bf2a73731396c5d9aa56fc554e0c00b
+Payload = edf5557e15473b747a819398c9ac1459ffdb
+CT = ba9e626e365516e2aaf46007ad5698db980b241412124ae20b84c13b0c3671d305c9
+
+Count = 187
+Adata = c0a2ff0de21b3ba961e06015ccd71374856a65a4c57cf8cde0a1643aca8ed868
+Payload = e139263478900df806a0f3446bd6600c1aeb
+CT = b65211245b82206ed6d500db0f2cec8e7d3bee9803747bf9fa63412bfc4e10aea89e
+
+Count = 188
+Adata = b54378f031a31cf3985f573829c9ffca14616742e0a7e03b0a2d7f05eff0219e
+Payload = 660eaff0f113eaa2f5f7ad4b62bb849a3a25
+CT = 316598e0d201c73425825ed4064108185df55afdf430b57845dcf622d4f25cdeb2a3
+
+Count = 189
+Adata = e67f35c18a9336469eae23040f98f52338ca8d0cab269ac32fe6bc7605d3ea56
+Payload = 0f89897271f5d0349d57399005ea60c0cadc
+CT = 58e2be6252e7fda24d22ca0f6110ec42ad0c7ed4c04c4b4dd585891ecfddeab8cc87
+
+[Plen = 19]
+
+Key = 7b71045ccef735bd0c5bea3cf3b7e16e58d9c62061a204e0
+Nonce = 2b9ecfd179242c295fe6c6fa55
+
+Count = 190
+Adata = b89166f97deb9cc7fdeb63639eeafb145895b307749ec1a293b27115f3aa8232
+Payload = 890d05420d57e3b3d8dbef117fe60c3fa6a095
+CT = f842ff6662684de8785af275fa2d82d587de0687ebe35e883cbd53b82f2a4624c03894
+
+Count = 191
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a49569a5b27b
+Payload = 6b425cdcdf8304e7fbb70b2973d55e6940025b
+CT = 1a0da6f8b0bcaabc5b36164df61ed083617cc807d4824f0a98db2d87365a42ca3b80e1
+
+Count = 192
+Adata = 9b4fc98fcdcf485205e7054bc9d1e02d0d8584420537e20d3821de2fd6824787
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2
+CT = b9f0ee7ba0c4018d6d9b513fe92670eaabd221404e631735c544edeeb4c0105c55bf0b
+
+Count = 193
+Adata = 45622e1472542be2f63f463d253617eafd4f2ad609f9020884905dd5c22fba53
+Payload = 12b5a76faedf6f855e328c2cb87be8aea78c5e
+CT = 63fa5d4bc1e0c1defeb391483db0664486f2cdc16a4cf37e8e96eed1217d21133e83d1
+
+Count = 194
+Adata = 958689aea3c6cd19020eff9d635ef44ee0793424df38fdf13a238b969d429777
+Payload = f0927c3cb0a876d7877466507da8bfa0bd9a16
+CT = 81dd8618df97d88c27f57b34f863314a9ce4859facf81a636351f6e67d6ec12636ae0b
+
+Count = 195
+Adata = c22911efc36fa739048af0c951ef2449bb3605c52f65120c4d71fe5976026032
+Payload = d2c5d4e2362f19c99de66da7bd9c495c03d9a1
+CT = a38a2ec65910b7923d6770c33857c7b622a7327ce73a7e2db69d30441f89a03fd0e84e
+
+Count = 196
+Adata = 799da61e2c10ebb4783f618b8f69da7704a1b2b925cebc228af57d7ceebb9825
+Payload = 1c9d7f5b329ef4d384b8b7955a20f8a3fc15cd
+CT = 6dd2857f5da15a882439aaf1dfeb7649dd6b5e8d787a9d06b8533ca96fb1db8aecc8e5
+
+Count = 197
+Adata = 14a8e18afe0b9fe18ddfd754219a7e18ed36f419f8262d91678e10daffb31c81
+Payload = 3a64414c3588d7c26871d7d054ac6c8420d491
+CT = 4b2bbb685ab77999c8f0cab4d167e26e01aa028ff5f819d552c08054b5ac02063e102a
+
+Count = 198
+Adata = 7294a8b4ad97c81969e4a2876a3dc0ee322d554726997dc9ed98c5601985ee5b
+Payload = 545dd71bea9967e07a89f84a2027aacd132187
+CT = 25122d3f85a6c9bbda08e52ea5ec2427325f141cde5af8fada67c47cbb5787a6b2d9c9
+
+Count = 199
+Adata = 99294b22d73805805630fb416d20d4fca67419ab660ff45cd19a3729e81b9f69
+Payload = ec1b17b885c018272652453f47fa6e9ed972b9
+CT = 9d54ed9ceaffb67c86d3585bc231e074f80c2a7412640b179bd3e8a417dc38462c16e8
+
+[Plen = 20]
+
+Key = dc7c67715f2709e150cceff020aaacf88a1e7568191acbcf
+Nonce = da56ea046990c70fa216e5e6c4
+
+Count = 200
+Adata = f799818d91be7bab555a2e39f1f45810a94d07179f94fe1151d95ab963c47611
+Payload = f383bd3e6270876b74abbb5d35e7d4f11d83412c
+CT = 377b5df263c5c74f63603692cbb61ea37b6d686c743f71e15490ca41d245768988719ede
+
+Count = 201
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d27ad5132d507504898f61e
+CT = a5a59286e8ff1d8b9aec209ecc84cd022e76df5ea9bc8cfaf2a1734a792076618c4b9690
+
+Count = 202
+Adata = 4586f73a1f162b2cdb65f6e798a60b5f48938d40b4612d84c1f39244f14efdce
+Payload = 6e923e1f404002aa5cf8f8aaf1b9772da425e21c
+CT = aa6aded341f5428e4b3375650fe8bd7fc2cbcb5cc5122df904b052e4d5580fdeddf5297c
+
+Count = 203
+Adata = 9f7ae892e5662803408d4d062265846441a43c1fa202da59f640ae722a692671
+Payload = 68115771505daa18bb3ce90054bfb7d077e1f37c
+CT = ace9b7bd51e8ea3cacf764cfaaee7d82110fda3ce0ba1bb1af18e15ade3316c21d6b41fb
+
+Count = 204
+Adata = 1f0769a7ae82bd985661e031c4a892c15d3ef37bdcfb45243d02f40fdb51d34b
+Payload = 681fd2a324b3fea4cfebed567ae4546ba373c8f1
+CT = ace7326f2506be80d820609984b59e39c59de1b1dc71e342fbc44289ef7e53e28edf3839
+
+Count = 205
+Adata = bf957ef5ab2805e58ea752da5793f7f23d98fce1b2b67738929e5de8a15f9801
+Payload = a7b9d2d069941e8b943706a02d2847ea713bb103
+CT = 6341321c68215eaf83fc8b6fd3798db817d59843ced1fb4a2a3e349aa590aabbfc3d13bc
+
+Count = 206
+Adata = 833264c1bebb597043b4158087cb651960915d9023189c9509c0d2aed84e7fe4
+Payload = 9b946e8198ce69d2173e970f4e0c103a47ee4160
+CT = 5f6c8e4d997b29f600f51ac0b05dda68210068205079f6c2739e2b789b6e3d3c60389374
+
+Count = 207
+Adata = 94c8414cbbec52e2d73bb8f02ef687c91432495c0c744666317d02e6d46706d2
+Payload = 81ac4618f3db6bcf9bbf67220b7671be4bb4f8a2
+CT = 4554a6d4f26e2beb8c74eaedf527bbec2d5ad1e22a02f287db7217148317d897f65f6a0c
+
+Count = 208
+Adata = fced1131dab3dabdc1a16d3409fa09a90ffe02f0e2c814a63f77f771c08c3389
+Payload = 90851933d4d3257137984cdb9cba2ca737322dac
+CT = 547df9ffd56665552053c11462ebe6f551dc04ec362df9f8b41b1dd4821f8f14e9e633d7
+
+Count = 209
+Adata = 495dfcf91f4735ab35c6bc4deef8468bd988e4099cd291a32b4707f93e13d82b
+Payload = c14ce6d57f0fe7367331c9fe159ae1fb8f1ccb2c
+CT = 05b406197ebaa71264fa4431ebcb2ba9e9f2e26cf61ffb51e56497ca9f39c6665fcbdfa8
+
+[Plen = 21]
+
+Key = f41e369a1599627e76983e9a4fc2e963dab4960b09ebe390
+Nonce = 68ef8285b90f28bcd3cb1bacea
+
+Count = 210
+Adata = dbe3e82e49624d968f5463ceb8af189fb3ad8b3b4122142b110d848a286dae71
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326
+CT = 9f6028153e06d14d30b862a99a35413413c04a49dc6f68a03a11cf00d58f062a7b36465d13
+
+Count = 211
+Adata = d9acfd611e5bbb08c5d05d56791b8aebabf8d69734ec89153c91a1f65b2e1adb
+Payload = 35f6bb3f6a388f3a5a039b0a495b676d0b928aeb19
+CT = 2b3bac123fd395813c44aaffb0362b469fb10781e3ca1fb470b666523a19f83481f16481ed
+
+Count = 212
+Adata = 6003b771afe4e99e1ef1ed4a31b10540d95f4ac49885f0c8e5cdcb63d213127e
+Payload = 6aa7e3802b5a29d4f9ca88eb59f94af783d1054466
+CT = 746af4ad7eb1336f9f8db91ea09406dc17f2882e9c53cb05bfcd64da2b45c2e9a89a380b49
+
+Count = 213
+Adata = c371644275a6290821e7d308714bec2bf62d36c30f7fa77a0d60b28894f1c82a
+Payload = 13332b67ba5ba18137c306bd860dc3eb0a9a0b871a
+CT = 0dfe3c4aefb0bb3a518437487f608fc09eb986ede048f70fbc680cf7092b3dd90b943fc6e5
+
+Count = 214
+Adata = 8eceb15300ec4220510ed5b7deb3429de6ae5f618e1c222c28990a9ab4b4bac8
+Payload = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4
+CT = 1b550aef3ff6a8638484e9ab50c99df7a01154873ee386f33c0b8da8d0c5934e617dd618e5
+
+Count = 215
+Adata = 96d1cf3690c48c77a155ce13e67bbd62e6f03d88c893c1f7c30a6435d5ab36e0
+Payload = 60249343a8cd4d33c6edc583ea7e5c221ef3064787
+CT = 7ee9846efd265788a0aaf476131310098ad08b2d7d3d2db1360fb1121893f4d197731bce4f
+
+Count = 216
+Adata = 379bbc9f919dc2a8687f2a86cc9c3291804240a9b566c58519956848102e6155
+Payload = 79003a8d3d20d412f468f11712cec4d37cee847440
+CT = 67cd2da068cbcea9922fc0e2eba388f8e8cd091eba335ce1bfafc0948f2523e75f2aad86f9
+
+Count = 217
+Adata = 9bff9c9a8f94cd77e7016748da31f86d1b9c68465cbf954511c93a4776981524
+Payload = 7d078a8b200514a00628756250d410f7a0f8a769e6
+CT = 63ca9da675ee0e1b606f4497a9b95cdc34db2a031c7dc265e281307f0f4c38cddc556ac725
+
+Count = 218
+Adata = 25125a4668c31dc2e8a68b6c4c95ad7cf9322852e371b415a357d09acb01b587
+Payload = d9b0eaaff786165f882f41a98dbc0c355b3a1aaf40
+CT = c77dfd82a26d0ce4ee68705c74d1401ecf1997c5ba61c78a2f85a447c3e62b6197d65b9065
+
+Count = 219
+Adata = ad34d8f0902a5b79fb145b8206bb4d3b77e0bd8ae2d0964815389eacb33b4007
+Payload = 17b517ef577f588da374340d2522cc9ea642c8d8ae
+CT = 097800c202944236c53305f8dc4f80b5326145b2540312d067c08a9b4400e1df8bb7ed671a
+
+[Plen = 22]
+
+Key = 3289e59e3a7b29bf4a309afc253030bba4b9bdd64f0722f9
+Nonce = 30259ce106e9bd7a8bacbaf212
+
+Count = 220
+Adata = 2870bd9a26c510e9a256920899bbc77a4eb9b53f927045a943d5ed6b13638cf3
+Payload = 53911a67b65738f87fc7c20d6db8044bde1af95838d1
+CT = 70cf37d4b6f7e707376b1574ce17c040b5143da47abb2fe9afafc2fccd98ccf63b0fdec30eac
+
+Count = 221
+Adata = 611032a95ee87f89ad6be7c0fed8bd245c5f81076087b3bda4cde5587b8d14b6
+Payload = 46917e38b8a542296d290d065b0aa7c8aaa38950c386
+CT = 65cf538bb8059dd62585da7ff8a563c3c1ad4dac81ec102dfd8c231d6a355f079c213ce6858e
+
+Count = 222
+Adata = 2e7ea26d1cceaca3b7862a7a8469e366b52ec27ca127e3317222ee651d8da4a0
+Payload = b527828c89f674dc6f024f8cdd80c694bb3ebd57b2d9
+CT = 9679af3f8956ab2327ae98f57e2f029fd03079abf0b36df11febe34dd568da12c374674b9ac4
+
+Count = 223
+Adata = 0bf4413010daec585de34142224d1cad3072f9720f91ac664ad152820e838741
+Payload = 78230f73f9c0150f630eca4cd679818551d449db82e6
+CT = 5b7d22c0f960caf02ba21d3575d6458e3ada8d27c08cb2916540d9439b832aa44236a7e187ac
+
+Count = 224
+Adata = 2e7cae3306582eb5bad148247aa6c6ec943f8748e84b8a069ca9488b11844716
+Payload = 847bb12e0e56fa07a086eeda5907ae148148fa4107d2
+CT = a7259c9d0ef625f8e82a39a3faa86a1fea463ebd45b80d0768a18dead55700901408aa3f901a
+
+Count = 225
+Adata = 63036dc4ad13aee5dc1832e867f7538da108188fec7b08262af440d07579c451
+Payload = ec59e208c4bb429a371f1b3ffdf07fce5dea8a05f0ce
+CT = cf07cfbbc41b9d657fb3cc465e5fbbc536e44ef9b2a45f2073605d2a441805b6ff89d8beb68c
+
+Count = 226
+Adata = f9ec5ce4b63156d57e451eb67ab6d7a59cc397f43f6d26dc07d1036f0fb4a8cf
+Payload = fb12d94bd21b5748b23132a03065c78dae65a0bd2cfb
+CT = d84cf4f8d2bb88b7fa9de5d993ca0386c56b64416e91dcabef6907811c6b7df4e74c7a63d83b
+
+Count = 227
+Adata = e13a204e16f42bbf4716e95f1cb7e125ffac66a87f591c8ef2c7b8485ff707fd
+Payload = 239fa31d4a65de0318bfc5b60a06d706c129dcf255ac
+CT = 00c18eae4ac501fc501312cfa9a9130daa27180e17c626aa8aa37e858cd990f5593d9ef35f2a
+
+Count = 228
+Adata = c4591c3ad984a1e189c526b719212f8248289eeb277827272b8205d78191eb2d
+Payload = 57caadbb1a56cc5b8a5cf9584552e17e7af9542ba13e
+CT = 749480081af613a4c2f02e21e6fd257511f790d7e354d81e424d6b4528901ae46fb35f8b3106
+
+Count = 229
+Adata = cf4795bc7f43c30d3c3a8fd1b8a9d77d69bf59eb8b59d0f464315f40cb52335d
+Payload = a68c74e05f0a44d4a0372c0e5915b83d8e6729efacbb
+CT = 85d259535faa9b2be89bfb77faba7c36e569ed13eed1f25a4bfda35e1390f3f16f638dcd4047
+
+[Plen = 23]
+
+Key = 40f1aff2e44d05f12126097a0f07ac0359ba1a609356a4e6
+Nonce = 0df3fc6396f851785fca9aa5ff
+
+Count = 230
+Adata = e9699b20b0574fce8b5cbc4ef792eb96e2c1cce36b1b1f06ea2a95fe300633cc
+Payload = 8d98c580fb366f330dbfda20f91d99a0878b47efd14c6d
+CT = 579cdf9da62a2df471e03450516adb4ce99ae0f70b1776a39c3b429a1f922fac0b59e29a122e43
+
+Count = 231
+Adata = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402677aeb51e216335f
+Payload = 7391ba60fabe2c632bbaca16af9a235b2c7dae61691c0b
+CT = a995a07da7a26ea457e5246607ed61b7426c0979b3471067bf538e40f9366adf8758968f06ce8a
+
+Count = 232
+Adata = 4f263cda4a50b0e5379ec2fb546b326a07943527c1d175c029455a917753883b
+Payload = 7e1e93a6ca35a2c0e4f08fdb2e7ee22b9f486f0ab919e2
+CT = a41a89bb9729e00798af61ab8609a0c7f159c8126342f964a1199251b54f419720a30de83161de
+
+Count = 233
+Adata = 4d43702be4f0530319555d7f1a3356160f6cae48051f12e22a153d7e405c1149
+Payload = f94ff053c7413f34f96eae41fd1ac101151069af5a9428
+CT = 234bea4e9a5d7df385314031556d83ed7b01ceb780cf33b417e4cceb8dcf45ef33cc0007755bbc
+
+Count = 234
+Adata = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259e319266042db8887
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c566990
+CT = 60030c2802e3fa28e822c465432f75b671e0af548c328bd35aed57f49dcfecf248cf9d246ac024
+
+Count = 235
+Adata = 12e4fe727b1f27a619dd67bb976ddc2b18b2ef8b7184290d9553494a500d933e
+Payload = 872940780a94680a791c937994ceafd2c8b7a22b5f4927
+CT = 5d2d5a6557882acd05437d093cb9ed3ea6a6053385123c97cda0e04d2ff65c2e06a8276bdf6f97
+
+Count = 236
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830
+CT = 0d1c7e9a22393a1c757245d27ed6bb18079b3b2db6232b3494dd2ee0a0fe5bfc9f69234c8142ed
+
+Count = 237
+Adata = cefc4f2fb796c2502329ca3d8f8af3200dd9edb8f164e15acec90536a15b6fdc
+Payload = cda681aa3109ebf5f21ee3a849098ea3a551e844fae4b4
+CT = 17a29bb76c15a9328e410dd8e17ecc4fcb404f5c20bfaf9008ead8e923997508eebf5e776198dc
+
+Count = 238
+Adata = 94fc7eb8febb832097ba6eecd2697da91b5a8a1f2248f67a7659e0ac55a09a0d
+Payload = d4f8d262870b5000a40b8fcce88f55c65c4d12e729975e
+CT = 0efcc87fda1712c7d85461bc40f8172a325cb5fff3cc45f136cc6ea1b0fdb554e0803053875b89
+
+Count = 239
+Adata = 459085184094e302b2e921cc04270b676e75bbcf0e4b53ed387df2bd0e75e0ac
+Payload = 732f211061c0a32c6ad124c58418d560ef5eab2602314c
+CT = a92b3b0d3cdce1eb168ecab52c6f978c814f0c3ed86a575da8ceccae093888daaf92c95817fc3d
+
+[Plen = 24]
+
+Key = 91f9d636a071c3aad1743137e0644a73de9e47bd76acd919
+Nonce = 1bf491ac320d660eb2dd45c6c3
+
+Count = 240
+Adata = 3bdfd7f18d2b6d0804d779f0679aaa2d7d32978c2df8015ae4b758d337be81dd
+Payload = 4eaf9384cad976f65f98042d561d760b5a787330dc658f6c
+CT = 635530cab14e3d0a135bb6eebb5829412676e6dd4995f99cb7e17f235bd660e7e17b2c65320e9fd4
+
+Count = 241
+Adata = 9de45b7e30bb67e88735b8fb7729d6f3de46c78921b228bad8f17cc9c709c387
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 7444449ff443f1ab73fdfda2ea2a04d5163a1209e868b1d99f40890c7d650afccda40fb2a4cd603b
+
+Count = 242
+Adata = 783477f981ef0551b5e7a714b640bbb38316c53756c96e30c898cdee3b72e6f4
+Payload = 4e7f3c86d846ff351db81dbe1d2e9ed73ec0450587ae681b
+CT = 63859fc8a3d1b4c9517baf7df06bc19d42ced0e8125e1eeb50236cf1a12a9e3542a4051788f9775a
+
+Count = 243
+Adata = 2851d40243512a43f70f9c25e9b18c122a1433f05c61e65017e197e88b129e43
+Payload = 2db7cb2739c839383b64c2c93c7d5c906d984756c3dedaa9
+CT = 004d6869425f72c477a7700ad13803da1196d2bb562eac59b1bbad9861192df356c6678b2f561ea3
+
+Count = 244
+Adata = 1cfa2d62cc1f6313fb0c6eb21803e09cdf61ee3ddb15192529560e5d8096cafb
+Payload = 2f2b82497c78369890809460d80a16be4f3330e8a0089165
+CT = 02d1210707ef7d64dc4326a3354f49f4333da50535f8e7951da4211d4c28d2d91568117fc99fd911
+
+Count = 245
+Adata = 5a14b556156191b2704936f64df0bf1dd2bd8d587418f4f85472338fcf86aa52
+Payload = 7cfefca725da1b6bb5d9545e3e50f5a624a8160bdb0e7d4e
+CT = 51045fe95e4d5097f91ae69dd315aaec58a683e64efe0bbeda99be0e054bb881a25a74b547d3ed5e
+
+Count = 246
+Adata = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c680d71fd1f9801fa
+Payload = 5205165c4e9612974dc92f60d1e328d68aa9466e27dbd499
+CT = 7fffb5123501596b010a9da33ca6779cf6a7d383b22ba2694c1fedb47fa30ff2ead6bf382431b2de
+
+Count = 247
+Adata = f852e38703097cc37c589b7860dbc333e091411462d5576dc9909a8cf6ac99d4
+Payload = f968f2833427abbc9fe1cab7e7a3f905a3b23a35802029ff
+CT = d49251cd4fb0e040d32278740ae6a64fdfbcafd815d05f0f338762a4e4299615c67130a28b56a383
+
+Count = 248
+Adata = 43df03a0e23c7ad0d13485150ca224c0b3f39d4e5f2d718db6308e003d3dc683
+Payload = 67da6ca42655188af0b8e389152b2a1b6e2c3ed88926afa5
+CT = 4a20cfea5dc25376bc7b514af86e75511222ab351cd6d9559dbdf61387294812f483aad76d48d899
+
+Count = 249
+Adata = b297dce04ada2ddebc7e94eff7c51b87eee2f98c410c5c0919d0652653ab7458
+Payload = 9777cf90dd7c7e863506686fc3ba6d3d05328f78b350f92f
+CT = ba8d6cdea6eb357a79c5daac2eff3277793c1a9526a08fdf078177541e19b11dfec995f40c99af70
diff --git a/lib/crypto/test/crypto_SUITE_data/VPT256.rsp b/lib/crypto/test/crypto_SUITE_data/VPT256.rsp
new file mode 100644
index 0000000000..e9cd7eefe9
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/VPT256.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476
+Nonce = 291e91b19de518cd7806de44f6
+
+Count = 0
+Adata = b4f8326944a45d95f91887c2a6ac36b60eea5edef84c1c358146a666b6878335
+Payload = 00
+CT = ca482c674b599046cc7d7ee0d00eec1e
+
+Count = 1
+Adata = 36c17fd901169e5b144fdb2c4bea8cd65ad8acf7b4d3dd39acf2ad83da7b1971
+Payload = 00
+CT = 67747defe5da5fecc00b9bf3b249f434
+
+Count = 2
+Adata = 9a37c654ab8e5a0c6bdfff9793457197d206ed207d768cbc8318cfb39f077b89
+Payload = 00
+CT = c57ef5d0faf49149c311707493a4cfd4
+
+Count = 3
+Adata = 5ab80169184541393a6975f442ee583cd432d71a6d1568fa51159df7c5b8f959
+Payload = 00
+CT = bc2fb5571a7563bb90689a229d2f63a7
+
+Count = 4
+Adata = c78a22a667aafab0c94047e03837d51b11490693d5c57ea27b901ff80b6a38f9
+Payload = 00
+CT = 428888c6420c56806f465b415a66e65a
+
+Count = 5
+Adata = e11e30cbf63623816379f578788b0c8e6b59ee3c9c50aa6e1dcd749172d48fed
+Payload = 00
+CT = 9f1b7520025e1075731adc946b80121d
+
+Count = 6
+Adata = 05716168829276ff7ab23b7dd373db361e6d9e1f11d0028d374a0d3fe62be19f
+Payload = 00
+CT = bd36b053b6a90f19e3b6622cba93105d
+
+Count = 7
+Adata = 3e915389639435629fcc01e1b7022d3574e2848e9151261ad801d03387425dd7
+Payload = 00
+CT = 458595a3413b965b189de46703760aa0
+
+Count = 8
+Adata = 2f496be73a9a5d9db5927e622e166c6ec946150687b21c51c8ca7e680f9775ac
+Payload = 00
+CT = 8b259b84a6ee5669e175affca8ba3b1a
+
+Count = 9
+Adata = 0a8725bd8c8eab9ed52ca47835837b9f00a6c8d834ab17105b01eb4eb30402e7
+Payload = 00
+CT = c5f35fdf2b63e77a18d154f0ddcfedbf
+
+[Plen = 1]
+
+Key = cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14
+Nonce = 6df8c5c28d1728975a0b766cd7
+
+Count = 10
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a
+CT = a5f24e87a11a95374d4c190945bf08ef2f
+
+Count = 11
+Adata = f6cfb81373f1cbb0574dda514747d0099635b48cb809c6f1fa30cbb671baa505
+Payload = 40
+CT = ffd43c5f39be92778fdce3c832d2d3a019
+
+Count = 12
+Adata = 5a88b14bada16b513d4aa349b11ce4a77d4cda6f6322ff4939ad77d8ecb63748
+Payload = 41
+CT = fe753b7b661f1aad57c24c889b1c4fe513
+
+Count = 13
+Adata = a92b95b997cf9efded9ff5e1bff2e49d32e65f6283552ded4b05485b011f853f
+Payload = 06
+CT = b91c5ac66e89bf2769ef5f38a3f1738b24
+
+Count = 14
+Adata = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd24aab5f2bbe112436
+Payload = c8
+CT = 773fe64379cea1a8ae3627418dd3e489a2
+
+Count = 15
+Adata = d3029f384fd7859c287e38c61a9475d5ddbfd64af93746b1dc86b8842a8c194c
+Payload = e2
+CT = 5dabc529442ff93005551b7689bcb748f7
+
+Count = 16
+Adata = 51ca3d3b70b5e354451a5177d7acfd8e7b44eae55e29d88b5e8eb8fc1e5c62fc
+Payload = 1a
+CT = a5ee68e416617ac974b3d1af7320cd51f6
+
+Count = 17
+Adata = 8c6c6791f1ac957b18bf008e260a0af4a5b7bfdb1e0008d6eaaa227f45cf4f62
+Payload = dd
+CT = 6243883d93d7066991e0fac453400b4fbf
+
+Count = 18
+Adata = b0a1af969a95025385b251afd1e89f353426ed6e5d71019cd73366aa31d5b464
+Payload = 4c
+CT = f3b940d416f3435812f9d1b18f441b7721
+
+Count = 19
+Adata = 7e72b2ca698a18cb0bf625f5daddb0d40643009db938340a9e4fe164a052fee1
+Payload = 88
+CT = 371d27e9a32feea28a6a7e7da2d27e1cc4
+
+[Plen = 2]
+
+Key = 36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510
+Nonce = 021bd8b551947be4c18cf1a455
+
+Count = 20
+Adata = b5c6e8313b9c68e6bb84bffd65fa4108d243f580eab99bb80563ed1050c8266b
+Payload = be80
+CT = ecacc3152e43d9efea26e16c1d1793e2a8c4
+
+Count = 21
+Adata = 38e5032c5949c2668191ef1af5bb17eddc28abdb4e5bb41eaffec2523b2525d6
+Payload = 82c9
+CT = d0e5d06bf4b50ccce0b2acfd16ce90a8854d
+
+Count = 22
+Adata = 0b50f5173249fb7118f80d25874d6745d88e4ce265fa0dd141ad67ae26c31122
+Payload = 8239
+CT = d0158d784f486c1dc4a2bafd5b02ca1e1c05
+
+Count = 23
+Adata = 0296743a3125b103a2b2a78a109e825ea10834bd684215ab2e85cc4172e37348
+Payload = 16c1
+CT = 44eda3377002a48f9fe306d157358e6df37d
+
+Count = 24
+Adata = a94e64becb803e211785ba51db7f3db042fbf44a7a821509156a6828b0f207e9
+Payload = 2801
+CT = 7a2df6c09bf1dcb1c82bd98c6e2c13a8d7a5
+
+Count = 25
+Adata = 105358cc17b12107e023a23d57b44c66a2c58d8db05100311575e1ea152fc350
+Payload = 65e7
+CT = 37cb2ea363c0d8864363056467570959ba03
+
+Count = 26
+Adata = 669f9a63cf638a202dca1965c4116273249813ce0b39703887d89bdf5b3b12d6
+Payload = 819d
+CT = d3b16519377e6d0252b5f80cdf3d0253eccf
+
+Count = 27
+Adata = e288590a3eba28ac6847a50b0294ab6bd0a548716ff5102c44a5b656b2d9ddd6
+Payload = 761e
+CT = 24329a4dee6ca2cde473f08f76f779856c3c
+
+Count = 28
+Adata = 5b222aae3c7786c3b9021ba672f9136190ec931cf055f84c85706127f74c6d5b
+Payload = 56de
+CT = 04f29e65c0f01e644e74092253b470cd5511
+
+Count = 29
+Adata = 2082f96c7e36b204ad076d8b2f796cccf5cbc80b8384b53a504e07706b07f596
+Payload = b275
+CT = e059809fa107f379957b52ac29fe0bc8a1e2
+
+[Plen = 3]
+
+Key = ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944
+Nonce = 0bddf342121b82f906368b0d7b
+
+Count = 30
+Adata = 887486fff7922768186363ef17eb78e5cf2fab8f47a4eb327de8b16d63b02acb
+Payload = db457c
+CT = 54473c3f65d6be431e79700378049ac06f2599
+
+Count = 31
+Adata = 0683c20e82d3c66787cb047f0b1eb1c58cdde9fb99ee4e4494bbf27eb62777d1
+Payload = 62a6c5
+CT = eda4853b186edc15c22ba24e470eb5a072da9f
+
+Count = 32
+Adata = 413074619b598f8bed34cab51ddf59941861ba0169ebe7570a5ed01d790c08e5
+Payload = cc67bc
+CT = 4365fc52a1fb5a58bd51931230c1a7dfb1a8c1
+
+Count = 33
+Adata = 2d65a5175c29a095dc082dab9cfcf4b895efbfa715c57614589d4db159543ce9
+Payload = 33800b
+CT = bc824b7d3810f59176cb108c7e969da51d4d79
+
+Count = 34
+Adata = 6a831b6059456be98e6fce608d8c71cb8efb04a96b45c2dfbdaeabf5420a1482
+Payload = b2c826
+CT = 3dca6646ffea832595c9c86e6517215541ddbd
+
+Count = 35
+Adata = 3a04a01160402bf36f33337c340883597207972728c5014213980cd7744e9e41
+Payload = d7e620
+CT = 58e460e89a6725f0fc35622d89d2f3e34be90a
+
+Count = 36
+Adata = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f6a2443ee03f6390b
+Payload = 795af4
+CT = f658b4b1bd7ad5d81686aeb44caa6025d488bd
+
+Count = 37
+Adata = 7bef8d35616108922aab78936967204980b8a4945b31602f5ef2feec9b144841
+Payload = 66efcd
+CT = e9ed8d0553c801f37c2b6f82861a3cd68a75e3
+
+Count = 38
+Adata = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe01ec1b66eee216341
+Payload = 78b00d
+CT = f7b24de3eeb8ea6c08b466baf246b3667feb3f
+
+Count = 39
+Adata = 71bf573cf63b0022d8143780fc2d9c7dbd0505ac31e9dce0ad68c2428b0878a0
+Payload = 9dd5e1
+CT = 12d7a11db811640c533794bfec6eeb977233ec
+
+[Plen = 4]
+
+Key = 62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0
+Nonce = 5bc2896d8b81999546f88232ab
+
+Count = 40
+Adata = fffb40b0d18cb23018aac109bf62d849adca42629d8a9ad1299b83fe274f9a63
+Payload = 87294078
+CT = 2bc22735ab21dfdcfe95bd83592fb6b4168d9a23
+
+Count = 41
+Adata = 75c3b3059e59032067e9cd94d872e66f168e503bcf46bc78d82a4d4a15a29f6e
+Payload = 0f28ee1c
+CT = a3c38951b5de3331078aa13bd3742b59df4f661a
+
+Count = 42
+Adata = 8fb9569f18a256aff71601d8412d22863e5a6e6f639214d180b095fa3b18d60e
+Payload = d41c9c87
+CT = 78f7fbcae52afe7326a12a9aaf22255a38d4bd0d
+
+Count = 43
+Adata = 8b62d9adf6819c46c870df8a1486f0a329672f7d137bb7d8659f419c361a466c
+Payload = 046bc0d8
+CT = a880a7957543692a72f0d599de48b5e5f5a9413f
+
+Count = 44
+Adata = fd98f8f39dfa46ea5926e0ffacbabbe8c34205aade08aa0df82e1d4eaaf95515
+Payload = 39bd4db8
+CT = 95562af530fc357f5482b9004d466bf858586acb
+
+Count = 45
+Adata = 09bf4f77a9883733590a3cc7ee97f3c9b70f4db255620e88cd5080badc73684c
+Payload = b43cdd3a
+CT = 18d7ba77a9e8db046fdd548b52d40375c1e9a448
+
+Count = 46
+Adata = 40326d765e0f6cf4b4deccb128bebf65a7b3c3e5bcf1d58f6158e1e9153b7e85
+Payload = e0052e9b
+CT = 4cee49d64efbdd4ad8d3e863172d9372fca07c20
+
+Count = 47
+Adata = aa5ae6dcdc21b5446489bdabf5c6747bdf3bbfdb3de2c03170efefe5ccb06d69
+Payload = 696825f6
+CT = c58342bb95bd661b32bc18025808f8b4035acad6
+
+Count = 48
+Adata = d3d34f140a856e55b29471fde4c0e5f7306b76d03faab26db79c10f95ffb3122
+Payload = 7eb07739
+CT = d25b1074ac05b072264e31a4b2801a6d790512d7
+
+Count = 49
+Adata = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671194646e0b0136432
+Payload = 9cad70b1
+CT = 304617fcc00514d260e1d211de361c254369e93a
+
+[Plen = 5]
+
+Key = bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576
+Nonce = 4f18bcc8ee0bbb80de30a9e086
+
+Count = 50
+Adata = 574931ae4b24bdf7e9217eca6ce2a07287999e529f6e106e3721c42dacf00f5d
+Payload = 3e8c6d1b12
+CT = 45f3795fcf9c66e1a43103d9a18f5fba5fab83f994
+
+Count = 51
+Adata = 99cd9d15630a55e166114f04093bd1bb6dbb94ecaad126fe5c408dee5f012d9f
+Payload = 76fc98ec66
+CT = 0d838ca8bb6f3cd579294f706213ed0f0bf32f00c5
+
+Count = 52
+Adata = 1516fdf7a7a99f3c9acc7fff686203dec794c3e52272985449ddf5a268a47bc3
+Payload = 6564c247cc
+CT = 1e1bd603117d38e026f706c9273dbcb6dc982751d0
+
+Count = 53
+Adata = 0c9c35be98591bf6737fc8d5624dcdba1a3523c6029013363b9153f0de77725b
+Payload = c11b9c9d76
+CT = ba6488d9abc3e46166767c6ad2aeffb347168b1b55
+
+Count = 54
+Adata = e74afe3ba960e6409dba78ecb9457e2a4ce2e09792b1d2e3858f4c79f7ddba62
+Payload = 45a4e0d7dd
+CT = 3edbf4930033a7dca78bcbf4d75d651ee5fadff31b
+
+Count = 55
+Adata = 96cbe9cd193513599c81f5a520fabaff51ee8cbdb81063c8311b1a57a0b8c8fd
+Payload = e5861b2327
+CT = 9ef90f67fa11585167c83105ee16828a574c84ac86
+
+Count = 56
+Adata = 2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d20024dac29e41e2cf
+Payload = f5b5bcc38e
+CT = 8ecaa88753ffaba456f78e431f4baa5665f14e1845
+
+Count = 57
+Adata = be125386f5be9532e36786d2e4011f1149abd227b9841150d1c00f7d0efbca4a
+Payload = b6cc89c75d
+CT = cdb39d838034714731f9503993df357954ecb19cd3
+
+Count = 58
+Adata = 3fa8628594b2645bc35530203dca640838037daeaf9cf8acaa0fb76abf27a733
+Payload = 3802f2aa9e
+CT = 437de6ee436c1b008b7572752f04362b2bfdc296bb
+
+Count = 59
+Adata = 642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f
+Payload = e082b8741c
+CT = 9bfdac30c1a3f7c3c29dc312c1f51a675400500e32
+
+[Plen = 6]
+
+Key = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c
+Nonce = 7a76eac44486afdb112fc4aab9
+
+Count = 60
+Adata = a66c980f6621e03ff93b55d5a148615c4ad36d6cbdd0b22b173b4b1479fb8ff7
+Payload = 1b62ad19dcac
+CT = 4ad1fcf57c12b14e0e659a6305b4aeffae82f8a66c94
+
+Count = 61
+Adata = c13f65bd491cb172a0f7bbc4a056c579484b62695e90383358d605307d5be0a5
+Payload = 3ef0faaa9b79
+CT = 6f43ab463bc779fa7932d365e2da9b05c00a7318384a
+
+Count = 62
+Adata = 59dcca8fc50740831f8f259eb55d4db11f763a83187d93758d78d166f4d73cd5
+Payload = 1a98ddbf35f1
+CT = 4b2b8c53954f813229912137b7a4945dc07cea24a974
+
+Count = 63
+Adata = 578509ca4f57aadb78056794bf18b0714090970db786e2e838105e672165761c
+Payload = f46a7b1c28ea
+CT = a5d92af088546e045f19f737a24c8addf832ed3f7a42
+
+Count = 64
+Adata = 696c0c6427273cf06be79f2206c43af9cbda0b884efaf04deba0c4bf0a25cb26
+Payload = e98f5e5a20d0
+CT = b83c0fb6806edaae8a7dcd3b0fbb59438f88743ec6e8
+
+Count = 65
+Adata = 95a66b60249ed086eecaeb9bc449afcee9de212619e87516ca947351b25120df
+Payload = 06319c0480e2
+CT = 5782cde8205cd9cb636ca6543c4e35964f47341f2814
+
+Count = 66
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112e1130c21d411cdf16a84176d
+Payload = f4c723433b7c
+CT = a57472af9bc2ec82eadf4eb1f055da1a92a82052ab8b
+
+Count = 67
+Adata = ff3bff3a26fc5a91252d795f7e1b06f352314eb676bff50dc9fbe881c446941e
+Payload = 02f809b01ce3
+CT = 534b585cbc5d01b10a7ae24a4ca2bfb07ea2a3b31a97
+
+Count = 68
+Adata = f6be4aad63d33a96c0b5e9c4be62323c9e2308b29961fff980ba0dbda0549274
+Payload = 2b6004823a29
+CT = 7ad3556e9a97231323a4b88af5d7d0b07c0e73ddce1d
+
+Count = 69
+Adata = c3706a28d7420b41e072dcecc06b6b13116cca110bde8faea8e51f5107352d71
+Payload = 236c60cba4fa
+CT = 72df31270444db30eb33d2ede33abbe22f37704fe68b
+
+[Plen = 7]
+
+Key = f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2
+Nonce = d0d6871b9adc8623ac63faf00f
+
+Count = 70
+Adata = e97175c23c5b47da8ce67811c6d60a7499b3b7e1347ad860519285b67201fe38
+Payload = d48daa2919348d
+CT = eb32ab153a8e092fa325bafc176a07c31e6cc0a852d288
+
+Count = 71
+Adata = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b6df8e69e5e1111fa
+Payload = f95b716bfe3475
+CT = c6e47057dd8ef1a24840f4f40a7963becde3a85968b29c
+
+Count = 72
+Adata = efcaa6f6cda3036b0b52ff9f36bc38ca74049c32c6b7cdfb8a46ca4144bacd64
+Payload = 4862e3677083f0
+CT = 77dde25b5339748f2a4a5c276727e0a210fc2efb5aeabe
+
+Count = 73
+Adata = 360bcb407603fe92f856bf677625b9882521e6dae8f35fdfc3dc737f9398f609
+Payload = 7f1ca0728f6d65
+CT = 40a3a14eacd7e1051734fc31232ab2ab63474020ab4dc9
+
+Count = 74
+Adata = f12ee9d37946cfd88516cbe4a046f08c9bbba76a3973ff1e2cb14493405bd384
+Payload = 67478ef73290fa
+CT = 58f88fcb112a7ec715244f307609ffa253e4e3659b0ece
+
+Count = 75
+Adata = 5833dde0c577b2be4eb4b3d01d7b0042fa8441ad7043ea462bbbbd56a59790ea
+Payload = 36bb9e511276c5
+CT = 09049f6d31cc41f11047da612d2987fa2e50ada5ae7f9d
+
+Count = 76
+Adata = 1e103c63d8ead36b985f921044cd32b8f9f04a2ba9fa154a09e676ffaa093970
+Payload = d68d6556c5a5b1
+CT = e932646ae61f35382f7648718127ebae7eb7443ebd2c2c
+
+Count = 77
+Adata = a1cfb61d45a140bdea6329ba0fe80429ff9aa4624a1d31bc752f7c97f1d390a0
+Payload = 0568cca4ff79dc
+CT = 3ad7cd98dcc358cc40a5e7fffb1fb9a5dd9d6ba91bede1
+
+Count = 78
+Adata = 116b5b015e44ceef0061b2d2e73fa0b386d5c1e187782beebdfc6efb5a1c6935
+Payload = bd93d08eea4263
+CT = 822cd1b2c9f8e7468d2b70c311732f11ed72b57d83e500
+
+Count = 79
+Adata = 3d55882e6f3f89309b6940a3b408e573458eedd10fc3d0e1f3170eb313367475
+Payload = 4fb62753024e92
+CT = 7009266f21f416b41a70f548e359add30c0e5746fbeb2b
+
+[Plen = 8]
+
+Key = 493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b
+Nonce = fe2d8ae8da94a6df563f89ce00
+
+Count = 80
+Adata = 579a637e37a0974cd2fc3b735d9ed088e8e488ffe210f043e0f9d2079a015ad6
+Payload = e5653e512d8b0b70
+CT = 75d31f8d47bee5c4e2ba537355ae8ab25cc9ed3511ff5053
+
+Count = 81
+Adata = 1583138aa307401dddc40804ac0f414d338fc3ffb2946f09aaaa7079426fc1ee
+Payload = 2c4ba9ce52e01645
+CT = bcfd881238d5f8f1781a9e359804831f31a1efb1ae1cb71d
+
+Count = 82
+Adata = 78d3dda40e433bba7a330ca3e5bd5170f0895f2e3e438402344ced79fcb0c719
+Payload = 5eb2d054a0e58c62
+CT = ce04f188cad062d62dcc77c4e1fe2bafd477598977835f0c
+
+Count = 83
+Adata = dfc762466fa84c27326e0ee4320aa71103d1e9c8a5cf7d9fab5f27d79df94bd6
+Payload = bbbf7830d04ab907
+CT = 2b0959ecba7f57b308946723baf0dbf613359b6e040f9bd5
+
+Count = 84
+Adata = 7e8ea82d1137c1e233522da12626e90a5f66a988e70664cb014c12790d2ab520
+Payload = 10c654c78a9e3c06
+CT = 8070751be0abd2b2003bd62ca51f74088bbbd33e54ac9dd4
+
+Count = 85
+Adata = 873da112557935b3929f713d80744ed08b4b276b86331dbc386fba361726d565
+Payload = 668d32e322e1da3e
+CT = f63b133f48d4348a67e65e7f2cdedf6ef8cc0ee7a6dcfb02
+
+Count = 86
+Adata = cfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82
+Payload = e39f6225e8eab6cc
+CT = 732943f982df58780532f8c6639e5d6c7b755fcf516724e3
+
+Count = 87
+Adata = 01abcfee196f9d74fcaa7b69ae24a275485c25af93cc2306d56e41e1eb7f5702
+Payload = 6021a00f6d0610a4
+CT = f09781d30733fe107fd7a33828413ebc252dd9d015773524
+
+Count = 88
+Adata = ce1c31e7121c071d89afab5a9676c9e96cac3d89dcae83136bbb6f5ca8f81e5d
+Payload = bbaf0ac4e77ee78d
+CT = 2b192b188d4b0939d3d51368799325ad1c8233fa071bade0
+
+Count = 89
+Adata = bb210ca5bc07e3c5b06f1d0084a5a72125f177d3e56c151221115ae020177739
+Payload = 98a2336549a23a76
+CT = 081412b92397d4c25d1ea568637f773174a7f920a51b1fe1
+
+[Plen = 9]
+
+Key = b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a
+Nonce = 274846196d78f0af2df5860231
+
+Count = 90
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d
+CT = f019ae51063239287d896e7127f17d13f98013b420219eb877
+
+Count = 91
+Adata = 162d0033c9ea8d8334d485b29eef727302135a07a934eea5fee6041e9f1f47c1
+Payload = 0d9168eeab3b27ba69
+CT = 9cd5b4f54443433d997cc2cd61da9358b4045fef32f8192cbf
+
+Count = 92
+Adata = 3f4ab57efa32f51a4c00790280e77c0e55b85bbda4f854e242368e9a289b5a81
+Payload = 6287dcffdd5fb97885
+CT = f3c300e43227ddff75d280f0ffdd560fb8915978e3bd6205bb
+
+Count = 93
+Adata = 945d18134c148f164b39fd7c4aef0335045553f6ea690a3b1726418d86f0de00
+Payload = 6e5e01b3fd71d16b9c
+CT = ff1adda81209b5ec6c7dbf90420a1ff2e24bd6303b80cfc199
+
+Count = 94
+Adata = 23af12893431b07c2922ab623aed901c0eaaeb9a24efc55273e96aea4dab7038
+Payload = b51521e689b5247362
+CT = 2451fdfd66cd40f492d741f4329ae7cc77d42bf7e5f2ec5ab6
+
+Count = 95
+Adata = b15a118b3132c20c31e6c9d09acdee0e15fcc59d6f18306442682512d22eb10f
+Payload = 7f973617e710fb76fe
+CT = eed3ea0c08689ff10ec9ffdcc2f36edac14613b1d85baf25a9
+
+Count = 96
+Adata = dcfbeb6490f5fa7eaf917462473a6cec98bebf8f17493fe9b994119a6d5a5457
+Payload = 7e909b6727ac3fd02f
+CT = efd4477cc8d45b57df5a61a28bb10265b26043d7a8dd357713
+
+Count = 97
+Adata = 77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478c
+Payload = a5075638932b5632f8
+CT = 34438a237c5332b508d321c371ae1fd01bdf3b6c75a597da6e
+
+Count = 98
+Adata = 3aa8f204eb127b547e13873ed0238018394e13686c8734e49e3e629deb352c77
+Payload = c10f15a0de78db8aa3
+CT = 504bc9bb3100bf0d539393d1635bc40ac62405a39155406c47
+
+Count = 99
+Adata = 7f67e6f97c6c258f014d721a4edaaa0ddb3f9f09993276ab7b714ea9356c231d
+Payload = 8294f830cfca42cfbe
+CT = 13d0242b20b226484eff89641e1bd5ad6cc827441b17c45ecf
+
+[Plen = 10]
+
+Key = dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9
+Nonce = b3503ed4e277ed9769b20c10c0
+
+Count = 100
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b22719
+CT = e317df43ab46eb31be7e76f2730d771d56099a0c8d2703d7a24e
+
+Count = 101
+Adata = da77c6d5627a2aa34911bd1f7cc5f8aa68a2c6546adc96a186b9af8e5baac4cf
+Payload = e081c43a07450ce0dfa2
+CT = 2daaebd62095206346c5bcc7a8260ef361dc39fdb776d041f0d4
+
+Count = 102
+Adata = 134d2d9726400d09dd3521326f96fbef993ddc0c4088770057b0f8d70356456f
+Payload = c381d2ae5e72fc82324a
+CT = 0eaafd4279a2d001ab2d19f0cbb0899f221aac9762f2650f8058
+
+Count = 103
+Adata = 0d065dfde1de1f21784c7869eb566c977f807cfbd53578f4616995b51d7dc045
+Payload = 737f4d00c54ddca80eec
+CT = be5462ece29df02b978b3dc92a9bd26b9653e5917359c331fcff
+
+Count = 104
+Adata = 95c54d187f2415535451cbb9cb35869749b171f7043216ce6886dd77baeecf60
+Payload = 4e9e251ebbbbe5dbc8ff
+CT = 83b50af29c6bc958519891dda72c27d272561e00f7041845d998
+
+Count = 105
+Adata = 0f98039e6a9fe360373b48c7850ce113a0ff7b2ae5ce773dd4c67ca967cd691b
+Payload = 0db72b281ab4046d15a6
+CT = c09c04c43d6428ee8cc1928ac628758ad58fc1b5a768d4722848
+
+Count = 106
+Adata = ad840bc55654762e5eba0e4a9e7998992d990a06d70da1b1ca922ef193dab19a
+Payload = 4f7b4f38ff1ba4df5a59
+CT = 825060d4d8cb885cc33ed11dad4dc8b265a53cf0bdd85c5f15f4
+
+Count = 107
+Adata = 911e9876ea98e1bcf710d8fd05b5bf000ea317d926b41b6015998ee1462ab615
+Payload = 58ce55379ef24b72d6d6
+CT = 95e57adbb92267f14fb18eb659a5a7084be48d099467da4395df
+
+Count = 108
+Adata = 3f68a4fb4043bcf9b6d277c97e11365d949c705bd6679c6f0aaf52e62330ad79
+Payload = a219028a953ce1544835
+CT = 6f322d66b2eccdd7d1523b2b2583fd117cec47b1c84d3863159e
+
+Count = 109
+Adata = 02f32242cba6204319075ea8ce806a57845355ae73e6b875955df510096ebff9
+Payload = 83b0ee9a52252c456105
+CT = 4e9bc17675f500c6f8625456eb2b6a2d35c649a84051f843153c
+
+[Plen = 11]
+
+Key = 4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207
+Nonce = bdb1b82ba864893c2ee8f7426c
+
+Count = 110
+Adata = 9bcc5848e928ba0068f7a867e79e83a6f93593354a8bfcfc306aeeb9821c1da1
+Payload = 8015c0f07a7acd4b1cbdd2
+CT = 8e9f80c726980b3d42e43a6512a0481255b729a10f9edb5f07c60c
+
+Count = 111
+Adata = c2e75952ab49216f305e3776865791ce877cef8c0229ca97561787093fddf1d8
+Payload = c97b62a719720b44b7779c
+CT = c7f122904590cd32e92e748c514444f00ffdb80a4bb7e9eb651946
+
+Count = 112
+Adata = c76a3ff4e6d1f742dd845be2d74c1a9b08e418909b15077deb20373ef55caf91
+Payload = cb7c17ef62464ecc8008f6
+CT = c5f657d83ea488bade511edb609dfc1929ac1ba5753fc83bf945b7
+
+Count = 113
+Adata = bdb69f99f9a144b9ad88c6cfd8ffb8304c201de9b2818552ce6379e6042c1951
+Payload = 893a690cc5221de597d0e8
+CT = 87b0293b99c0db93c9890053b74283296d0fca83b262915289163c
+
+Count = 114
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf0
+CT = 8e79a41300dc6d60b1d21888a34955893059d66549795b3ac2105c
+
+Count = 115
+Adata = a9db62e9ab53c4a805c43838ce36b587d29b75b43fb34c17a22d3981120f3bc5
+Payload = 641c6914920a79943dca39
+CT = 6a962923cee8bfe26393d1377c4e2f20aaa872a9a0b1d1d7f56df0
+
+Count = 116
+Adata = f0c2cc5a1b4c4cbe839338fa0d7a343514801302aef2403530605cf4f44d2811
+Payload = 2286a1eddd80737a724ca9
+CT = 2c0ce1da8162b50c2c15415545aa0c1dd11551891ae553d3a91908
+
+Count = 117
+Adata = 9842922499ad4d487488b3731f48765efe0b4eb59e7b491ba5f6636f09ed564d
+Payload = d8c63e7d7d332198249c0c
+CT = d64c7e4a21d1e7ee7ac5e4d9e07ec5806360843676ef27d811b246
+
+Count = 118
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf
+CT = 450bc07a2b989fc0ff5e27483b8727c5753ede25e1fab0d86963be
+
+Count = 119
+Adata = 2c186c5c3463a4a8bad771feb71e2973c4f6dede2529827707bf4fa40672660f
+Payload = dfc762466fa84c27326e0e
+CT = d14d2271334a8a516c37e64b5c3c1dc577ee8fcf6ef3ebc0783430
+
+[Plen = 12]
+
+Key = d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906
+Nonce = 0b5f69697eb1af24e8e6fcb605
+
+Count = 120
+Adata = ea26ea68facdac3c75ba0cdf7b1ad703c9474af83b3fbfc58e548d776b2529b9
+Payload = a203aeb635e195bc33fd42fa
+CT = 62666297a809c982b50722bd56bc555899345e0404b2938edf33168e
+
+Count = 121
+Adata = 0b32069fc7e676f229f1037d3026c93eef199913e426efd786b524ce1dbde543
+Payload = aac414fbad945a49ae178103
+CT = 6aa1d8da307c067728ede1449b15447c904b671824c2ca24c4fc7ad4
+
+Count = 122
+Adata = 7a8658302e5181552292aa56e8209de63b5d86934167549b0d936202681757e1
+Payload = 7ee0ce371329192618e3cda0
+CT = be8502168ec145189e19ade7ea13850e99ef9300c65f5abc9419d13a
+
+Count = 123
+Adata = 4f05600950664d5190a2ebc29c9edb89c20079a4d3e6bc3b27d75e34e2fa3d02
+Payload = b0a1af969a95025385b251af
+CT = 70c463b7077d5e6d034831e8486c93c31bbedc9e5ffa2f4154bceea9
+
+Count = 124
+Adata = 4530e4dc6a4c3733b8ab7e77e384223cc1a8c179fb66818c08aca47e5c705d89
+Payload = 9f6c6d60110fd3782bdf49b0
+CT = 5f09a1418ce78f46ad2529f7f18b556e7da59fd2549dc57a17bf64f8
+
+Count = 125
+Adata = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381c5439b098ff978b01b
+Payload = 90958d7f458d98c48cbb464c
+CT = 50f0415ed865c4fa0a41260b30aad3a838680cbd313004685a5510c5
+
+Count = 126
+Adata = f6df267e5cbc9d2a67b1c0fd762f891ee3b7c435884cb87d8228091b34aeddae
+Payload = 9f7ae892e5662803408d4d06
+CT = 5f1f24b3788e743dc6772d411d57b89ed0c91251aed37a6ca68a50c7
+
+Count = 127
+Adata = 4372e152b1afd99c7f87c8a51dbc3a5c14c49d04ea1c482a45dfbcda54972912
+Payload = 817074e351455f23cb67883d
+CT = 4115b8c2ccad031d4d9de87ad79a3b0feea16ff5fbca16211ea6fdd9
+
+Count = 128
+Adata = 82b6cd1c6618c42ba74e746075dc28700333578131ca6fde6971d2f0c6e31e6a
+Payload = 1b7da3835e074fdf62f1eb3c
+CT = db186fa2c3ef13e1e40b8b7b49f22737c4b2f9fa0a7e3dd4b067fbaa
+
+Count = 129
+Adata = a5422e53975e43168726677930f6d3e13281bdbd13c67c168340ed67e45d15b0
+Payload = 57473e7a105c806867379194
+CT = 9722f25b8db4dc56e1cdf1d3ef43a48dbea8c1547455ad0197af88a2
+
+[Plen = 13]
+
+Key = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df
+Nonce = 55b59eb434dd1ba3723ee0dc72
+
+Count = 130
+Adata = 9b1d85384cb6f47c0b13514a303d4e1d95af4c6442691f314a401135f07829ec
+Payload = 8714eb9ecf8bdb13e919de40f9
+CT = ba6063824d314aa3cbab14b8c54c6520dac0f073856d9b9010b7857736
+
+Count = 131
+Adata = fa17c693d0997140fbc521d39e042d8e08388106874207ca81c85f45c035d6e6
+Payload = a0837676e091213890dc6e0a34
+CT = 9df7fe6a622bb088b26ea4f20820a423dd30796b6016baff106aaef206
+
+Count = 132
+Adata = 27663597b389b78e96c785ca2f5510c8963a5561d2b0b24c4dcdf8e58562c12c
+Payload = b8a2ce7e051b8d094ec43f2a7f
+CT = 85d6466287a11cb96c76f5d2436032bc79c4aef1f74da25e92b0aa7f8a
+
+Count = 133
+Adata = d8f1a83371487d611ce704e0a6731f97a933c43569690022fce33cb5aecdc0a7
+Payload = 9e4103ab1dfb77ae3494507332
+CT = a3358bb79f41e61e16269a8b0e658123d2e5bb324c7ead8897f8e32b0a
+
+Count = 134
+Adata = 05c57aab99f94b315cf8bdd2d6b54440c097fe33c62a96b98b1568cdee4ce62c
+Payload = fb3e3d1b6394d2daebf121f8ac
+CT = c64ab507e12e436ac943eb0090270758ab09f93fa3ba7d7a2aa8eac789
+
+Count = 135
+Adata = 1c1b0933c508c6a8a20846ebd0d0377e24f4abc0c900d3a92bc409ba14ef1434
+Payload = 549ba26a299391538b56ce4bd7
+CT = 69ef2a76ab2900e3a9e404b3eb2293813f1bcb96564f772e9308e42b2d
+
+Count = 136
+Adata = 9f5cf9149f556124d6bb4e3e243cca1502c02682709392cc2ec7eb262fd4d479
+Payload = 287f31e69880823df7798c7970
+CT = 150bb9fa1a3a138dd5cb46814c81877380d5cf097c2fb5177750f8b53a
+
+Count = 137
+Adata = 1a49aaea6fc6fae01a57d2fc207ef9f623dfd0bc2cf736c4a70aaaa0af5dafd3
+Payload = 040d18b128ae4a1935f9509266
+CT = 397990adaa14dba9174b9a6a5acf42c75787edc62a180568c6ef56545d
+
+Count = 138
+Adata = f29a0b2c602ff2cacb587292db301182e6c76c5110b97ca8b706198f0e1dbc26
+Payload = 92441cbe8d70820870bb01ad63
+CT = af3094a20fca13b85209cb555f56d47a0631f2038103e3904b556ba7a5
+
+Count = 139
+Adata = 01fcf5fef50e36175b0510874ea50a4d2005ad5e40e5889b61417700d827251e
+Payload = f11d814df217de96333dee1cbf
+CT = cc69095170ad4f26118f24e4835be15b7ae24edccd0b0934e3af513ed3
+
+[Plen = 14]
+
+Key = 3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+
+Count = 140
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f38983
+CT = 37a346bc4909965c5497838251826385a52c68914e9d1f63fd297ee6e7ed
+
+Count = 141
+Adata = 52f6a10a022e5ee57eda3fcf53dcf0d922e9a3785b39fad9498327744f2852e4
+Payload = 23fe445efa5bcb318cc85e2ad1ac
+CT = 81c90102c44e7cc9cee2de5b09ad364b603de6afbc2d96d00510894ccbe7
+
+Count = 142
+Adata = d236e3841b9556b32dbd02886724d053a9b8488c5ad1b466b06482a62b79ebb6
+Payload = 762fdc3e0c30c7ecf2ec8808bb79
+CT = d418996232257014b0c6087963781a4321c2ddbc35ce4864457d611219e9
+
+Count = 143
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+Payload = b6813d5fe8afa68d646c197337a2
+CT = 14b67803d6ba117526469902efa3296e55efebb17fe145cdca9b31ea7bcc
+
+Count = 144
+Adata = 7f291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4090e94b3ef5fd4
+Payload = 4ce8b6578537215224eb9398c011
+CT = eedff30bbb2296aa66c113e9181059270a0510e7cc1b599705853af2144d
+
+Count = 145
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f38f50bd
+CT = 3c88d63806415da4d58e73fe88bcb55847573bf21e946ce9bdc5f569e3ff
+
+Count = 146
+Adata = 5a44ff94f817c7c028a8f3db35a4d01364d2598432469f09ded86e5127d42d35
+Payload = da989cc7d375ed5fac4d7f938d74
+CT = 78afd99bed605aa7ee67ffe25575b8a61c5687ea02f0276824b8316b76f1
+
+Count = 147
+Adata = 2a755e362373ef27a911c4d93ca07bc97135645442ad7ad6a8ef98146c71e9d7
+Payload = 6fbab5a0f98e21e4d15904af5948
+CT = cd8df0fcc79b961c937384de8149a07ee02791011129fcacffcfb1bf4145
+
+Count = 148
+Adata = f7988873f45a5de314e5381d3f14d8f8c48c9b649bf3e745ed5dc882d507da58
+Payload = b610349e8b370a7c195598573637
+CT = 142771c2b522bd845b7f1826ee36d34204b1ce23f5f58a8eb7cf1fa8cfa7
+
+Count = 149
+Adata = 95d2c8502e28ab3ee2cac52e975c3e7bccb1a93acc33d9c32786f66d6268d198
+Payload = 1d969fd81dab5ced3e6ee70be3bf
+CT = bfa1da8423beeb157c44677a3bbe9c618bb88bbcefb008a5ea6bed4ff949
+
+[Plen = 15]
+
+Key = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Nonce = a5c1b146c82c34b2e6ebeceb58
+
+Count = 150
+Adata = 5e60b02b26e2d5f752eb55ea5f50bb354a6f01b800cea5c815ff0030b8c7d475
+Payload = 54be71705e453177b53c92bbf2ab13
+CT = 788db949697b8cd9abbc74ed9aa40cd6852dc829469368491149d6bb140071
+
+Count = 151
+Adata = 210c04632341fbfc185bfe3cbf6fe272bbe971104173bcb11419b35ab3aaf200
+Payload = 22197f9ad14591e7a6d5f8b18c969a
+CT = 0e2ab7a3e67b2c49b8551ee7e4998556940dc5a7e44bf10234806d00a012b5
+
+Count = 152
+Adata = d3a205dd017e79a67400a937a20ef049f4c40d73311731f03ab857a3f93bd458
+Payload = 096b2f530933c1273304a6ad423726
+CT = 2558e76a3e0d7c892d8440fb2a38390898f7dbde25b0b70d335df71a06987b
+
+Count = 153
+Adata = 0c9b3ba4faf5fc2f310ad1bab06c4ca13474b714feeffb6ad615c1b850bbd6a3
+Payload = d44fdfd9da3a63c1083afe574e91bf
+CT = f87c17e0ed04de6f16ba1801269ea02fd10d1f21b6b963c05aeda8eb09e272
+
+Count = 154
+Adata = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841528cccb79fd791b3
+Payload = 8d836acc13ed83c2b2c706415c9679
+CT = a1b0a2f524d33e6cac47e0173499664491d23d90ff55abca17e9d943b98c7f
+
+Count = 155
+Adata = 69dc21eb6f295b12ba493ee8fe6c40d78af946067ce772db316a3cbf00d3c521
+Payload = 2a68e3fe746f593c1b97cb637079c3
+CT = 065b2bc74351e49205172d351876dc9616886c6b2adc97db5a673846b6662c
+
+Count = 156
+Adata = 095eb52135dc6d9c1f56a2571c1389852482e7aa3edc245a3904a0449db24a70
+Payload = 39799b001ed2c334c269acb0f2328c
+CT = 154a533929ec7e9adce94ae69a3d932441dcae1760db90379bd354fa99164e
+
+Count = 157
+Adata = efd7270e0396392fde8b0ddaab00544cbbd504f4d97d4e90d749d1946de90dcb
+Payload = 42143a2b9e1d0b354df3264d08f7b6
+CT = 6e27f212a923b69b5373c01b60f8a9c7c7deb28bdcf84886ef843216b94449
+
+Count = 158
+Adata = 8bc181ce2e66294e803a8dc3834958b5f173bc2123c0726e31f3fca25b622ed6
+Payload = a3dcf26327059a4245b79a38bb8db6
+CT = 8fef3a5a103b27ec5b377c6ed382a935061ae3cd892ba63c44b809d6d29421
+
+Count = 159
+Adata = c39ec70c2c71633ae0dccc41477ac32e47638c885cf59f34ebd4a096d32f91f9
+Payload = 3d54883449ecca8f153436c25a0a01
+CT = 1167400d7ed277210bb4d09432051e3c9ae69a4c59ff8e251c2fe022d065a9
+
+[Plen = 16]
+
+Key = ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62
+Nonce = 121642c4218b391c98e6269c8a
+
+Count = 160
+Adata = 718d13e47522ac4cdf3f828063980b6d452fcdcd6e1a1904bf87f548a5fd5a05
+Payload = d15f98f2c6d670f55c78a06648332bc9
+CT = cc17bf8794c843457d899391898ed22a6f9d28fcb64234e1cd793c4144f1da50
+
+Count = 161
+Adata = a371ca29b92ed676bab5dfc4d78631bb6d9bb23a29f822907084a1f0fe17721f
+Payload = 60d55a8d5ab591a51e87fdf6aaa2ad25
+CT = 7d9d7df808aba2153f76ce016b1f54c68b55bbe42d8c97504b97c34a5f16e6a6
+
+Count = 162
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2
+CT = d6b93591a99b14dc6ff85768fc5fdc51017d8706acd676ae99e93d5312a4113c
+
+Count = 163
+Adata = eebd2bbf1e9f6d817cd8062a6a9680e7f10464eefeb50b07cb46b14b9b3fcb2c
+Payload = 865b89aa38ee1b5a3ce56620307e8937
+CT = 9b13aedf6af028ea1d1455d7f1c370d45982f0fe5d951a8c62c87894657301e4
+
+Count = 164
+Adata = 72863362612f146699f6b2f6ec3688f2ca6cb1505af7a309c91c1933e34d516a
+Payload = a8efc37d1b8b51f2a47b21dd14da383d
+CT = b5a7e40849956242858a122ad567c1de5addfddbb59f4985947fb3a9ab56333e
+
+Count = 165
+Adata = 9c9efc6593f96207678db813608f2b8bc33ed1bef974ed77ed7b6e74b621b819
+Payload = d9b0eaaff786165f882f41a98dbc0c35
+CT = c4f8cddaa59825efa9de725e4c01f5d6b651053516673402a57538db1a9ce7e9
+
+Count = 166
+Adata = dc482a051b58d8a3904d3af37c37b51983f634a504451bbba6f77d71337f8e78
+Payload = df49d972b6ebbbb18ee975ac635d847e
+CT = c201fe07e4f58801af18465ba2e07d9d86d772b1a1991b7be6589bbccad36171
+
+Count = 167
+Adata = 51ef065a43caa23faf750b02a41ad6ba701aeb8058f6d8738d6f6b005bec7f60
+Payload = 78318aa5cd16699b77bdcea2fc9d1d20
+CT = 6579add09f085a2b564cfd553d20e4c3569387a1a6bcc826e94012670820576e
+
+Count = 168
+Adata = 88e2a74d2920c89c6a101f5f06d0624a6d5eabd9bdb51395ee3983934c55c73d
+Payload = 8e20d65d02dd9a64379f75b6d8328f2d
+CT = 9368f12850c3a9d4166e4641198f76cee9c788b4aae9b2c6caf0c44aa9bd2ed0
+
+Count = 169
+Adata = ada3ed7db2dabbfbc441ef68a5656e628d6d5bd6c1574369688497179a77601a
+Payload = 97e8d8513af41b97801de98cc4269096
+CT = 8aa0ff2468ea2827a1ecda7b059b6975f1df0f01944641a1b04d753e6ab8d3cc
+
+[Plen = 17]
+
+Key = 7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d
+Nonce = 98a32d7fe606583e2906420297
+
+Count = 170
+Adata = 217d130408a738e6a833931e69f8696960c817407301560bbe5fbd92361488b4
+Payload = b0053d1f490809794250d856062d0aaa92
+CT = a6341ee3d60eb34a8a8bc2806d50dd57a3f628ee49a8c2005c7d07d354bf80994d
+
+Count = 171
+Adata = 4ae414bc888a42141d3060c71c2dbbffd425b6a952806982271a8e756b3c9e24
+Payload = 51eb190c6a9f46e8ec1628b090795470c0
+CT = 47da3af0f599fcdb24cd3266fb04838df13c1c5755a5a240c33b2b890a486aac8b
+
+Count = 172
+Adata = 7b7f78ae1a5ee96fdc49dacd71be1a6ac09a6a162d44dea0172886eca5674e46
+Payload = 25144e807e389bb0e45b6dc25558caf61a
+CT = 33256d7ce13e21832c8077143e251d0b2b4cfca1c19abf447d7bc0898d61885144
+
+Count = 173
+Adata = 03f31c6143b77f6ad44749e2256306b8bf82242f2821fad4075b09b388ba81ca
+Payload = dbe1ee14abfe2ecf4edf6db206cf9886ce
+CT = cdd0cde834f894fc860477646db24f7bff229cc7a390867a245dcb7c434f1db347
+
+Count = 174
+Adata = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa001d553375cc63f8a2
+Payload = db6df31f12bf552f81deff5fa2a373fc22
+CT = cd5cd0e38db9ef1c4905e589c9dea401135361b539f9fe0fb7842907c2326aef63
+
+Count = 175
+Adata = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a7b9bb2bd99392c8a
+Payload = ff2a97b49fcc6a50d4549c979d53ccc51f
+CT = e91bb44800cad0631c8f8641f62e1b382e8ed10943929e7d7bf798b2ae8371aae5
+
+Count = 176
+Adata = 4d1513478fc1fb0a18eb6d2a9324fefbd975ecd1b409025de826bc397462acc1
+Payload = 73ddfa0185200a890b7690a7e3986d8818
+CT = 65ecd9fd1a26b0bac3ad8a7188e5ba7529f92b9e49ab83f113f8949dc9e4a36e0d
+
+Count = 177
+Adata = b26a7ff61bfe94864249af7cc9b4a723627dd4463f5a22f0ca6063769522eab7
+Payload = 5c7604f9ac8fdf30ee5820e5aeb75b65d7
+CT = 4a4727053389650326833a33c5ca8c98e6d0e53223adff22a08e3dddf66fff23e3
+
+Count = 178
+Adata = 960f9a85cfbfb6eab223a4139c72ce926a680ea8e8ecc3088cf123de659ad310
+Payload = d44fdfd9da3a63c1083afe574e91bf01c9
+CT = c27efc25453cd9f2c0e1e48125ec68fcf833f49a42521a7a2367f91bfcc2180b7c
+
+Count = 179
+Adata = 3718467effb5d5dc009aaefce84d8cb4fe8f80eb608f4c678f5d0de02ea11e59
+Payload = bb515dc227abb9acad8fefaa14771bb77b
+CT = ad607e3eb8ad039f6554f57c7f0acc4a4ac08bd395c6807223311070659f550934
+
+[Plen = 18]
+
+Key = 0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c
+Nonce = f61ef1c8c10a863efeb4a1de86
+
+Count = 180
+Adata = 67874c808600a27fcab34d6f69cc5c730831ad4589075dd82479823cb9b41dc3
+Payload = 6a26677836d65bd0d35a027d278b2534e7df
+CT = d1c1f3c60603359c7d6a707f05ecb2296f8e52f2210b7a798ad5c778ee7cfd7fe6e0
+
+Count = 181
+Adata = e0c27cddf919d3092d9a34766c89a5ae6dcf39fe954d1e6f1a70ddf96805def4
+Payload = 4021ff104ff1dbd91e46db249fd82198b0a1
+CT = fbc66bae7f24b595b076a926bdbfb68538f00923bb5a347af13df12f234fca5f03ef
+
+Count = 182
+Adata = 7ae9eca03f616ab39ebb3be26b848842b4aa584e5c8e5695065ad5af34951175
+Payload = 6a681f164efce199a787bccff223b8ae1a98
+CT = d18f8ba87e298fd509b7cecdd0442fb392c9d03ed7bffac83e890caceb6903d9cab5
+
+Count = 183
+Adata = b47c9bc4eb01c74f5db2e6a293bef80db18c58cf06feef7ee0f8a7a9a51c22bb
+Payload = 7861dac338ba3f8274dca04c8c6f92b6d44c
+CT = c3864e7d086f51cedaecd24eae0805ab5c1d4dd8f30870025b2bd1e2a2511574d3e7
+
+Count = 184
+Adata = f6afd661f218c7426b92ee53e65d14898cd0c78a7e594fcc6ac0e3fb5cab1c9c
+Payload = a3f0473c620d2739d5ba4f7156f88d0fb669
+CT = 1817d38252d849757b8a3d73749f1a123e386046d17f337f3cb49884d94995edbdc9
+
+Count = 185
+Adata = d3802911e341577046cfc61d9043b4af059fb4bef3c6a2ff46ccdcb05670af37
+Payload = 07c535d9456a6ff1e41321150d16dae3f7a3
+CT = bc22a16775bf01bd4a2353172f714dfe7ff25fdc77b43bca254d6459263cdfed8fbb
+
+Count = 186
+Adata = db60720db67a60ca286fe744d46173c231fbcc7deb4c9b0d87d52a2247e06b74
+Payload = 5ee220720a896249efdab2ce418318bb5ebf
+CT = e505b4cc3a5c0c0541eac0cc63e48fa6d6eedd1a1d36c8164c55d55dbf0ff1e9517a
+
+Count = 187
+Adata = 57f70ba5493265b30491decc726354e2065e7971a2efd56db9cf0f79b1d76859
+Payload = 98e4eb0361c8bf40bcbe0539b0850e4c35ff
+CT = 23037fbd511dd10c128e773b92e29951bdaeb476e2ca48fd52bec0539b00744a8a07
+
+Count = 188
+Adata = 4a29b9ad548964942f87f28ba267ec0d0e8f72c73b3823ee57693dd63c2605c1
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72
+CT = c4e0d10096f1178ca63ebcc70c5056fea523fad68c62b81d62f2d490ae74f5bb1465
+
+Count = 189
+Adata = acbd2e9911b3218a230d9db5086d91dccac3fc93fc64b0f4a15d56954906b2b7
+Payload = e99ed2ac6c38e033061b5d85f3e77dd72518
+CT = 527946125ced8e7fa82b2f87d180eacaad4913b15d8000266c61ba5aec898eb35b52
+
+[Plen = 19]
+
+Key = bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f
+Nonce = 05b50c458adbba16c55fcc454d
+
+Count = 190
+Adata = 89ad6ae1e550975eaa916a62615e6b6a66366a17a7e06380a95ea5cdcc1d3302
+Payload = c1a994dc198f5676ea85801cd27cc8f47267ec
+CT = 7c9b138177590edaafec4728c4663e77458ffbe3243faec177de4a2e4a293952073e43
+
+Count = 191
+Adata = dfddb719d00398bf48a6cefd27736389e654a93b8595cd5ac446af1996e0f161
+Payload = 791e232bfb42fb18197adc1967da1a83f70168
+CT = c42ca4769594a3b45c131b2d71c0ec00c0e97f8422f736fc435687634d42254b22fd99
+
+Count = 192
+Adata = 58ef310997dcaf067dd217274921504da6dbf0428a2b48a65fe8a02c616ac306
+Payload = 3d4127942459bb8682e662dfc862467582fa68
+CT = 8073a0c94a8fe32ac78fa5ebde78b0f6b5127f38a96e68ef7dbaef1b460cc0980eacd4
+
+Count = 193
+Adata = 511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b8
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd6
+CT = b343016147b47ce03873efc86345faf0d223c15c5c702a82d468929227502e4e35796f
+
+Count = 194
+Adata = e48dfaa53b6807ea6f01d8dca67960b9f321f7851f324459a9bf61fe0be73abb
+Payload = e0f1cd013e6aea4fa484fc3fa35d348b1a2399
+CT = 5dc34a5c50bcb2e3e1ed3b0bb547c2082dcb8e89188c0940182dd99a902d158c5b0810
+
+Count = 195
+Adata = c12c0423fe36e4c88775dd00b4af267b85b7dd2a37a742a3156923c8917c97a3
+Payload = b1cc1946b4fc1dbd033254cdf536f61e9f9cd7
+CT = 0cfe9e1bda2a4511465b93f9e32c009da874c015849acbb7af1892790300bb84fb0558
+
+Count = 196
+Adata = 4255f8af18df7237e0abe98421aec9634443561752d893aaffe76380e829ef32
+Payload = 87284658928208e3bddca83e3ceb13708d88d4
+CT = 3a1ac105fc54504ff8b56f0a2af1e5f3ba60c3e75aaf3077ac6dfb5454851ec3910de6
+
+Count = 197
+Adata = ab83567833d2f3461b5fbecc0e366694bb5ea00933b2b3e792ec3aefe20325df
+Payload = bdb79f931ef3035a33bdd1b032fd9de8f6b2ba
+CT = 008518ce70255bf676d4168424e76b6bc15aade70f42e3e1f2b5bb58433bd11f5dea1f
+
+Count = 198
+Adata = bd1446ba3185d1c16551730947c22142142caa8cc1c540e89ab734ec297401bc
+Payload = 1f9c3a8eb8bc59f3869e10f73883aa8f8990cb
+CT = a2aebdd3d66a015fc3f7d7c32e995c0cbe78dc564f6248cefe5fc7cfb547c90a558925
+
+Count = 199
+Adata = b87577755d2d9489194f6f7cfabf267dc3433a9c91954e81beb72c5e06870922
+Payload = 5f28809181f9a889894da8d6fe1fde6cce354a
+CT = e21a07ccef2ff025cc246fe2e80528eff9dd5db52249d812f7f235afa0732e984e91b2
+
+[Plen = 20]
+
+Key = 8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876
+Nonce = 8479bdfad28ebe781e9c01a3f6
+
+Count = 200
+Adata = 7aebdfd955d6e8a19a701d387447a4bdd59a9382156ab0c0dcd37b89419d6eff
+Payload = 7b125c3b9612a8b554913d0384f4795c90cd387c
+CT = 6cc611d816b18c6847b348e46a4119465104254a04e2dfeeeac9c3255f6227704848d5b2
+
+Count = 201
+Adata = d119f300fbd74e754a200ea2c3f9fabc1466d02078c84245db693eef3f5672a6
+Payload = 8b013f5782d5d1af8dbd451a4202866095dac975
+CT = 9cd572b40276f5729e9f30fdacb7e67a5413d44338d48329997c5981d678b5e24a6f01b0
+
+Count = 202
+Adata = d6204303b86acf62d5ab860ca70161288ede56e3cf017c08dca56fd2d6f8f6fe
+Payload = b2b1d82a5523b72ea366a680922ed3a4624536c4
+CT = a56595c9d58093f3b044d3677c9bb3bea38c2bf2a77e3ab68e0a73519591a33ed098b758
+
+Count = 203
+Adata = 8557e22eb4529b43f16b1f8ae47c714ac8a2c827c1408a47704778b4c5b52601
+Payload = f8c4eb4285d3d7744da52775bb44ca436a3154f7
+CT = ef10a6a10570f3a95e87529255f1aa59abf849c1cff6c24251c2fb7b8604dfa10c60ef4a
+
+Count = 204
+Adata = 8c1a4187efbb3d38332f608f2c8bbe64247d9afa2281ced56c586ecb4ab7a85e
+Payload = 6e7fe35fa39c937a0e6b3a8c072e218650f42b8d
+CT = 79abaebc233fb7a71d494f6be99b419c913d36bb6c3c39f915d081d34559179869b32d81
+
+Count = 205
+Adata = a41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3
+Payload = 917b467d841850fc6e648f1bc298a7f9f1ee38ca
+CT = 86af0b9e04bb74217d46fafc2c2dc7e3302725fc9389a6a6a74c6eb0e1f87562469f2082
+
+Count = 206
+Adata = b0b024e20c4f75a6dad54c21a9edbce846792e957878b1c8ed2d916c757e2b3c
+Payload = 2b4314fe1a6bfa786b7cfc13fbee861b348efbf6
+CT = 3c97591d9ac8dea5785e89f4155be601f547e6c03bed3a2f5dfdbfcc0d7ac26c88d1962c
+
+Count = 207
+Adata = 42153925c46fc9d5d328312d62f59bb99fdc4ac479a3386d5f88fefd4b32f577
+Payload = e19fa7f83c79920cbff45c41a9dee8fc99e97396
+CT = f64bea1bbcdab6d1acd629a6476b88e658206ea035ea1d99be344fa1467ee91c73bbca67
+
+Count = 208
+Adata = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711a08da6acd42299fe
+Payload = 53e0475cf492b3d39dad600f5c58eb0bd0021554
+CT = 44340abf7431970e8e8f15e8b2ed8b1111cb08627936ec10a81b36768b606e9a38b2f4c5
+
+Count = 209
+Adata = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a7977eda6de045878
+Payload = c119a383d9a3d4bff4270a1d22076b346db5f61c
+CT = d6cdee605900f062e7057ffaccb20b2eac7ceb2a11575ae03ea8a57bbe4a67c060367b74
+
+[Plen = 21]
+
+Key = c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2
+Nonce = 94ab51ce75db8b046d6ab92830
+
+Count = 210
+Adata = 2a243246bfe5b5ab05f51bf5f401af52d5bbaa2549cf57a18e197597fe15dd8c
+Payload = 73b09d18554471309141aa33b687f9248b50fe3154
+CT = b7e8264ca70fd2a4fb76f20a8ad5da3c37f5893fb12abeeaef1187f815ca481ed8ddd3dd37
+
+Count = 211
+Adata = 0595306eb7441622a49800edee0134492d82320707fceba902af2e0c95fe634a
+Payload = b64d00f3a4df754fa4ee6376922fb67ccce0c6209f
+CT = 7215bba75694d6dbced93b4fae7d95647045b12e7accc2b55011dbe92ce7619e0ad48b4ccf
+
+Count = 212
+Adata = bd439dbefec589e120fb4f9825b315bf86523b85c61791cd4da4c8d474ba2714
+Payload = 2b11d1ac74ffe701ec733d32085b1054132726e622
+CT = ef496af886b444958644650b3409334caf8251e8c71e8b1f4d70d8f4c7df4f22847d36b394
+
+Count = 213
+Adata = cfebe1cf82267394065bcecfada6709c6c35a3ac835644f560d4c9a8c1848364
+Payload = a88f22424643a523aa3d7d88f4364f1290f49dd0a2
+CT = 6cd79916b40806b7c00a25b1c8646c0a2c51eade47a85e76a9d07b7b361ca56d53c34cda50
+
+Count = 214
+Adata = 7a37255b682766a0bfecf78e5162528885a339174c2a49325739d2bd8877e64f
+Payload = c81427bc84c6a3cfefd4c4cb210fe82212977e1947
+CT = 0c4c9ce8768d005b85e39cf21d5dcb3aae320917a2fddb010e7508ad03ad287068ecee6020
+
+Count = 215
+Adata = 619f2ae80070e278615466a3fd6c9acb7b510c5679bed7038889c77e78d8bd32
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447
+CT = ec9c6d8acc67468feeac4b64a0af139c4c46625aa2ddea785e6c470c52c4fdf432fd78b66e
+
+Count = 216
+Adata = b2571e56f66a857daffbdc99370ceddd4a7bed3867d600cc797000a3b7b57a9d
+Payload = 4c88151cafef75832bacef43a06e862349d56b67ee
+CT = 88d0ae485da4d617419bb77a9c3ca53bf5701c690b91232cfbd7ffff252498b35274fb2995
+
+Count = 217
+Adata = db409636e3e3bcd606a91aeb7592009896f9ad2c4cc6b7f578e6ad59c0f8fa22
+Payload = 572855e22ce89bc2bcf09cb15a1765d99973449d61
+CT = 9370eeb6dea33856d6c7c488664546c125d633938472b2c50e5e391ad104f9ee33b94f2872
+
+Count = 218
+Adata = 62c89a835721207a182968c516dc8be45774ec846e8dcab9ab8611888f2a76a8
+Payload = 89ce46b3de3afaf2518d419b1a2ac24cabca269a96
+CT = 4d96fde72c7159663bba19a22678e154176f5194732d69c5d6db1b130102af3dae0690673b
+
+Count = 219
+Adata = 33f30ddd83002eea50fd4a8fae39d0980a04160a22ac88b755ac050f1d1f8639
+Payload = edf1682a626e9fbf3d57bb260e0876c6f92ba5b114
+CT = 29a9d37e90253c2b5760e31f325a55de458ed2bff1489903365970c2673c9fd457e1077aad
+
+[Plen = 22]
+
+Key = 9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4
+Nonce = af1a97d43151f5ea9c48ad36a3
+
+Count = 220
+Adata = f5353fb6bfc8f09d556158132d6cbb97d9045eacdc71f782bcef62d258b1950a
+Payload = 3cbb08f133270e4454bcaaa0f20f6d63c38b6572e766
+CT = 3966930a2ae8fdd8f40e7007f3fde0bd6eb48a46e6d26eef83da9f6384b1a2bda10790dadb3f
+
+Count = 221
+Adata = e3a1555ffe5f34bb43c4a2dae9019b19f1e44a45fb577d495d2a57097612448d
+Payload = 946e86795c332031e2d1ee09d3d4a101fb6800d00911
+CT = 91b31d8245fcd3ad426334aed2262cdf5657efe408a5587bdd120a7d08cd3841cb117af444fb
+
+Count = 222
+Adata = 9c5d43c1a1269cde199509a1eff67cc83a1759b71c9e7a6ee99f76b98c6e23a6
+Payload = b76ce2ab0065ba1c0a754494991c8c452cb416f18ab1
+CT = b2b1795019aa4980aac79e3398ee019b818bf9c58b0545b32f81dcf03e2bcc2aaf62ad366e97
+
+Count = 223
+Adata = b07452a7900a289b91b2771dfdd5108852536659aa259def7b41e38f80bd03ab
+Payload = a3e0d8d0784155bfc45769c52711d4fa68e8bc390c20
+CT = a63d432b618ea62364e5b36226e35924c5d7530d0d94fea17d78533bc9e022dbfb460afdf499
+
+Count = 224
+Adata = 6b30f55c3101540523a92380390f3f84632f42962061b2724cde78ac39809397
+Payload = 6e6a88abbb52a709b47365ad6aa8016fa9a03a9bd834
+CT = 6bb71350a29d549514c1bf0a6b5a8cb1049fd5afd98056defc6dcaeec80b1c639350ab6f1fde
+
+Count = 225
+Adata = 9fc62d14f8b7a6026509275cff80312ff1ade2b5d9c274cb72a506a571439fc1
+Payload = eba1810d537041821121aeff8e0914ac26a550072c8c
+CT = ee7c1af64abfb21eb19374588ffb99728b9abf332d389d37b7251fb8c0ef2b37c36d51219d0f
+
+Count = 226
+Adata = 6b9389cc42113d639fd2b40cbc732ae0dc7c14513b88b36b45a6ea5a06fe4d2b
+Payload = dfc6692cd2442e5ff1f918c8812a27f81d107d16a12f
+CT = da1bf2d7cb8bddc3514bc26f80d8aa26b02f9222a09bd279d9da4437c8a2a252436508134c56
+
+Count = 227
+Adata = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad166c77952a50318bd
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae
+CT = 9f0ea330e4d4a17a0ef3a2575ff28bfcd9c75f865f1a63943543bc1c5f5991ecc5964a288f79
+
+Count = 228
+Adata = e98b710c47a4d12a73cd8aa2613fc2910c16f4195ea7f15650132493521d19be
+Payload = 9f5a05db89e0e336da066ce81b79ad9be1d0ec4fb7b8
+CT = 9a879e20902f10aa7ab4b64f1a8b20454cef037bb60c0a49ee2b7ceddcbd28abb24b77d5edee
+
+Count = 229
+Adata = 527817316fc48b105f8ab178dd2db1fefa09c50461aa9d8bdf3c03482343bbf9
+Payload = 58f31e5770070a5d4031fb795dc2d298561d3559960d
+CT = 5d2e85ac69c8f9c1e08321de5c305f46fb22da6d97b9b099a68cfa3572d974e03232e09f37fb
+
+[Plen = 23]
+
+Key = d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135
+Nonce = 3891e308b9f44c5b5a8b59004a
+
+Count = 230
+Adata = 0cda000ed754456a844c9ed61843deea9dadf5e723ea1448057712996d660f8c
+Payload = 79ac1a6a9eca5e07ce635bfd666ef72b16f3f2e140d56c
+CT = 1abcc9b1649deaa0bfa7dcd23508282d9c50ca7fee72486950608d7bcb39dcf03a2cab01587f61
+
+Count = 231
+Adata = 3fb6ddb76809b8e6d703347664ef00a365955124c603900d5c8d4ff476138252
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f
+CT = 15c1fde7b60a2dac84a74125f7ff4154132eb0e139e05b1c4fb40e5c8bc37152a173d4bbb18c3e
+
+Count = 232
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab4a5667c472c98b2626
+Payload = a027c28fbe22111fd4c8a226cfe8531c16d7790d561eca
+CT = c33711544475a5b8a50c25099c8e8c1a9c744193f8b9ee019c359008adae3070b5a543ead0effb
+
+Count = 233
+Adata = 7a459aadb48f1a528edae71fcf698b84ed64dc0e18cc23f27ab47eeabeaf833f
+Payload = fa597e37c26c38694abdcf450f9edc529160fa0d651979
+CT = 9949adec383b8cce3b79486a5cf803541bc3c293cbbe5dbd099ab134756b90746762a92a4a9f7f
+
+Count = 234
+Adata = 484207909dec4c35929ebe82fcacf20d2af6d850bd69364ebac9557adeadfbd4
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a0
+CT = fd5c59724fdd3a0cb49cefbda632cf063e9c2f470ef684fa4f6adfec85d055310107ba89198afa
+
+Count = 235
+Adata = 88b5448372548e6aab1b262630a28a471d285514703f1bdb10c695850e18fe6d
+Payload = 7d9582cf9e3bb9ee34dce965f56b08e716589486b0641c
+CT = 1e855114646c0d4945186e4aa60dd7e19cfbac181ec338915d23eb2e952afcc89fbddb567d9d75
+
+Count = 236
+Adata = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb38842d7795d830d2e
+Payload = 5a387e7cc22491fc556fe6a0c060b4911d01f0c11f801e
+CT = 3928ada73873255b24ab618f93066b9797a2c85fb1273aaad6c31828314e24198f005955ca8f5e
+
+Count = 237
+Adata = 2aa7a28da38c42fda2e578d9d6340cd8e80b9b32047c3db296d0640d517b0872
+Payload = 87946e910059cbaf48df63b220f397049c65ca10cd1920
+CT = e484bd4afa0e7f08391be49d7395480216c6f28e63be04e531ebbadccfe47182b41904bbfebcfe
+
+Count = 238
+Adata = 3382051c268891da04e6ca73adcead4029f6a1593be4acfe3968e7351a6a2fb5
+Payload = c62f67d208f1c8ffd5d57df9de15ef54f97fbc07d1630a
+CT = a53fb409f2a67c58a411fad68d73305273dc84997fc42e7c582414154236c09ee704cf4a5de411
+
+Count = 239
+Adata = c352828b1920e53bbb60f2ea6a5f15639659e6f3243405c26f6e48628d5519a9
+Payload = 697e73eaaf562d31bdbf7ce9e78c7426fe1c87e421def9
+CT = 0a6ea03155019996cc7bfbc6b4eaab2074bfbf7a8f79dd57c9990029c89d1b37988745fa5737a3
+
+[Plen = 24]
+
+Key = 4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976
+Nonce = 00d772b07788536b688ff2b84a
+
+Count = 240
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75b8af7746d4e570c848
+CT = f28ec535c2d834963c85814ec4173c0b8983dff8dc4a2d4e0f73bfb28ad42aa8f75f549a93594dd4
+
+Count = 241
+Adata = 1ae8108f216defea65d9426da8f8746a3ae408e563d62203063d49bf7e0d6bdf
+Payload = 2b223932fb2fd8433e4b1af9e8234a824569a141f6c96a69
+CT = 4546c70127abacf84a87e513b8b90331639d386dcff38f6f4de907a59c5e4d3f21e1348d7cdf92b6
+
+Count = 242
+Adata = 460f08114b1015fe8b7a9b5dd1b9e6a3d28367c4bd15f29b13c02a8cb9a53968
+Payload = 4d57cbe4a7e780d4ed17267d5ebc91750c2f0209e0444bd2
+CT = 233335d77b63f46f99dbd9970e26d8c62adb9b25d97eaed4ff4239544e2f354d6c6837cd9c23b884
+
+Count = 243
+Adata = 860f4428259d9c5b17698cc95363db6cfee603258582e3a3e8feb886599d4ac4
+Payload = fda8665f87c618646a89c7abdca275fd10c31453ad4b9c99
+CT = 93cc986c5b426cdf1e4538418c383c4e36378d7f9471799f3f6c6f7cc494201069344e2d6d41bd9b
+
+Count = 244
+Adata = 1b43c482f83780c21583f88e5afcf6938edd20f21b74d895161b60c27a6a42f0
+Payload = 98104fd3f3413ad1f57ef4912cb50097dca379a58c47b0d2
+CT = f674b1e02fc54e6a81b20b7b7c2f4924fa57e089b57d55d43787a15352cfceb028202c8730beaa7a
+
+Count = 245
+Adata = b082ccd964617c27a5607b7324faad237ee53acfc18c35502dbf7c1937a9dfcb
+Payload = b46b343e64d2d70e0bd909dbb3f6bedf7e4adc74321be526
+CT = da0fca0db856a3b57f15f631e36cf76c58be45580b210020f3a0ca3da647eb31893e867956097983
+
+Count = 246
+Adata = b8539ba93ef17254ec1d8d62e8f4eae4d41ee1e75345bf90c9cbb26c63bce501
+Payload = 8e12620bb575e6b167b085255b2b5631ff28e04cbef8826d
+CT = e0769c3869f1920a137c7acf0bb11f82d9dc796087c2676be663fbbebbc251b9f1760afa49e89e71
+
+Count = 247
+Adata = b6b09463b5ef5ead1f17f4021693a0d8452e98dcbb8e7590f9fde6394970a6f8
+Payload = 792aaa23b923d1b53173fe19853b9aa402a301d48529873e
+CT = 174e541065a7a50e45bf01f3d5a1d317245798f8bc136238da90cd87e9d9ca5d85430a150e682752
+
+Count = 248
+Adata = 390f6de14d5e1f2f78dbe757c00b89209d0cf8bc48cbbea035779f93de357905
+Payload = ddc5b4e48970ebd72869be6998e9103c014475e8ae6ea29c
+CT = b3a14ad755f49f6c5ca54183c873598f27b0ecc49754479afc0cc4601afb61efa7059cfe49ec9dde
+
+Count = 249
+Adata = 1d75c9e7acb09932db332498d30f82e4009025cb1827047c59a8f97812b568a4
+Payload = d2b66096c475a77648c27235e6972ba8f18761330d3c6adf
+CT = bcd29ea518f1d3cd3c0e8ddfb60d621bd773f81f34068fd9cf7474962c3602dcfcb50039f43e3d6f
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp
new file mode 100644
index 0000000000..0e56a03d42
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 4ae701103c63deca5b5a3939d7d05992
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 02209f55
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 9a04c241
+Result = Fail
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = f5f915df
+Result = Fail
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 7a3c3499
+Result = Fail
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = f09c2986
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 4ae97e71
+Result = Fail
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = ecb38c8b
+Result = Fail
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 9c4dc530
+Result = Fail
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 67299ef6
+Result = Fail
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = b0538d02
+Result = Fail
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 88200ea8
+Result = Fail
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 19867aa5
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 3b392a52
+Result = Pass
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 1c5e47e0
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 97a56b8b
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 75d582db43ce9b13ab4b6f7f14341330
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 3a65e03af37b81d05acc7ec1bc39deb0
+Result = Fail
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = efc5721e0b9e4c3c90deab0e1d5c11bd
+Result = Fail
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 91b4b779823f4f0e3979ced93b99736c
+Result = Fail
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = e2e87ca82523ccfeb416b42af9d9aadc
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 7b85fd105cc960df86ad86846d178274
+Result = Fail
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = ffa140be27b25f307a6efd9697d66c9b
+Result = Fail
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ed356542e0a804a724bfaa422e98a970
+Result = Fail
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = e31dd8dc920fe7900e1b1817fe845c7d
+Result = Fail
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = ae5a0777f03bbf541f305d00acff0396
+Result = Fail
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 957dca58616c1cbe99f94fd8f7c257d9
+Result = Fail
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 0e150af422f6da238bb476810b2d5bc2
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 8e1150756ff3a733a1274470f072b74c
+Result = Pass
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = a1f70df3fa9cfeb95f869b3fe08466e0
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = fdf3f6c177aa1d71fe3474a5a2eb6bb1
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 90156f3f
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 88909016
+Result = Fail
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = de547d03
+Result = Fail
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = ea4bad52
+Result = Fail
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 1bc82b3d
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 92e72250
+Result = Fail
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = e81f0647
+Result = Fail
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7cb906ec
+Result = Fail
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = d60f815b
+Result = Fail
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d3d4f3b0
+Result = Fail
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = a9df97ad
+Result = Fail
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 36a37a59
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = dba02a36
+Result = Pass
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 25dcb3c5
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 1d2832d0
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fb04dc5a44c6bb000f2440f5154364b4
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 5447075bf42a59b91f08064738b015ab
+Result = Fail
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = fdc992847f0815fac67aa935b35208ed
+Result = Fail
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 2cabd690a45e59854b7587b26dd77f8e
+Result = Fail
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 3dacc71169f6da77ec91ff1d2f649ed1
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 97a2eb170ef03fa12124f1315e3b694f
+Result = Fail
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 94d85a83169d8dc76f58baf4d63ecfee
+Result = Fail
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = d3903c6289ca3684b8ce1174c23153a4
+Result = Fail
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 5cbac5c418374a68bd7085454c4b0c13
+Result = Fail
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = 26317f6b8b0130097441ed04b8009aef
+Result = Fail
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = b82ab6f3bbf59b6caafc54f05570f74e
+Result = Fail
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 1ae34207e74c8c78890ae17e320e84bd
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 5c5fa254c0be503b02caffade6b85259
+Result = Pass
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 9340266730ea36207bb734819d3553e9
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = ec17cccf33bd9a0d4ce7aa20690c1333
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = a90e8ea44085ced791b2fdb7fd44b5cf0bd7d27718029bb703e1fa6b
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 50aafe0578c115c4a8e126ff7b3ccb64dce8ccaa8ceda69f23e5d81c
+Result = Fail
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 512ed208bf10d57406537e94d20a5b6e2e9ab0683dfdc685869a97f0
+Result = Fail
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = af72db9cd9d6f46607d6f9542ca69988dd15255c5c91171c838e7f95
+Result = Fail
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 47d71409a03c330be9451b3f92c9d21c584391ad1010e9d609b89801
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = e562c7af0384ea16431ca20934a293a058d722cbfc3186c8eaf5f825
+Result = Fail
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = 004d9d89c401aa79919c2805fcd5de69316e191df56426c05ec1aa6a
+Result = Fail
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = d623673d7f6d57c208bde112ca858561f3af5cc2bf5de926f3586c6f
+Result = Fail
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = fd4733d158b5630f4f6c03ab26b11bff0cbe0d5d3df99a735fa40618
+Result = Fail
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = d352cb996c3075ff367a8dcacbbae46a12fbef08aa96ec835bf4f930
+Result = Fail
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 31730fac20e21eca0aef591faa9fa90b3c058e32af1ce48a66f0496e
+Result = Fail
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = dd175905a7ea3aef9fce068e6cb78e9cc60519755a178c77b753181c
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 8ad6b76f54392ee0f2834f09142545bcde9bf03d04d64aa10876f2da
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = 808eb3e04c39abde64674f0f7716dde11699cff8dd367c4cd4f7fc07
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e074d13aad43f7b2364d47db0a02326641ca3b2ad61a1c49973a2712
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 24ab9eeb0e5508cae80074f1070ee188a637171860881f1f2d9a3fbc210595b7b8b1b41523111a8e
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 7ebfda6fa5da1dbffd82dc29b875798fbcef8ba0084fbd2463af747cc88a001fa94e060290f209c4
+Result = Fail
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = cbf133643851f91ddc7a1e19a0c21990459f2b7728da58f5cf3b8e6c8aeb5eeb0a5efb3700be45a2
+Result = Fail
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0de7567a945c0af4a2291a651de411e8d0438508f2d4da80f7bd61a0158accbca28913e39fe80906
+Result = Fail
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = d43035cdb5a1868aa430e8b41a1dc57a639087238e38bd628feeda2e8f249dd93a8358def7639875
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 389547260b354a6cbc909de057d367677049e80613877f6fbf19f89da977e56f308373c616299ad4
+Result = Fail
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = a95aa33483ed3711470025394616bf98fe624fbca8aa6fbc21366b9da457ede2a673351475b53d41
+Result = Fail
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3d53b6ab8925f429ae14a0065cd203d4f9deddd402a79ac6d889a7cae55efd71b369cd6d43ef363b
+Result = Fail
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = d5e6e82cb5f8034a89e58adf8298476253f18981bcb3b0364be7f19463dd330a4b9f3cbb30b88fa5
+Result = Fail
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 02f69107d62ff77145c7d57684c70ba671d55f1c63bb2ad8c2df063f7fdbae27f0736a37fd065fb4
+Result = Fail
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 64ec2f321111da9c5389e8255bfe69876d4f548f94cacd529b45d54cc24cff1b1d8aa1df32fbd81a
+Result = Fail
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 37d63c2bbf44d2eb155ecc1a844841d5c33f1a6d443419330217a4f1f4fb302257b0de7c9da2e750
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 33e0dce4410e51bed5323ea49490207084ac91732bae429236a305d520a1a24930a70a311aa3695d
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 1d732c334319bd775e7cf93dbdc4204bbdb58192be08280481e3d64ed546b6b70ee088a693f55fbb
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = c92fc2f0d24593f67d9c09d326158a8138237c4096093f0d737719dd84ccfb397a4f61b70c85262a
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4a550134f94455979ec4bf89ad2bd80d25a77ae94e456134a3e138b9
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 118ec53dd1bfbe52d5b9fe5dfebecf2ee674ec983eada654091a5ae9
+Result = Fail
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 6b0fea26e4dfe902b5e876c7ba92afbad8aa52d3c1d00ae578b6bcc4
+Result = Fail
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 640c740e2b8af851712a05948ecee055b25b145ccb82ca58ac542b09
+Result = Fail
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 05f20b2ae70fcb0ea79aa1845c15b899a799ca60f51e6c296413020a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 9fa576a8a5c72468afa372338cbbc33fef81ad5a873eb38a142d5636
+Result = Fail
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = 8d26582c74b2b4d960ee9e417c6395daafaebb3aff45d477f3757b6a
+Result = Fail
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = cb62a13e38e17cc6635e409c922956ece38f593189a51b99a7001a16
+Result = Fail
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f3e29b792423c7fbe743a3b2f890a2bff29519f3636a6232050e9225
+Result = Fail
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 136e60d6714d906d1f4c02b7bdbb5f3ccdd2165306912dec850ec9f0
+Result = Fail
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 49b6d0b6eeff74af0de70072d9ccdc68a0ee36a5ddbf098b4eb95533
+Result = Fail
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = a2a59041c3f78f6e10c3045118e8a475945e24c85b02abc40f8fb949
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 19b4ad222795326cb031cfdb07b652dbf64ca5db5ff5d6d569d8ab41
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 76b66b908657f4df8a329c34ccdde50ae7fc71c4a718b712f00fe764
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 20df4662ce6c8c4ce49b14fa791e41ff8598ec93d8a825e879f9eb72
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4bfe4e35784f0a65b545477e5e2f4bae0e1e6fa717eaf2cb6a9a970b9beb2ac1bd4fd62168f8378a
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 0c56a503aa2c12e87450d45a7b714db980fd348f327c0065a65666144994bad0c8195bcb4ade1337
+Result = Fail
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 5f69d6c21f771eb98dc724f891f530b1c045f49a054de103a85f868739404b64a7cbdd61b577c388
+Result = Fail
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = d335ba572520c336f711edf27ea738ba5e6b0d772ea443b8b2b164f3c255b699cbf75330d96c3c13
+Result = Fail
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 9fa846ef8d198c538f84f856bab8f7f9c3bed90b53acb6a32658e077687315eaf11458bdf6e3c36a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = b7095030acdc5fbb8fea2c24717c1c236231f9737bcc78f463db3756abba1feef626a956794d7e56
+Result = Fail
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = d6911d5831163c8ebad0916af1833051b885aae822f9f6657d6fee1de626bc7c93f2caa27a3ecaa0
+Result = Fail
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 6b10a098c96c2bbf9aeb5c9adcf91e4812838dff319f8be989e2d235192f33ba0f357492112d98f4
+Result = Fail
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = aecd11cbac04e1f79b0fd24052c8cedf393dce9df350d24f800b81e834ea5dd2bdc2c688d9505359
+Result = Fail
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = d3a7a25f71b1988482dc852ed713d55abdcc4bb1129ddcae430889cd5c97343cc0dedfbd62e6b6eb
+Result = Fail
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 368e1574a433d78d0276ce4a1cacfba834a216693536c00b15acded53c41010554e1c1fe937a7605
+Result = Fail
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 99e40b3c67aca95dd4462c20cbd6b2741e7033fc4f41a975c9390fbdb9ec416267096ccbf2c148e5
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = de079418c25ba67e5fda009998e3fce61bfdc3b7787cf06655c18ae38b7ee7f00f96cfca4fe9a2ef
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = fbab64d8dd8b6e33c7cc6124cd65f004d7247277fe98d5d3b35357a35ff9e58e18d6d80df9fc335d
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 372b9af0655df2d0c830b4949a2d2faa8db251ee922a3bff9aba89639f4033be9ba9f3c101acc1bd
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 782e4318
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = a04f270a
+Result = Fail
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 97dfd257
+Result = Fail
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 6c202a1c
+Result = Fail
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 1be535a0
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 4fb6617d
+Result = Fail
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = c056bd3e
+Result = Fail
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 87048576
+Result = Fail
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = ea8c0407
+Result = Fail
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 41c12dc5
+Result = Fail
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = de84cf5c
+Result = Fail
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = e617e006
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = b7909395
+Result = Pass
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 8a05d2ea
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 8643ba47
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 41b476013f45e4a781f253a6f3b1e530
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = f9f018fcd125822616083fffebc4c8e6
+Result = Fail
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 534cc67c44c877c9c908071ee1082f4c
+Result = Fail
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 201c0ef2ddaa51b645911b5c37d76e95
+Result = Fail
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = ec774d9000763bba3a5ac307418827b2
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 75798c3fe5202f0e33c9183c837aeaf5
+Result = Fail
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 32601de5960c11c925444b5c47d42289
+Result = Fail
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 4c1cd6a774c8e6f4e261db1f73b0aa20
+Result = Fail
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 8bd9c00ff23310216bbd24981c1e2cf7
+Result = Fail
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 174efd089409f9932b8e631965e762a6
+Result = Fail
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 8de80f620bd41eee6a58925dc8404bfa
+Result = Fail
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 0b9d79e8e33ec45532af5515a99f05df
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 1583e1e5a86001bbcec62292ccfd4d48
+Result = Pass
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = b72caac6362e68e445f69f605f21e0a2
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 352769a19ac75b8a116be031b33d6449
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 9f69f24f
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = e17afaa4
+Result = Fail
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 07155b7e
+Result = Fail
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = d538cf2f
+Result = Fail
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = c283466f
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = aa8d8098
+Result = Fail
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = a44b69b0
+Result = Fail
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = f395733f
+Result = Fail
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 1e9e9237
+Result = Fail
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = e9d2a722
+Result = Fail
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = a90fc438
+Result = Fail
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = 48f3a1ec
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 24763def
+Result = Pass
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 63394bee
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = d79b1686
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 1859ac36a40a6b28b34266253627797a
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = edf8b46eb69ac0044116019dec183072
+Result = Fail
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 66622ac26c7227a0329739612012737c
+Result = Fail
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = e4c9e86493ee78b1cbf6e55e94731b63
+Result = Fail
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = 8b5bfe6b5b5552007300bae71172612f
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1848be3cb7665ac68874c617a75d8bd2
+Result = Fail
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 65a23b7b5ee78af9c7d0113447f78ab9
+Result = Fail
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 90a420b6d2252392e161dcf4fb953d7e
+Result = Fail
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 004cbe11292887e246de7704a4a1a05f
+Result = Fail
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = ad7af41e39ea0c0cd072263e826f3cf0
+Result = Fail
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 16b1a4fadbadc906a949592d6ef319a3
+Result = Fail
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = e9cfb1069380434f221db4229a083a76
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 380cb57fd531bb1dcf22350518bbf8af
+Result = Pass
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = fbf2becc35b5024078bfcfc1f831b669
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 080203eb842b3f98a730abbbf98f493e
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6be31860ca271ef448de8f8d8b39346daf4b81d7e92d65b338f125fa
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4cc57a9927a6bc401441870d3193bf89ebd163f5c01501c728a66b69
+Result = Fail
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 1f16c6d370fff40c011a243356076b67e905d4672ae2f38fee2de18c
+Result = Fail
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 46edb001d58a01dce1bcf064cfc9a04accc82c42b33ba16524537a81
+Result = Fail
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 9b61335f96fc5b31274cc1fb275f29c1105d68c67b70654f9405edb1
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 97b5eb2d55847f5d5d9f8c762dace481d8efb19ccfd72265548effe3
+Result = Fail
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = f5cc8198dce8e890587b62572b07413a915bfb55628c901c03459b29
+Result = Fail
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 50c0b1f6c5e4c86a0c938ecbc762eeaf99b9fe04c2820a43963b04f3
+Result = Fail
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 1fdbe91189da01c5098cf1538addd85b1cfef0abd0797c141330f633
+Result = Fail
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = 462e7cdf9a6a553bca37d4d93bed4986b715d0349238613e10c1f6d7
+Result = Fail
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 7d142f26aa6c9d55850c5c9f58ab36a66670d47c515bf93cd37e5543
+Result = Fail
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = f7122cbcec93d53fc7e3fc629ea15d28363cad1c83a23bb3cc5e0c4a
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = e1cad7f946b20c373323218c8a89e56edf3030662e50d459fc12a512
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = d4741814466a23e26107d773f103a4c83db9d772dbd5fdc1c2eaf895
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = ed35ff66bc7f6d8ec7acf896f994d79f5792cf6d22d6691ff92fa2f7
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = b351ab96b2e45515254558d5212673ee6c776d42dbca3b512cf3a20b7fd7c49e6e79bef475c2906f
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = df1a5285caa41b4bb47f6e5ceceba4e82721828d68427a3081d18ca149d6766bfaccec88f194eb5b
+Result = Fail
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 04a29fc109dfc626e8297e0f586d0bfaf31260017d95f62d5eb4f0875dda5ccd9b94026ba49fb34e
+Result = Fail
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 77e4cd5d319353ecb6b89e2de14bcfee4fbf738b61df14f3920843994def41aed3103995d3392eed
+Result = Fail
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = e676f5dfde8ad810d9e729d142670eef77f2878369a28797d57603d5c45606c68be5535c671d5432
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 60c51e5c3fe4197454d64fa14017639bcfd1423b9d74e506a0bfd54fb786208e1e49c6d0e645d9fb
+Result = Fail
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 64d1160365062eca1027cc7036862b027bdda3a9abdf794daf8a9b7a5c50b0be4596290a4d405e79
+Result = Fail
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 968ca115583c645710d2b47fb196cf55f6ef33f2b01400e22ce9c776932ecf7fddd849be58096b88
+Result = Fail
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 4985821b16ff6d4d3416573e2fba4d53186d912f0b023a99915d0020da92f483a5a7914cba14b1e7
+Result = Fail
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = c7345b031ef85bde766226a7603adaa7dcb07a7b2a8be1b571420e036ea48dddd671be622d372c5b
+Result = Fail
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 11460b9acccc13001be236814da6b73f2c8e0467574f151bb619a331f8d67d70c3f3a59b3fab53a5
+Result = Fail
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 1bcff940a2d9d48e93bbfd13aed5947237485983e6ae04b8b944bb46306a9b1e783f3e54c92d5f5e
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = 3b6c1570c85f297079be14cd66d335251c7b52e131a636f148608963f3037763843b70c35d7011f8
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = b540cd8cbe733e0ca2ba2112ea785596d2c1d707f41608514ba2d0944c68cc36d4125b3ef9071d69
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 3c9c1481f1428acf202b510dca67e5e6b2abc5dd71a954da51387922af7182b7d46a33c703e6e7a8
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 934f893824e880f743d196b22d1f340a52608155087bd28ac25e5329
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = f43ba9d834ad85dfab3f1c0c27c3441fe4e411a38a261a6559b3b3ee
+Result = Fail
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = c686eac859a7bae3cce97d0b6527a0a7c8c2b24ece35f4370bf6688e
+Result = Fail
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 2b28355ecf7246ddb08d65c464dcaa90af85f434ff95267280ed869c
+Result = Fail
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = ecde42091baa1f5c17b79746e21c3de5c78984570748021ccd399507
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 5c338435ed4f148342604c9aed63e907c100453d719fda2a3da37b66
+Result = Fail
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 30eac1042015eb82729673edd9939bf9995b2575da4d6c4c7e75dded
+Result = Fail
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = ebd3ce55b40e4bbd8172033948c6c78049161ee8f949eb50722b9c87
+Result = Fail
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 20f79b36ca83baac97600fd8a6dad22c2cd0f9b7e770576048c042e5
+Result = Fail
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 77b76f249f936fb19bd47fe28ad4dbb7725dec365a1cb23a885ba975
+Result = Fail
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = cf6763a23c2eab730845d1eb79bbba9f54ee899fe3d70570aa799e79
+Result = Fail
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 1f8086a43c1b2dea557952db88e0dbbdb96aafdb345eddae6c0b0104
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = c0c5f92285b114e0a0777e1bc22b810e7cc4f68c28cd5ce047a28dd8
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 56327f4db9c18f72bbefc3f316d31f9795dd77f493385ab7b7543552
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 37d5b17995fac8c94302ec9ba20a36d97678e85199b677f8ee39867e
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0e
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 50038b5fdd364ee747b70d00bd36840ece4ea19998123375c0a458bfcafa3b2609afe0f825cbf503
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = 78ed8ff6b5a1255d0fbd0a719a9c27b059ff5f83d0c4962c390042ba8bb5f6798dab01c5afad7306
+Result = Fail
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 4b91d8e616d3f60452fd3a576bd7c265b7f549523ed4a5d7a3463394cf3c25bef8af8f244d0c0b00
+Result = Fail
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = ab8cf8891ab62924c0c6f49dd253cfa0c3d6260d0ee4d9ba88caf8ae59d9d1131626da0dddf8722d
+Result = Fail
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = c6b7680f321132a8bd00e8e92f785d0b828b100af6392a04d1292373a76970eda77a8194f6276262
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = aea98867d3d707c43a963c1d7fdcfc953cbd707803b2b5f0a97af19d0b7bf7c7ce398cb0b44d73af
+Result = Fail
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = c55e17ba7886eb58126d50bde8c5c211cc1aafd71a3d9e5b343065b4bdd973ee072dbf5160d310f3
+Result = Fail
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 791a62d5fb39ff9735ad94507e1afe2647714d5cc56b6ff4233ec600bca1d31f704807494fb0f18d
+Result = Fail
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = f98a081998e29500f15ebd8978a95423aed4e8e78e0279d17ec183db0e2a33ebb147d0e2363fbb01
+Result = Fail
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 7779814dc295a23b4100ca94bec0ad4ce2f6be6fb75a0c217e67ea2577ade5836c26a89760e0959b
+Result = Fail
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 55640eed12c7595a36ab423da8d8241905b6ff1e906db9624978a7865df8369635269411b3aaeb32
+Result = Fail
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 7fcdce0ba567b9a708d54fdb16125de71dce952f4741684f4f9d302e4f1d2a2aedf2768d7b29163f
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = d42111ba22987eac1ead5cc6cb8548bcda190d118dcd5461a50036af67fadab163e9daa8bd8e9030
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d2f1322ac69b848b001476323aed84c47
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 9d993b945476ace0b9ca932963ac8835e1bd02e8065da2d816786c4d8cf14c03b031ff723311b3c4
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt
new file mode 100644
index 0000000000..1606dcb21e
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT128.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 4ae701103c63deca5b5a3939d7d05992
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 02209f55
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 9a04c241
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = f5f915df
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 7a3c3499
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = f09c2986
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 4ae97e71
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = ecb38c8b
+Result = Fail (1 - Adata changed)
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 9c4dc530
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 67299ef6
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = b0538d02
+Result = Fail (1 - Adata changed)
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 88200ea8
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 19867aa5
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 3b392a52
+Result = Pass (0)
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 1c5e47e0
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 97a56b8b
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 75d582db43ce9b13ab4b6f7f14341330
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 3a65e03af37b81d05acc7ec1bc39deb0
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = efc5721e0b9e4c3c90deab0e1d5c11bd
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 91b4b779823f4f0e3979ced93b99736c
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = e2e87ca82523ccfeb416b42af9d9aadc
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 7b85fd105cc960df86ad86846d178274
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = ffa140be27b25f307a6efd9697d66c9b
+Result = Fail (1 - Adata changed)
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ed356542e0a804a724bfaa422e98a970
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = e31dd8dc920fe7900e1b1817fe845c7d
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = ae5a0777f03bbf541f305d00acff0396
+Result = Fail (1 - Adata changed)
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 957dca58616c1cbe99f94fd8f7c257d9
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 0e150af422f6da238bb476810b2d5bc2
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 8e1150756ff3a733a1274470f072b74c
+Result = Pass (0)
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = a1f70df3fa9cfeb95f869b3fe08466e0
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = fdf3f6c177aa1d71fe3474a5a2eb6bb1
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 90156f3f
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 88909016
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = de547d03
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = ea4bad52
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 1bc82b3d
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 92e72250
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = e81f0647
+Result = Fail (1 - Adata changed)
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7cb906ec
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = d60f815b
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d3d4f3b0
+Result = Fail (1 - Adata changed)
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = a9df97ad
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 36a37a59
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = dba02a36
+Result = Pass (0)
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 25dcb3c5
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 1d2832d0
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fb04dc5a44c6bb000f2440f5154364b4
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 5447075bf42a59b91f08064738b015ab
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = fdc992847f0815fac67aa935b35208ed
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 2cabd690a45e59854b7587b26dd77f8e
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 3dacc71169f6da77ec91ff1d2f649ed1
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 97a2eb170ef03fa12124f1315e3b694f
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 94d85a83169d8dc76f58baf4d63ecfee
+Result = Fail (1 - Adata changed)
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = d3903c6289ca3684b8ce1174c23153a4
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 5cbac5c418374a68bd7085454c4b0c13
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = 26317f6b8b0130097441ed04b8009aef
+Result = Fail (1 - Adata changed)
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = b82ab6f3bbf59b6caafc54f05570f74e
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 1ae34207e74c8c78890ae17e320e84bd
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 5c5fa254c0be503b02caffade6b85259
+Result = Pass (0)
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 9340266730ea36207bb734819d3553e9
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = ec17cccf33bd9a0d4ce7aa20690c1333
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = a90e8ea44085ced791b2fdb7fd44b5cf0bd7d27718029bb703e1fa6b
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 50aafe0578c115c4a8e126ff7b3ccb64dce8ccaa8ceda69f23e5d81c
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 512ed208bf10d57406537e94d20a5b6e2e9ab0683dfdc685869a97f0
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = af72db9cd9d6f46607d6f9542ca69988dd15255c5c91171c838e7f95
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 47d71409a03c330be9451b3f92c9d21c584391ad1010e9d609b89801
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = e562c7af0384ea16431ca20934a293a058d722cbfc3186c8eaf5f825
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = 004d9d89c401aa79919c2805fcd5de69316e191df56426c05ec1aa6a
+Result = Fail (1 - Adata changed)
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = d623673d7f6d57c208bde112ca858561f3af5cc2bf5de926f3586c6f
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = fd4733d158b5630f4f6c03ab26b11bff0cbe0d5d3df99a735fa40618
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = d352cb996c3075ff367a8dcacbbae46a12fbef08aa96ec835bf4f930
+Result = Fail (1 - Adata changed)
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 31730fac20e21eca0aef591faa9fa90b3c058e32af1ce48a66f0496e
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = dd175905a7ea3aef9fce068e6cb78e9cc60519755a178c77b753181c
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 8ad6b76f54392ee0f2834f09142545bcde9bf03d04d64aa10876f2da
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = 808eb3e04c39abde64674f0f7716dde11699cff8dd367c4cd4f7fc07
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e074d13aad43f7b2364d47db0a02326641ca3b2ad61a1c49973a2712
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 24ab9eeb0e5508cae80074f1070ee188a637171860881f1f2d9a3fbc210595b7b8b1b41523111a8e
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 7ebfda6fa5da1dbffd82dc29b875798fbcef8ba0084fbd2463af747cc88a001fa94e060290f209c4
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = cbf133643851f91ddc7a1e19a0c21990459f2b7728da58f5cf3b8e6c8aeb5eeb0a5efb3700be45a2
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0de7567a945c0af4a2291a651de411e8d0438508f2d4da80f7bd61a0158accbca28913e39fe80906
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = d43035cdb5a1868aa430e8b41a1dc57a639087238e38bd628feeda2e8f249dd93a8358def7639875
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 389547260b354a6cbc909de057d367677049e80613877f6fbf19f89da977e56f308373c616299ad4
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = a95aa33483ed3711470025394616bf98fe624fbca8aa6fbc21366b9da457ede2a673351475b53d41
+Result = Fail (1 - Adata changed)
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3d53b6ab8925f429ae14a0065cd203d4f9deddd402a79ac6d889a7cae55efd71b369cd6d43ef363b
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = d5e6e82cb5f8034a89e58adf8298476253f18981bcb3b0364be7f19463dd330a4b9f3cbb30b88fa5
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 02f69107d62ff77145c7d57684c70ba671d55f1c63bb2ad8c2df063f7fdbae27f0736a37fd065fb4
+Result = Fail (1 - Adata changed)
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 64ec2f321111da9c5389e8255bfe69876d4f548f94cacd529b45d54cc24cff1b1d8aa1df32fbd81a
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 37d63c2bbf44d2eb155ecc1a844841d5c33f1a6d443419330217a4f1f4fb302257b0de7c9da2e750
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 33e0dce4410e51bed5323ea49490207084ac91732bae429236a305d520a1a24930a70a311aa3695d
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 1d732c334319bd775e7cf93dbdc4204bbdb58192be08280481e3d64ed546b6b70ee088a693f55fbb
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = c92fc2f0d24593f67d9c09d326158a8138237c4096093f0d737719dd84ccfb397a4f61b70c85262a
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d5243
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4a550134f94455979ec4bf89ad2bd80d25a77ae94e456134a3e138b9
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 118ec53dd1bfbe52d5b9fe5dfebecf2ee674ec983eada654091a5ae9
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 6b0fea26e4dfe902b5e876c7ba92afbad8aa52d3c1d00ae578b6bcc4
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 640c740e2b8af851712a05948ecee055b25b145ccb82ca58ac542b09
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 05f20b2ae70fcb0ea79aa1845c15b899a799ca60f51e6c296413020a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 9fa576a8a5c72468afa372338cbbc33fef81ad5a873eb38a142d5636
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = 8d26582c74b2b4d960ee9e417c6395daafaebb3aff45d477f3757b6a
+Result = Fail (1 - Adata changed)
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = cb62a13e38e17cc6635e409c922956ece38f593189a51b99a7001a16
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f3e29b792423c7fbe743a3b2f890a2bff29519f3636a6232050e9225
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 136e60d6714d906d1f4c02b7bdbb5f3ccdd2165306912dec850ec9f0
+Result = Fail (1 - Adata changed)
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 49b6d0b6eeff74af0de70072d9ccdc68a0ee36a5ddbf098b4eb95533
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = a2a59041c3f78f6e10c3045118e8a475945e24c85b02abc40f8fb949
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 19b4ad222795326cb031cfdb07b652dbf64ca5db5ff5d6d569d8ab41
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 76b66b908657f4df8a329c34ccdde50ae7fc71c4a718b712f00fe764
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 20df4662ce6c8c4ce49b14fa791e41ff8598ec93d8a825e879f9eb72
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 4bfe4e35784f0a65b545477e5e2f4bae0e1e6fa717eaf2cb6a9a970b9beb2ac1bd4fd62168f8378a
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 0c56a503aa2c12e87450d45a7b714db980fd348f327c0065a65666144994bad0c8195bcb4ade1337
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = 5f69d6c21f771eb98dc724f891f530b1c045f49a054de103a85f868739404b64a7cbdd61b577c388
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = d335ba572520c336f711edf27ea738ba5e6b0d772ea443b8b2b164f3c255b699cbf75330d96c3c13
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 9fa846ef8d198c538f84f856bab8f7f9c3bed90b53acb6a32658e077687315eaf11458bdf6e3c36a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = b7095030acdc5fbb8fea2c24717c1c236231f9737bcc78f463db3756abba1feef626a956794d7e56
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = d6911d5831163c8ebad0916af1833051b885aae822f9f6657d6fee1de626bc7c93f2caa27a3ecaa0
+Result = Fail (1 - Adata changed)
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 6b10a098c96c2bbf9aeb5c9adcf91e4812838dff319f8be989e2d235192f33ba0f357492112d98f4
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = aecd11cbac04e1f79b0fd24052c8cedf393dce9df350d24f800b81e834ea5dd2bdc2c688d9505359
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = d3a7a25f71b1988482dc852ed713d55abdcc4bb1129ddcae430889cd5c97343cc0dedfbd62e6b6eb
+Result = Fail (1 - Adata changed)
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 368e1574a433d78d0276ce4a1cacfba834a216693536c00b15acded53c41010554e1c1fe937a7605
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 99e40b3c67aca95dd4462c20cbd6b2741e7033fc4f41a975c9390fbdb9ec416267096ccbf2c148e5
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = de079418c25ba67e5fda009998e3fce61bfdc3b7787cf06655c18ae38b7ee7f00f96cfca4fe9a2ef
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = fbab64d8dd8b6e33c7cc6124cd65f004d7247277fe98d5d3b35357a35ff9e58e18d6d80df9fc335d
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 372b9af0655df2d0c830b4949a2d2faa8db251ee922a3bff9aba89639f4033be9ba9f3c101acc1bd
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe4829
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 782e4318
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = a04f270a
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 97dfd257
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 6c202a1c
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 1be535a0
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 4fb6617d
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = c056bd3e
+Result = Fail (1 - Adata changed)
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 87048576
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = ea8c0407
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 41c12dc5
+Result = Fail (1 - Adata changed)
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = de84cf5c
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = e617e006
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = b7909395
+Result = Pass (0)
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 8a05d2ea
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 8643ba47
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 41b476013f45e4a781f253a6f3b1e530
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = f9f018fcd125822616083fffebc4c8e6
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 534cc67c44c877c9c908071ee1082f4c
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 201c0ef2ddaa51b645911b5c37d76e95
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = ec774d9000763bba3a5ac307418827b2
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 75798c3fe5202f0e33c9183c837aeaf5
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 32601de5960c11c925444b5c47d42289
+Result = Fail (1 - Adata changed)
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 4c1cd6a774c8e6f4e261db1f73b0aa20
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 8bd9c00ff23310216bbd24981c1e2cf7
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 174efd089409f9932b8e631965e762a6
+Result = Fail (1 - Adata changed)
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 8de80f620bd41eee6a58925dc8404bfa
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 0b9d79e8e33ec45532af5515a99f05df
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 1583e1e5a86001bbcec62292ccfd4d48
+Result = Pass (0)
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = b72caac6362e68e445f69f605f21e0a2
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 352769a19ac75b8a116be031b33d6449
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 9f69f24f
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = e17afaa4
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 07155b7e
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = d538cf2f
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = c283466f
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = aa8d8098
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = a44b69b0
+Result = Fail (1 - Adata changed)
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = f395733f
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 1e9e9237
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = e9d2a722
+Result = Fail (1 - Adata changed)
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = a90fc438
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = 48f3a1ec
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 24763def
+Result = Pass (0)
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 63394bee
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = d79b1686
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 1859ac36a40a6b28b34266253627797a
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = edf8b46eb69ac0044116019dec183072
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 66622ac26c7227a0329739612012737c
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = e4c9e86493ee78b1cbf6e55e94731b63
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = 8b5bfe6b5b5552007300bae71172612f
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1848be3cb7665ac68874c617a75d8bd2
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 65a23b7b5ee78af9c7d0113447f78ab9
+Result = Fail (1 - Adata changed)
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 90a420b6d2252392e161dcf4fb953d7e
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 004cbe11292887e246de7704a4a1a05f
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = ad7af41e39ea0c0cd072263e826f3cf0
+Result = Fail (1 - Adata changed)
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 16b1a4fadbadc906a949592d6ef319a3
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = e9cfb1069380434f221db4229a083a76
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 380cb57fd531bb1dcf22350518bbf8af
+Result = Pass (0)
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = fbf2becc35b5024078bfcfc1f831b669
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 080203eb842b3f98a730abbbf98f493e
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c7571
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6be31860ca271ef448de8f8d8b39346daf4b81d7e92d65b338f125fa
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4cc57a9927a6bc401441870d3193bf89ebd163f5c01501c728a66b69
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 1f16c6d370fff40c011a243356076b67e905d4672ae2f38fee2de18c
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 46edb001d58a01dce1bcf064cfc9a04accc82c42b33ba16524537a81
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 9b61335f96fc5b31274cc1fb275f29c1105d68c67b70654f9405edb1
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 97b5eb2d55847f5d5d9f8c762dace481d8efb19ccfd72265548effe3
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = f5cc8198dce8e890587b62572b07413a915bfb55628c901c03459b29
+Result = Fail (1 - Adata changed)
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 50c0b1f6c5e4c86a0c938ecbc762eeaf99b9fe04c2820a43963b04f3
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 1fdbe91189da01c5098cf1538addd85b1cfef0abd0797c141330f633
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = 462e7cdf9a6a553bca37d4d93bed4986b715d0349238613e10c1f6d7
+Result = Fail (1 - Adata changed)
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 7d142f26aa6c9d55850c5c9f58ab36a66670d47c515bf93cd37e5543
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = f7122cbcec93d53fc7e3fc629ea15d28363cad1c83a23bb3cc5e0c4a
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = e1cad7f946b20c373323218c8a89e56edf3030662e50d459fc12a512
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = d4741814466a23e26107d773f103a4c83db9d772dbd5fdc1c2eaf895
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = ed35ff66bc7f6d8ec7acf896f994d79f5792cf6d22d6691ff92fa2f7
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = b351ab96b2e45515254558d5212673ee6c776d42dbca3b512cf3a20b7fd7c49e6e79bef475c2906f
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = df1a5285caa41b4bb47f6e5ceceba4e82721828d68427a3081d18ca149d6766bfaccec88f194eb5b
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 04a29fc109dfc626e8297e0f586d0bfaf31260017d95f62d5eb4f0875dda5ccd9b94026ba49fb34e
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 77e4cd5d319353ecb6b89e2de14bcfee4fbf738b61df14f3920843994def41aed3103995d3392eed
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = e676f5dfde8ad810d9e729d142670eef77f2878369a28797d57603d5c45606c68be5535c671d5432
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 60c51e5c3fe4197454d64fa14017639bcfd1423b9d74e506a0bfd54fb786208e1e49c6d0e645d9fb
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 64d1160365062eca1027cc7036862b027bdda3a9abdf794daf8a9b7a5c50b0be4596290a4d405e79
+Result = Fail (1 - Adata changed)
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 968ca115583c645710d2b47fb196cf55f6ef33f2b01400e22ce9c776932ecf7fddd849be58096b88
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 4985821b16ff6d4d3416573e2fba4d53186d912f0b023a99915d0020da92f483a5a7914cba14b1e7
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = c7345b031ef85bde766226a7603adaa7dcb07a7b2a8be1b571420e036ea48dddd671be622d372c5b
+Result = Fail (1 - Adata changed)
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 11460b9acccc13001be236814da6b73f2c8e0467574f151bb619a331f8d67d70c3f3a59b3fab53a5
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 1bcff940a2d9d48e93bbfd13aed5947237485983e6ae04b8b944bb46306a9b1e783f3e54c92d5f5e
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = 3b6c1570c85f297079be14cd66d335251c7b52e131a636f148608963f3037763843b70c35d7011f8
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = b540cd8cbe733e0ca2ba2112ea785596d2c1d707f41608514ba2d0944c68cc36d4125b3ef9071d69
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 3c9c1481f1428acf202b510dca67e5e6b2abc5dd71a954da51387922af7182b7d46a33c703e6e7a8
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728c
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 934f893824e880f743d196b22d1f340a52608155087bd28ac25e5329
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = f43ba9d834ad85dfab3f1c0c27c3441fe4e411a38a261a6559b3b3ee
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = c686eac859a7bae3cce97d0b6527a0a7c8c2b24ece35f4370bf6688e
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 2b28355ecf7246ddb08d65c464dcaa90af85f434ff95267280ed869c
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = ecde42091baa1f5c17b79746e21c3de5c78984570748021ccd399507
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 5c338435ed4f148342604c9aed63e907c100453d719fda2a3da37b66
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 30eac1042015eb82729673edd9939bf9995b2575da4d6c4c7e75dded
+Result = Fail (1 - Adata changed)
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = ebd3ce55b40e4bbd8172033948c6c78049161ee8f949eb50722b9c87
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 20f79b36ca83baac97600fd8a6dad22c2cd0f9b7e770576048c042e5
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 77b76f249f936fb19bd47fe28ad4dbb7725dec365a1cb23a885ba975
+Result = Fail (1 - Adata changed)
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = cf6763a23c2eab730845d1eb79bbba9f54ee899fe3d70570aa799e79
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 1f8086a43c1b2dea557952db88e0dbbdb96aafdb345eddae6c0b0104
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = c0c5f92285b114e0a0777e1bc22b810e7cc4f68c28cd5ce047a28dd8
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 56327f4db9c18f72bbefc3f316d31f9795dd77f493385ab7b7543552
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 37d5b17995fac8c94302ec9ba20a36d97678e85199b677f8ee39867e
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0e
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 50038b5fdd364ee747b70d00bd36840ece4ea19998123375c0a458bfcafa3b2609afe0f825cbf503
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = 78ed8ff6b5a1255d0fbd0a719a9c27b059ff5f83d0c4962c390042ba8bb5f6798dab01c5afad7306
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 4b91d8e616d3f60452fd3a576bd7c265b7f549523ed4a5d7a3463394cf3c25bef8af8f244d0c0b00
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = ab8cf8891ab62924c0c6f49dd253cfa0c3d6260d0ee4d9ba88caf8ae59d9d1131626da0dddf8722d
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = c6b7680f321132a8bd00e8e92f785d0b828b100af6392a04d1292373a76970eda77a8194f6276262
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = aea98867d3d707c43a963c1d7fdcfc953cbd707803b2b5f0a97af19d0b7bf7c7ce398cb0b44d73af
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = c55e17ba7886eb58126d50bde8c5c211cc1aafd71a3d9e5b343065b4bdd973ee072dbf5160d310f3
+Result = Fail (1 - Adata changed)
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 791a62d5fb39ff9735ad94507e1afe2647714d5cc56b6ff4233ec600bca1d31f704807494fb0f18d
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = f98a081998e29500f15ebd8978a95423aed4e8e78e0279d17ec183db0e2a33ebb147d0e2363fbb01
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = 7779814dc295a23b4100ca94bec0ad4ce2f6be6fb75a0c217e67ea2577ade5836c26a89760e0959b
+Result = Fail (1 - Adata changed)
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 55640eed12c7595a36ab423da8d8241905b6ff1e906db9624978a7865df8369635269411b3aaeb32
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 7fcdce0ba567b9a708d54fdb16125de71dce952f4741684f4f9d302e4f1d2a2aedf2768d7b29163f
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = d42111ba22987eac1ead5cc6cb8548bcda190d118dcd5461a50036af67fadab163e9daa8bd8e9030
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 1bf0ba0ebb20d8edba59f29a9371750c9c714078f73c335d2f1322ac69b848b001476323aed84c47
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 9d993b945476ace0b9ca932963ac8835e1bd02e8065da2d816786c4d8cf14c03b031ff723311b3c4
+Result = Fail (2 - CT changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp
new file mode 100644
index 0000000000..e0978a99ac
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = c98ad7f38b2c7e970c9b965ec87a08208384718f78206c6c
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 9d4b7f3b
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 80745de9
+Result = Fail
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 2f6fa823
+Result = Fail
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 3cc132c6
+Result = Fail
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = c79d5557
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 41e0eea0
+Result = Fail
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = 1f129266
+Result = Fail
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 41b0e4e2
+Result = Fail
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 5082e06a
+Result = Fail
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = 70587cce
+Result = Fail
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6aaa0acd
+Result = Fail
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 22976e42
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = f440ea1d
+Result = Pass
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 88903fb9
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 3ff345c3
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 17223038fa99d53681ca1beabe78d1b4
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = d0e1eeef4d2a264536bb1c2c1bde7c35
+Result = Fail
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 81d587f8673fd514c23172af7fb7523d
+Result = Fail
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 500142447e535207899ab1499994daea
+Result = Fail
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = fdfdbb38bf161785114f9ee2018e892f
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 38fe9622eaa2a50152cf57e393dd3063
+Result = Fail
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = 73af4b87c167572e1400a0ee28209aff
+Result = Fail
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ace2248b9f23efa813449c82217e4a4a
+Result = Fail
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = a9bb0e469829d9cf09ad765c5b0b58bf
+Result = Fail
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = a5977f0826926ec0d32541b2bd4e2b1e
+Result = Fail
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6938fb5afec1a84e4abb062e1a943c20
+Result = Fail
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 7e3bbe0eb13988a93972f2fbcd35659e
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 48d7a15cf4f5808eb45d1ad817470554
+Result = Pass
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 97185ce68af1e6ab718c8c4b83ec04cd
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = a81bc8f5a18293ffe19505a3687ce3f3
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fe69ed84
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = db7ffc82
+Result = Fail
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 7a677329
+Result = Fail
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = d903d8f7
+Result = Fail
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 215e0bf2
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 0d38100f
+Result = Fail
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 9f8ab5f7
+Result = Fail
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7d811d50
+Result = Fail
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = c2e18439
+Result = Fail
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d8b5817b
+Result = Fail
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 28cd70ff
+Result = Fail
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 790b2624
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 9e46632d
+Result = Pass
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 39b82901
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 4c0cf71f
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 0c66a8e547ed4f8c2c9a9a1eb5d455b9
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 38757b3a61a4dc97ca3ab88bf1240695
+Result = Fail
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 11875da4445d92391d0fab5f3625497b
+Result = Fail
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 64477bcd4316e5c5789e1a678fdef943
+Result = Fail
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 87da5dbc04e39fc468f43675d4e7df33
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = bf0d53ee529d8cafc5ad7a8f2d85e7a2
+Result = Fail
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 676370637ad78c705d43fce066dc909f
+Result = Fail
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 289936db0f9f148a3c9e2d28f7d7de51
+Result = Fail
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 58a283641627669d5514f2af559b6c14
+Result = Fail
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = a6b058540ed905d6e3499a13ea1f3d83
+Result = Fail
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 7a19b3377384f09915d0e1ae93a9f16c
+Result = Fail
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = a0d047a1f9940d325e474da54aa13897
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 8a4768a2093694b6bcb7083c0bb6331c
+Result = Pass
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = a7cafd6f68dc1f15a3603da654ce27bc
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = c49845f2ea3c9981ad7e9b942f615b8d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 411986d04d6463100bff03f7d0bde7ea2c3488784378138cddc93a54
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 32b649ab56162e55d4148a1292d6a225a988eb1308298273b6889036
+Result = Fail
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = a963c3568ab413b174cd95cc1e3ca61ee181292bebdb28179b4de35f
+Result = Fail
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0396e6c8db43e5fac205f4c576fd577368adcb688cf3d7e76df9ffc5
+Result = Fail
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = b41bfba94edcafc41b4c144269b9126a6d47b19e83b15772b28c8e38
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 01e3bb938e16d0284d1d0fee049d80fb97356ae4d84127cf7336a30a
+Result = Fail
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = abd7551c5e84e9bef5fbfad3e24d13f02864410eae9177ad0c40cc72
+Result = Fail
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3b5ae49e0974f41826152432b46f1a85ab4995afefbbccddfc9fd290
+Result = Fail
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = 21fb4324de4ba1e2762b3041ce26e43a3d191458a046d489e485910b
+Result = Fail
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 99ca8f542fd06481e23719214c9892442f393d72899deea08695053f
+Result = Fail
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 5fcc05342cdc27f66b324ae7387205bfb4ab6302bfe0af09050d2054
+Result = Fail
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 0a7fe63046daf8a979935b897088c64acc1b47a5a9b86fdd6def28ab
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = daf7d7dfa512ceb1d7d3435634d9a70b3ef6c6dc38f409e068941fce
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = cdb417dff6502208775f21e35cdb8e3e1199308d1a94229051a1ec4a
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e75441093c8ccba6eac5913dc246ce96de4784a01051498298eaddaf
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = cba4b4aeb85f0492fd8d905c4a6d8233139833373ef188a8c5a5ebecf7ac8607fe412189e83d9d20
+Result = Pass
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = ca62713728b5c9d652504b0ae8fd4fee5d297ee6a8d19cb6e699f15f14d34dcaf9ba8ed4b877c97d
+Result = Fail
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 93012c0a5f6f1025b8c4a5d897d3eea0b1c77be8000c9e59f3b8899459788c58794f177cfd838f35
+Result = Fail
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = b8eb95f72f643c2c51ad74775cc203d215c86626e903eb013ad22e8fa4d2f9725ce4f212a8844855
+Result = Fail
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 71f17cf21c44267c676657db9e55bee33273787474e77b17b5eab45d7d096577643815e6d467312d
+Result = Pass
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = d6737f642260c4ee3b19cb78cc2ef1767213416b82c71e918b1a5ecca7354af824fea617b9b69031
+Result = Fail
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = cbe60d633399daa6ee66418be6d16e292ea47a93c291fce2c54c98f8007ed55a21759f5452559538
+Result = Fail
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 2a78a7beb8df4bf5d35ff0b2853bc51ce127163d2f56e00ea555aa972e1c2e3f439f85663ae25889
+Result = Fail
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = ee78ddbea9c3aede9f88af0e82464d9d1afe81de16aa18c49aeb326578fa615e86969348d9bbfb7f
+Result = Fail
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = cdf7cb74d978e7ea738e288ed79edfccf10b553c09d1856e2efbff1da769af3b72099cbda3cbf091
+Result = Fail
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 90b990a1ea254592f2c226c969b332fc7bfe5f808729c2d83291a566e6641a965ffdabe097050dc5
+Result = Fail
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 44a6aa954c3508b3c9264c20c272e80c0e95d50ddec2849084b47504dced5b70c302cc93502cc37e
+Result = Pass
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 9d4ff7a44cdb9b14f586efc3d6be02d069b425c06bec4eed37109739a3676f03adfd740dbaa4940d
+Result = Pass
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 23da95e102c7921a51b19b5733ea5776ab6c287f6057c00ec4bfacbb2f246b570efd93d98e99be49
+Result = Pass
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = 53d00d5839d0a1e695916151f9450b7311982917edcbd7c66496912db41761a1d2aecfda04fb2cfa
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 042653c674ef2a90f7fb11d30848e530ae59478f1051633a34fad277
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 1902d9769a7ba3d3268e1257395c8c2e5f98eef295dcbfa5a35df775
+Result = Fail
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = ebacb8e78c0ad9d3ed99f1821b0b0085beac351f88a79ef71faaf310
+Result = Fail
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = efc1d5b6f0a48e4ce3e821d743d34206b28c69485c410fa94d5e6103
+Result = Fail
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 3c1836e5d0f0473dab7bfd7a95ba69575f7f841970ac6c6769ac966a
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 2c583e54d75a02948c7f6dcd12cba32a65e8d605fba7ec10c47e9a8e
+Result = Fail
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = a8632dee22f34315b05c40135c6dd471c63b09438da834dc1f3f537f
+Result = Fail
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 0f03ea1b2561951d79062e19a85d98293c8c2846936c724c26421940
+Result = Fail
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f9764405e54d827ac433fd624506b92e123463a5b01f21ffa3a22ac7
+Result = Fail
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = a326e0cf3f97adff3249944880ddfb8d616cd18a086e046289429246
+Result = Fail
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = f188bc1a72e81b34d75b402e4f8ef3d638d2f56a409eab064c9649b7
+Result = Fail
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 341df3a273e85cf387ab823bdf9c34a1ae2c86940cb4bfcde2e93f29
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = a0e7997fd67ea66b6274d719b84da92433fdf7d512b160da35c7081d
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = dd8fd11e1c0746e7273fdd2e7dfa1ee4fc8ad835ca3141c0f83a9ad7
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 39b0d3603f1289b5885ac244953275d28491952e7e57d93c7ff1eb5d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = a5b7d8cca2069908d1ed88e6a9fe2c9bede3131dad54671ea7ade30a07d185692ab0ebdf4c78cf7a
+Result = Pass
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 9a98617fb97a0dfe466be692272dcdaec1c5443a3b51312ef042c86363cc05afb98c66e16be8a445
+Result = Fail
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = d3068ae815c3605d7670058abb9384f4c15b75150eb7910041a8f6ac697430627826bd76b19da027
+Result = Fail
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 388a289bb85533b667b141a78d0c79acdeb9fbf72886d5ab980581017fefef92c2b50ae20b93c81c
+Result = Fail
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 71f68480a8801d4966c84807c5ff6139d83ba0a5b902bee3327f5f91763c0a0bec43264c27cd237f
+Result = Pass
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 8627bf1e3edafc69f1328c393dd8e7bd1c182d021e6d3a3652c4b7fd911ca77950ff2d035e47b7ec
+Result = Fail
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = b10ea86a384432a45f50b3c2e482595b46c81c61ca39bc0f4ffcb29bde8b9a81945d671b0f619045
+Result = Fail
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 3ace8b7e03a0c1fa9e97f46975ab0a4924446e791540e225578cc14aa558e18d5f777ab6e16dcfee
+Result = Fail
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = 8190abe4c21e320e10825e269190bb10a354691958e2436275433c4ae28757c8544c86f1f74ea6a5
+Result = Fail
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 1d7e308c34cdca7b7b222f4ebc92afd8055bff542c0b76d3d7752ebe9c5dbf00ee8ad60ac34dd7d0
+Result = Fail
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 9c2609f7af5b634a16e58f2e9cc7a9ef7812a12d209847000a4432b35d3b884e4169c28d287499ff
+Result = Fail
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 5b0b5e6690d648e1b92c12cfddb431d6d3dfe689d01db8199256ace490c2f0afb93ba32be58fd1de
+Result = Pass
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 8722fca71fdf750ec5d62fc6d7ba079aef19210da764067aefd8535dd6b7fa701c9ca8c8b635c30b
+Result = Pass
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 91ac457f5e53492301e72d9d495277ed17edb30e8c7a48d21b5d2cd4d5b6d2ef48413245a6b27b67
+Result = Pass
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = d2fe5293b7d53ed46ddf02a5618039adbae22845ce72e434fdc83ea4863c3e84a5456f7f853a1ea6
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 1d089a5f
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = 2f46022a
+Result = Fail
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 67dc4693
+Result = Fail
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 7027a849
+Result = Fail
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 5c6a4de2
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 1d855f5d
+Result = Fail
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 1b318980
+Result = Fail
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = cf871f91
+Result = Fail
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 4f0e04bc
+Result = Fail
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = fc9013df
+Result = Fail
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 5134def3
+Result = Fail
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 5814103a
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 74c75c4a
+Result = Pass
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 9884898b
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 0b1cbfb1
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 5280a2137fee3deefcfe9b63a1199fb3
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = d40a7318c5f2d82f838c0beeefe0d598
+Result = Fail
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 7551978bc9592bf9e294b4984c5862bb
+Result = Fail
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 859cf444f89225b32a55a1645bd24979
+Result = Fail
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 29e967a0245607c36cf3eaf00fdae566
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 9daa0e1c4df5f2bf507b1a57a1135b86
+Result = Fail
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 18caec79720a5d67d7457e9b7c7a153c
+Result = Fail
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 5f2c455546c56f514a0f69f05345c2c4
+Result = Fail
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = b7e4846ff30b7c3673a962a2701c0387
+Result = Fail
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 7b5fa0d42a616ab05ac2c58c904ce92f
+Result = Fail
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = c8c67f558b5844b149dd47824c8cb9d8
+Result = Fail
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 70a09aaf22ac316124a169f6b0a83ffe
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 5bc85ed5521a91b9eb42b437950f0e06
+Result = Pass
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 989ec0e7b192ea010dd61d3fb64e8de0
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 15c2dbe7fa307654d8ca7c0f8d6d2f14
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 5e0eaebd
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 71b7fc33
+Result = Fail
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 93227bd4
+Result = Fail
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = ced654e2
+Result = Fail
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = bf7a8e0c
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 840caa3e
+Result = Fail
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 1e22fc41
+Result = Fail
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 968ccbbf
+Result = Fail
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0a31cc96
+Result = Fail
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = a456c3da
+Result = Fail
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 29746eea
+Result = Fail
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = df7f63ca
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = bf0b1445
+Result = Pass
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = ae8533f5
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 9426cf89
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = d07ccf9fdc3d33aa94cda3d230da707c
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 65fe32b649dc328c9f531584897e85b3
+Result = Fail
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = ec31fb6b41c2dae87cf395fc1fe3a080
+Result = Fail
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = 33c2f2312dd5bfcadbb05f8d0a33fd4a
+Result = Fail
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = a9e81afd1030d195c679e2c837aeb736
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1db000f0e7d3a03718293fc118678427
+Result = Fail
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = ea37900f049db8fc5cbf46edb5fcac2c
+Result = Fail
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = d1097ebd7ad0a41f61ba32a44dc15305
+Result = Fail
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0979729272d8b42f2e3dc0eb181a1217
+Result = Fail
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = 4457200916a20116b096225606f1a9e2
+Result = Fail
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = cc6b51f39a3dcfb54abbb89f4df21114
+Result = Fail
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = aac09cef9697927331251f028d24c31f
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 56c00070eae0db329894a045d866bbaf
+Result = Pass
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 090016bb96aeaabbf66fd34fc97591a4
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 264407dfe796bf7f6eb1f26c1f8504ef
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 9f6ca4af9b159148c889a6584d1183ea26e2614874b0504575dea8d1
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 84d8212e9cfc2121252baa3b065b1edcf50497b9594db1ebd7965825
+Result = Fail
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 5f60a8f867a33b2077ecc69863b295c3c6aeae7d7cade7f8f7f796fe
+Result = Fail
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 1353b3fa1bb1d57ffb139017885c02e26c90231a24b5a615b8f1f2ae
+Result = Fail
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = c3116d9040e1ed4f7c9464d270fb302bd3f1561c25c5b95b8b4b53f6
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 0ca17e8f89bea67db48a8f132ef6c6df7a292914d401299af6bf3800
+Result = Fail
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 0ce543569e8187f3cec70399ff922e4903cb1d12f990f05613244cf6
+Result = Fail
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 3acdbc163a350f312791b152a41e57627b1cc8bf3e41c8aea5876de8
+Result = Fail
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 604518e436edf7a0561d5e284f3915839a6d28cb06ef792a1970ed17
+Result = Fail
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = fc79b520d67da891e63654d7927db6c8012c96985a0059d5f68d8da4
+Result = Fail
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = d86bb51a98770098d0feb39170bd979199a8f741041df13790ee4c14
+Result = Fail
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 51b6b928bdd1cc0bd0a0aed2cda302472d618ffaa60e179029c87855
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = d0abab9b8e9d6c11bb9c15bea8a486704bed32c57297055b4de8ed8d
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = 92fd519a966c0fbdd7087ff5a1bd946cd663502db378383531d69947
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f239b1916830161f3b52b7ab13542a5a0a97a17f30ca5fa30768d4d
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6aab64c4787599d8f213446beadb16e08dba60e97f56dbd14d1d980d6fe0fb44b421992662b97975
+Result = Pass
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4980b2ee49b1aaf393175f5ab9bae95ec7904557dfa206603c51d36c826f01384100886198a7f6a3
+Result = Fail
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 86a02bdd6ae733eee26f8eab898b336105978b5bbd6df781758a111aae4f735b7dd4d9802f2a8406
+Result = Fail
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 59cfab8956813c48e09332a2bb8a30dbcdf5afb2529532ab8cef14ebc2951069739d5d657d82addb
+Result = Fail
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 67d989ea935b9ce190e3a7f3b645305e1e308a7fe617f80f170a2b9c309de6c2326115a76efbdf98
+Result = Pass
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 2522a5e4d157193ef2c264cfe877db8ac75b3cc5aab08a814bcd14af0205af716f2b864f0c397f65
+Result = Fail
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 4536422bbad220079ee09e700e103efdaac832d016a20813762d5d8adafe75a191310a2618930c48
+Result = Fail
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = d6711a78adf54f4effe647d531c4618cf32e3037eb700580206f80080dfa3e66e6371c0cde6cd205
+Result = Fail
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = e44034a397778e1c6babab27f5a50fa4aac0e83d6b3eb25db1b5b2b35c8a8125efccd1f4102f3e82
+Result = Fail
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = b8e31c5910623e405f2ebf65821963e5b8814043612395feca36f53b01943f03cb8b69b5af53e505
+Result = Fail
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 4000faf8558f2f4e01e45e90796cd236e5211d1704270f31c3bfc6851049d32105fd16bd45b29f29
+Result = Fail
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 53bb608f6236798839af35888cb0fa4797b599271084cc13847b022733ca5a5e3c4d472332484b7f
+Result = Pass
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = be54551d1d2f1b3eb60ffe3b165524ff90ca09fb252bf21c1c79edbf38c50e0f240a2d70f65aa79f
+Result = Pass
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = f07c1072d8f8e077dfbb3ad86dd92d32b41f29e647dcd7e3a82cd3ebaf6c2d3e21749bdf570ad28d
+Result = Pass
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f7cf7f4d0645934cb0a5e67b4227a909aa55dba09b2c39cef93a8759845326683a0d9c22151f486
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 16e543d0e20615ff0df15acd9927ddfe40668a54bb854cccc25e9fce
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = df35b109caf690656ae278bbd8f8bba687a2ce11b105dae98ecedb3e
+Result = Fail
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 7075da2291e2cb527eb926ed08d8020c5f8f0f2d4a6a4745728da544
+Result = Fail
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 18a77a66457b53286b1aea0845304cac8e66a02d5c642e4c02a9b9bc
+Result = Fail
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = 24e1d3820101412d8f4d57118cab8f7e489d5cac78802dd5ccf8ecf0
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = b5929bc9648e24a553c5cd953ecb9d67ee508d2d4ac7b46e661181d5
+Result = Fail
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 54aa018dc7fdf8a54809e1393d18031bab4aa5ca35c201907d74517d
+Result = Fail
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 69bcc300a459862b3cd284c15dd4af53dc7e95f3067bb8254a8edd83
+Result = Fail
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5c2d2df0d8aade3e5ae0f8d8b4b4d7c565817a31b2865dc270ad39a6
+Result = Fail
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = df1b3f98b6b0060191e7eb817f5908ddc0bc6f83860349e8ae423997
+Result = Fail
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 16e59dd38395c7be7f580371edabb1e9bf21270de270aa283309108e
+Result = Fail
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 0ef8981dd37c055a3c3e14786fc662b2a11065964911d35ebcc87096
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = fc1870cfc440f74f73f40e682cf4713d027c297b9426c3efe981e935
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 9fc2c462dff1ba9756772d73de5c4e822b5ea0bc88845a323b98de4f
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 05fc586d5c780b8e06f618b5bb85f591665a54390eba4e14af3b74e1
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = c5b0b2ef17498c5570eb335df4588032958ba3d69bf6f3178464a6f7fa2b76744e8e8d95691cecb8
+Result = Pass
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = d1f0518929f4ae2f0543de2a7dfe4bb0110bb3057e524a1c06bd6dc2e6bcc3436cffb969ae900388
+Result = Fail
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 1aa7dfa3a9818142c4971cbf4f64d4cbdbd354c6958ef474bb56d90669c726d866fe2206b8828727
+Result = Fail
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 90352a5ec92d4fa52a96ae28251a57933728b2a3670e2ecd9953fec4e091b3573214e1ecac1ac00c
+Result = Fail
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = eaa995946ed91d6a08ade14b260ac752cbd1081d5a7cad90783618374f6d03df28ee57a1a5aa38d8
+Result = Pass
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 0e320c4ece6ef0305a431a07a5a34d463ec4a37fc513c4b947bb3f30d6e674d10a496806c1c8933e
+Result = Fail
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 10685888091597c50acc54b2fb65150b83a7115351d6f8bd7dd7ee3f75cfb47fa72433644f9cf62e
+Result = Fail
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = e456abf9ee83e0a68fbdb09c4a7afaba0efb0aa6d74a17c443314076072a0ebd253fe1ab4883ebea
+Result = Fail
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5adadfd296edaf4bea92c8245983dc31b11335f682fb222c16a72444f0949868f0e71907acbb29f4
+Result = Fail
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = c2bb4d5a830646b3f8bf84044851c3b676c4ec02e43dcbf1ab2025208191d73041c038cf2562bb8c
+Result = Fail
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 9589b8abcb47e54e6e8fad3e64fec7ed4f70ac435bb3e548b7e6d183efa1f51b7ff31eaa52ed59ba
+Result = Fail
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = af63f27e2a9e70f106477493dc141d16a1d059dd7a8a7810d990b642039f24755790332b3cc47c49
+Result = Pass
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = 1d2ae88c878684a0b404986252b3a7583e1a5a51163ddc606d3968fdceaae5138c411a29d0d333ee
+Result = Pass
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 30c154c616946eccc2e241d336ad33720953e449a0e6b0f0dbf8e9464909bdf337e48093c082a10b
+Result = Pass
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 0c95b692b07b39039b40c80cf52ff71608ae87c973ac9ccb88bba8f204bb98b17cb3c8644e472b1e
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt
new file mode 100644
index 0000000000..27671e1a0a
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT192.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = c98ad7f38b2c7e970c9b965ec87a08208384718f78206c6c
+
+Count = 0
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 9d4b7f3b
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = 3796cf51b87266
+Adata = 00
+CT = 80745de9
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 2f6fa823
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 3cc132c6
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = c79d5557
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 41e0eea0
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = 06d102a9328863
+Adata = 00
+CT = 1f129266
+Result = Fail (1 - Adata changed)
+
+Count = 7
+Nonce = c288b810fb5334
+Adata = 00
+CT = 41b0e4e2
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = 5082e06a
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = 70587cce
+Result = Fail (1 - Adata changed)
+
+Count = 10
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6aaa0acd
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 22976e42
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = f440ea1d
+Result = Pass (0)
+Payload = 00
+
+Count = 13
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 88903fb9
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 9dc18698731b27
+Adata = 00
+CT = 3ff345c3
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 15
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 17223038fa99d53681ca1beabe78d1b4
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = 3796cf51b87266
+Adata = 00
+CT = d0e1eeef4d2a264536bb1c2c1bde7c35
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = 89ca5a64050f9f
+Adata = 00
+CT = 81d587f8673fd514c23172af7fb7523d
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = ec9d8edff25645
+Adata = 00
+CT = 500142447e535207899ab1499994daea
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = 05e16f0f42a6f4
+Adata = 00
+CT = fdfdbb38bf161785114f9ee2018e892f
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = 2e504b694f8df5
+Adata = 00
+CT = 38fe9622eaa2a50152cf57e393dd3063
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = 06d102a9328863
+Adata = 00
+CT = 73af4b87c167572e1400a0ee28209aff
+Result = Fail (1 - Adata changed)
+
+Count = 22
+Nonce = c288b810fb5334
+Adata = 00
+CT = ace2248b9f23efa813449c82217e4a4a
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = 08a166d9eb6610
+Adata = 00
+CT = a9bb0e469829d9cf09ad765c5b0b58bf
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 4a5810b121c91b
+Adata = 00
+CT = a5977f0826926ec0d32541b2bd4e2b1e
+Result = Fail (1 - Adata changed)
+
+Count = 25
+Nonce = 44077341139bf9
+Adata = 00
+CT = 6938fb5afec1a84e4abb062e1a943c20
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = a9df4f37847e1f
+Adata = 00
+CT = 7e3bbe0eb13988a93972f2fbcd35659e
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = 11df57fcd131e9
+Adata = 00
+CT = 48d7a15cf4f5808eb45d1ad817470554
+Result = Pass (0)
+Payload = 00
+
+Count = 28
+Nonce = 890fff56d10dc0
+Adata = 00
+CT = 97185ce68af1e6ab718c8c4b83ec04cd
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 9dc18698731b27
+Adata = 00
+CT = a81bc8f5a18293ffe19505a3687ce3f3
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 4bb3c4a4f893ad8c9bdc833c325d62b3d3ad1bccf9282a65
+
+Count = 30
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = fe69ed84
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = db7ffc82
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 7a677329
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = d903d8f7
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 215e0bf2
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = 0d38100f
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 9f8ab5f7
+Result = Fail (1 - Adata changed)
+
+Count = 37
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 7d811d50
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = c2e18439
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = d8b5817b
+Result = Fail (1 - Adata changed)
+
+Count = 40
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 28cd70ff
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = 790b2624
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 9e46632d
+Result = Pass (0)
+Payload = 00
+
+Count = 43
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = 39b82901
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = 4c0cf71f
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 45
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 0c66a8e547ed4f8c2c9a9a1eb5d455b9
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = a16a2e741f1cd9717285b6d882
+Adata = 00
+CT = 38757b3a61a4dc97ca3ab88bf1240695
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 368f3b8180fd4b851b7b272cb1
+Adata = 00
+CT = 11875da4445d92391d0fab5f3625497b
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = 7bb2bc00c0cafce65b5299ae64
+Adata = 00
+CT = 64477bcd4316e5c5789e1a678fdef943
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 935c1ef3d4032ff090f91141f3
+Adata = 00
+CT = 87da5dbc04e39fc468f43675d4e7df33
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = 2640b14f10b116411d1b5c1ad1
+Adata = 00
+CT = bf0d53ee529d8cafc5ad7a8f2d85e7a2
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = b229c173a13b2d83af91ec45b0
+Adata = 00
+CT = 676370637ad78c705d43fce066dc909f
+Result = Fail (1 - Adata changed)
+
+Count = 52
+Nonce = 37ca0dc2d6efd9efde69f14f03
+Adata = 00
+CT = 289936db0f9f148a3c9e2d28f7d7de51
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = 6b6238aed86d677ba2b3e2622c
+Adata = 00
+CT = 58a283641627669d5514f2af559b6c14
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = d6cb2ac67bb13b8f6d31fad64a
+Adata = 00
+CT = a6b058540ed905d6e3499a13ea1f3d83
+Result = Fail (1 - Adata changed)
+
+Count = 55
+Nonce = 32a7cd361ef00e65f5778fdfd4
+Adata = 00
+CT = 7a19b3377384f09915d0e1ae93a9f16c
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = d0a1508fdefcf5be30a459b813
+Adata = 00
+CT = a0d047a1f9940d325e474da54aa13897
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = 5381a61b449dc6a42aa4c79b95
+Adata = 00
+CT = 8a4768a2093694b6bcb7083c0bb6331c
+Result = Pass (0)
+Payload = 00
+
+Count = 58
+Nonce = c55430f2da0687ea40313884ab
+Adata = 00
+CT = a7cafd6f68dc1f15a3603da654ce27bc
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = ec76d1850acc0979a1f11906fb
+Adata = 00
+CT = c49845f2ea3c9981ad7e9b942f615b8d
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 19ebfde2d5468ba0a3031bde629b11fd4094afcb205393fa
+
+Count = 60
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = 411986d04d6463100bff03f7d0bde7ea2c3488784378138cddc93a54
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 61
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = 32b649ab56162e55d4148a1292d6a225a988eb1308298273b6889036
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = a963c3568ab413b174cd95cc1e3ca61ee181292bebdb28179b4de35f
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = 9cbce402511b89
+Adata = 00
+CT = 0396e6c8db43e5fac205f4c576fd577368adcb688cf3d7e76df9ffc5
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 123a0beace4e39
+Adata = 00
+CT = b41bfba94edcafc41b4c144269b9126a6d47b19e83b15772b28c8e38
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 65
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = 01e3bb938e16d0284d1d0fee049d80fb97356ae4d84127cf7336a30a
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = abd7551c5e84e9bef5fbfad3e24d13f02864410eae9177ad0c40cc72
+Result = Fail (1 - Adata changed)
+
+Count = 67
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 3b5ae49e0974f41826152432b46f1a85ab4995afefbbccddfc9fd290
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 040a257dede70e
+Adata = 00
+CT = 21fb4324de4ba1e2762b3041ce26e43a3d191458a046d489e485910b
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = 99ca8f542fd06481e23719214c9892442f393d72899deea08695053f
+Result = Fail (1 - Adata changed)
+
+Count = 70
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 5fcc05342cdc27f66b324ae7387205bfb4ab6302bfe0af09050d2054
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 0a7fe63046daf8a979935b897088c64acc1b47a5a9b86fdd6def28ab
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 72
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = daf7d7dfa512ceb1d7d3435634d9a70b3ef6c6dc38f409e068941fce
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 73
+Nonce = 098e053fa08043
+Adata = 00
+CT = cdb417dff6502208775f21e35cdb8e3e1199308d1a94229051a1ec4a
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 74
+Nonce = 4bf48328725514
+Adata = 00
+CT = e75441093c8ccba6eac5913dc246ce96de4784a01051498298eaddaf
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 75
+Nonce = 5a8aa485c316e9
+Adata = 00
+CT = cba4b4aeb85f0492fd8d905c4a6d8233139833373ef188a8c5a5ebecf7ac8607fe412189e83d9d20
+Result = Pass (0)
+Payload = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22
+
+Count = 76
+Nonce = 31f8fa25827d48
+Adata = 00
+CT = ca62713728b5c9d652504b0ae8fd4fee5d297ee6a8d19cb6e699f15f14d34dcaf9ba8ed4b877c97d
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 5340ed7752c9ff
+Adata = 00
+CT = 93012c0a5f6f1025b8c4a5d897d3eea0b1c77be8000c9e59f3b8899459788c58794f177cfd838f35
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = 9cbce402511b89
+Adata = 00
+CT = b8eb95f72f643c2c51ad74775cc203d215c86626e903eb013ad22e8fa4d2f9725ce4f212a8844855
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 123a0beace4e39
+Adata = 00
+CT = 71f17cf21c44267c676657db9e55bee33273787474e77b17b5eab45d7d096577643815e6d467312d
+Result = Pass (0)
+Payload = 9d033e3b66efed1467868f382417c80594877a28bc97f406
+
+Count = 80
+Nonce = 8ea1594a58fe4a
+Adata = 00
+CT = d6737f642260c4ee3b19cb78cc2ef1767213416b82c71e918b1a5ecca7354af824fea617b9b69031
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 5a7743e59e82da
+Adata = 00
+CT = cbe60d633399daa6ee66418be6d16e292ea47a93c291fce2c54c98f8007ed55a21759f5452559538
+Result = Fail (1 - Adata changed)
+
+Count = 82
+Nonce = f477f754d7ee76
+Adata = 00
+CT = 2a78a7beb8df4bf5d35ff0b2853bc51ce127163d2f56e00ea555aa972e1c2e3f439f85663ae25889
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 040a257dede70e
+Adata = 00
+CT = ee78ddbea9c3aede9f88af0e82464d9d1afe81de16aa18c49aeb326578fa615e86969348d9bbfb7f
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = dd51b8e91683d1
+Adata = 00
+CT = cdf7cb74d978e7ea738e288ed79edfccf10b553c09d1856e2efbff1da769af3b72099cbda3cbf091
+Result = Fail (1 - Adata changed)
+
+Count = 85
+Nonce = ab3cb86cca6fb2
+Adata = 00
+CT = 90b990a1ea254592f2c226c969b332fc7bfe5f808729c2d83291a566e6641a965ffdabe097050dc5
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = f67b98efd39b55
+Adata = 00
+CT = 44a6aa954c3508b3c9264c20c272e80c0e95d50ddec2849084b47504dced5b70c302cc93502cc37e
+Result = Pass (0)
+Payload = f2e944e1ae47ad5873bf391f1b0cc07f6151eb4c50bb45b2
+
+Count = 87
+Nonce = e60e2c002d1c99
+Adata = 00
+CT = 9d4ff7a44cdb9b14f586efc3d6be02d069b425c06bec4eed37109739a3676f03adfd740dbaa4940d
+Result = Pass (0)
+Payload = 70f48dc1d76e5028da07e29852801375a9edb2214a5ea4c0
+
+Count = 88
+Nonce = 098e053fa08043
+Adata = 00
+CT = 23da95e102c7921a51b19b5733ea5776ab6c287f6057c00ec4bfacbb2f246b570efd93d98e99be49
+Result = Pass (0)
+Payload = bd81680e3dc0b35431c92598dcaa26ef09ca0da5e77193de
+
+Count = 89
+Nonce = 4bf48328725514
+Adata = 00
+CT = 53d00d5839d0a1e695916151f9450b7311982917edcbd7c66496912db41761a1d2aecfda04fb2cfa
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 197afb02ffbd8f699dacae87094d524324576b99844f75e1
+
+Count = 90
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = 042653c674ef2a90f7fb11d30848e530ae59478f1051633a34fad277
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 91
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 1902d9769a7ba3d3268e1257395c8c2e5f98eef295dcbfa5a35df775
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = ebacb8e78c0ad9d3ed99f1821b0b0085beac351f88a79ef71faaf310
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = efc1d5b6f0a48e4ce3e821d743d34206b28c69485c410fa94d5e6103
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 3c1836e5d0f0473dab7bfd7a95ba69575f7f841970ac6c6769ac966a
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 95
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 2c583e54d75a02948c7f6dcd12cba32a65e8d605fba7ec10c47e9a8e
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = a8632dee22f34315b05c40135c6dd471c63b09438da834dc1f3f537f
+Result = Fail (1 - Adata changed)
+
+Count = 97
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 0f03ea1b2561951d79062e19a85d98293c8c2846936c724c26421940
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = f9764405e54d827ac433fd624506b92e123463a5b01f21ffa3a22ac7
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = a326e0cf3f97adff3249944880ddfb8d616cd18a086e046289429246
+Result = Fail (1 - Adata changed)
+
+Count = 100
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = f188bc1a72e81b34d75b402e4f8ef3d638d2f56a409eab064c9649b7
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 341df3a273e85cf387ab823bdf9c34a1ae2c86940cb4bfcde2e93f29
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 102
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = a0e7997fd67ea66b6274d719b84da92433fdf7d512b160da35c7081d
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 103
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = dd8fd11e1c0746e7273fdd2e7dfa1ee4fc8ad835ca3141c0f83a9ad7
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 104
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = 39b0d3603f1289b5885ac244953275d28491952e7e57d93c7ff1eb5d
+Result = Fail (2 - CT changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 105
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = 00
+CT = a5b7d8cca2069908d1ed88e6a9fe2c9bede3131dad54671ea7ade30a07d185692ab0ebdf4c78cf7a
+Result = Pass (0)
+Payload = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697
+
+Count = 106
+Nonce = 49004912fdd7269279b1f06a89
+Adata = 00
+CT = 9a98617fb97a0dfe466be692272dcdaec1c5443a3b51312ef042c86363cc05afb98c66e16be8a445
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = efeb82c8c68d6600b24dd6d8ee
+Adata = 00
+CT = d3068ae815c3605d7670058abb9384f4c15b75150eb7910041a8f6ac697430627826bd76b19da027
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = 7b93d368dc551640b00ba3cbb5
+Adata = 00
+CT = 388a289bb85533b667b141a78d0c79acdeb9fbf72886d5ab980581017fefef92c2b50ae20b93c81c
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 24b7a65391f88bea38fcd54a9a
+Adata = 00
+CT = 71f68480a8801d4966c84807c5ff6139d83ba0a5b902bee3327f5f91763c0a0bec43264c27cd237f
+Result = Pass (0)
+Payload = 43419715cef9a48dc7280bc035082a6581afd1d82bee9d1a
+
+Count = 110
+Nonce = 6aa3f731522fce7e366ba59945
+Adata = 00
+CT = 8627bf1e3edafc69f1328c393dd8e7bd1c182d021e6d3a3652c4b7fd911ca77950ff2d035e47b7ec
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = a11cf5bed0041ee3cb1fef4b43
+Adata = 00
+CT = b10ea86a384432a45f50b3c2e482595b46c81c61ca39bc0f4ffcb29bde8b9a81945d671b0f619045
+Result = Fail (1 - Adata changed)
+
+Count = 112
+Nonce = 273cc5013785baeb5abc79c8bd
+Adata = 00
+CT = 3ace8b7e03a0c1fa9e97f46975ab0a4924446e791540e225578cc14aa558e18d5f777ab6e16dcfee
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = d2d4482ea8e98c1cf309671895
+Adata = 00
+CT = 8190abe4c21e320e10825e269190bb10a354691958e2436275433c4ae28757c8544c86f1f74ea6a5
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = a8849b44adb48d271979656930
+Adata = 00
+CT = 1d7e308c34cdca7b7b222f4ebc92afd8055bff542c0b76d3d7752ebe9c5dbf00ee8ad60ac34dd7d0
+Result = Fail (1 - Adata changed)
+
+Count = 115
+Nonce = a632ba0d00511122abcd6227ff
+Adata = 00
+CT = 9c2609f7af5b634a16e58f2e9cc7a9ef7812a12d209847000a4432b35d3b884e4169c28d287499ff
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = c47af80cd26d047630c1fdf0d1
+Adata = 00
+CT = 5b0b5e6690d648e1b92c12cfddb431d6d3dfe689d01db8199256ace490c2f0afb93ba32be58fd1de
+Result = Pass (0)
+Payload = d8306c9c4ea6c69c6e2ad0fc0e49b1e0126b01078d6419ff
+
+Count = 117
+Nonce = 70e132023acae1f88c7a237b68
+Adata = 00
+CT = 8722fca71fdf750ec5d62fc6d7ba079aef19210da764067aefd8535dd6b7fa701c9ca8c8b635c30b
+Result = Pass (0)
+Payload = d0b2bef5ed1a87d9c73d4a459cb05c11799c4f51ad640b1e
+
+Count = 118
+Nonce = 8010d3a2a14f72f5585defc940
+Adata = 00
+CT = 91ac457f5e53492301e72d9d495277ed17edb30e8c7a48d21b5d2cd4d5b6d2ef48413245a6b27b67
+Result = Pass (0)
+Payload = 4faba05569bf7ac656780c16995e9122e565fe9984be8a68
+
+Count = 119
+Nonce = a98c2f0e0a7b68942853905191
+Adata = 00
+CT = d2fe5293b7d53ed46ddf02a5618039adbae22845ce72e434fdc83ea4863c3e84a5456f7f853a1ea6
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 90929a4b0ac65b350ad1591611fe48297e03956f6083e451
+
+Count = 120
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 1d089a5f
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = 2f46022a
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 67dc4693
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 7027a849
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 5c6a4de2
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 1d855f5d
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 1b318980
+Result = Fail (1 - Adata changed)
+
+Count = 127
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = cf871f91
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = 4f0e04bc
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = fc9013df
+Result = Fail (1 - Adata changed)
+
+Count = 130
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = 5134def3
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 5814103a
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 74c75c4a
+Result = Pass (0)
+Payload = 00
+
+Count = 133
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 9884898b
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 0b1cbfb1
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 135
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 5280a2137fee3deefcfe9b63a1199fb3
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = a265480ca88d5f
+Adata = a2248a882ecbf850daf91933a389e78e81623d233dfd47bf8321361a38f138fe
+CT = d40a7318c5f2d82f838c0beeefe0d598
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = 87ec7423f1ebfc
+Adata = 2bed1ec06c1ca149d9ffbaf048c474ea2de000eb7950f18d6c25acf6ab3f19b5
+CT = 7551978bc9592bf9e294b4984c5862bb
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = b8b04f90616082
+Adata = 4898731e143fcc677c7cf1a8f2b3c4039fb5e57028e33b05e097d1763cbfe4d8
+CT = 859cf444f89225b32a55a1645bd24979
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 8c687b4318813a
+Adata = fcad52a88544325bb31eb5de4a41dbff6a96f69d0993b969a01792ee23953acf
+CT = 29e967a0245607c36cf3eaf00fdae566
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = 29b810eed8fc92
+Adata = 40d1d320eb63a25d7a2b3141563a552114275ddda56beb62cc0c0273d5795faa
+CT = 9daa0e1c4df5f2bf507b1a57a1135b86
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = 62452462c53934
+Adata = 1eb8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+CT = 18caec79720a5d67d7457e9b7c7a153c
+Result = Fail (1 - Adata changed)
+
+Count = 142
+Nonce = 4cceba0e7aee97
+Adata = f33e184c967165eb62542999afaca4e3e319840e439b5bb509544fb4b6901445
+CT = 5f2c455546c56f514a0f69f05345c2c4
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b5151b0601c683
+Adata = 73d27303ec91f28c79b278882034d11eb6a5266746f37edbb77f8409a8738b8c
+CT = b7e4846ff30b7c3673a962a2701c0387
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 4e5d6d7ac9e71e
+Adata = a01b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+CT = 7b5fa0d42a616ab05ac2c58c904ce92f
+Result = Fail (1 - Adata changed)
+
+Count = 145
+Nonce = dc88e989951a3f
+Adata = fdcacfaff46585406cc45a2da364e67e132a91c98900a8f9d7bfb14ec951fca5
+CT = c8c67f558b5844b149dd47824c8cb9d8
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = a1aeda4b4cb8dd
+Adata = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c6f6d03036edea963
+CT = 70a09aaf22ac316124a169f6b0a83ffe
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = f248e5225e3d9a
+Adata = fdc64ef76a3bfd0a15d0bc8e8bacaf64346796a3e35afcf2ac1ab136f63f7b6e
+CT = 5bc85ed5521a91b9eb42b437950f0e06
+Result = Pass (0)
+Payload = 00
+
+Count = 148
+Nonce = e68228f5c65b73
+Adata = 614efdf89ce2a9fcbd38bdc0b4cece54dfd7532880e0b4ce6eb3a4010b7cb1e7
+CT = 989ec0e7b192ea010dd61d3fb64e8de0
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = ea167cfd1101d9
+Adata = 28130f938c45a1a92b02dbeadbd8df816b6d934e87cca2dfdbfdc49c7cd84041
+CT = 15c2dbe7fa307654d8ca7c0f8d6d2f14
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = 6a798d7c5e1a72b43e20ad5c7b08567b12ab744b61c070e2
+
+Count = 150
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 5e0eaebd
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 71b7fc33
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = 93227bd4
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = ced654e2
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = bf7a8e0c
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 840caa3e
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = 1e22fc41
+Result = Fail (1 - Adata changed)
+
+Count = 157
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = 968ccbbf
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0a31cc96
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = a456c3da
+Result = Fail (1 - Adata changed)
+
+Count = 160
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = 29746eea
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = df7f63ca
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = bf0b1445
+Result = Pass (0)
+Payload = 00
+
+Count = 163
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = ae8533f5
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 9426cf89
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 165
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = d07ccf9fdc3d33aa94cda3d230da707c
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = 8739b4bea1a099fe547499cbc6
+Adata = f6107696edb332b2ea059d8860fee26be42e5e12e1a4f79a8d0eafce1b2278a7
+CT = 65fe32b649dc328c9f531584897e85b3
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 0f98fdbde2b04387f27b3401dd
+Adata = 02010329660fa716556193eb4870ee84bd934296a5c52d92bba859cc13caaddc
+CT = ec31fb6b41c2dae87cf395fc1fe3a080
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 4eed58f381e500902ba5c56864
+Adata = 96056d9ebd7c553c22cc2d9d816b61123750d96c1b08c4b661079424bf3c4946
+CT = 33c2f2312dd5bfcadbb05f8d0a33fd4a
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = 1e7e51f0fa9a33ed618c26f5e3
+Adata = da9b8ffb0f3c2aee2e386cc9f035ec1eb3e629bd1544c11dc21be4fd8ac9074a
+CT = a9e81afd1030d195c679e2c837aeb736
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = f012f94f5988c79aa179d7fdfc
+Adata = 612b2ef2683109d99452f95099417641d0c2be3f8ab4cbb2a44e83355ba9303c
+CT = 1db000f0e7d3a03718293fc118678427
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 715acf92cfb69ad56036c49e70
+Adata = 960667b85be07304634124b9324be12a1c11451f1fa9db82c683265b4cf8e5ff
+CT = ea37900f049db8fc5cbf46edb5fcac2c
+Result = Fail (1 - Adata changed)
+
+Count = 172
+Nonce = 141be3601e38185a9fa1596d2e
+Adata = 606452c62290b43559a588bb03356f846cecb0ccaf0bdaf67a18abd811d4315a
+CT = d1097ebd7ad0a41f61ba32a44dc15305
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = fcdda3c5f0e80843b03d8788da
+Adata = 03f22247a55461a293d253c77483859fdac1b87c2480e208a3df767cfbfde512
+CT = 0979729272d8b42f2e3dc0eb181a1217
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = ca660ed3b917c0aca140dcd3fb
+Adata = 254a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b42574572f51
+CT = 4457200916a20116b096225606f1a9e2
+Result = Fail (1 - Adata changed)
+
+Count = 175
+Nonce = 642ae3466661ce1f51783deece
+Adata = 4432a1cec5976cc13b8fb78341d426c2248f091b597123d263ffafc7f82da5a5
+CT = cc6b51f39a3dcfb54abbb89f4df21114
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = 7864c717ec93db38b10679be47
+Adata = 679aad1ad1e57029e3362b325572fc71cac53184b0f1546867e665a4a59466c4
+CT = aac09cef9697927331251f028d24c31f
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = c3bf9dfe9d6c26f543188fb457
+Adata = e301f69ad3a7e08a3d02462f0aa584449eb0449b0e3c50aa8dfaa4472816c8b0
+CT = 56c00070eae0db329894a045d866bbaf
+Result = Pass (0)
+Payload = 00
+
+Count = 178
+Nonce = 1527657d2fd98f7deca55cc649
+Adata = f4c723433b7cafe3cda9bb4940a21a89a8382d13018b622ccd1ffb9ffd3211af
+CT = 090016bb96aeaabbf66fd34fc97591a4
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = b8432d3d5525a0dadbbaa6b6b8
+Adata = 86ee6e37b4a2d9a0b52ec95643b4e8297e237721e15ce8bf7593a98644f83eba
+CT = 264407dfe796bf7f6eb1f26c1f8504ef
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = f9fdca4ac64fe7f014de0f43039c757194d544ce5d15eed4
+
+Count = 180
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 9f6ca4af9b159148c889a6584d1183ea26e2614874b0504575dea8d1
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 181
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 84d8212e9cfc2121252baa3b065b1edcf50497b9594db1ebd7965825
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 5f60a8f867a33b2077ecc69863b295c3c6aeae7d7cade7f8f7f796fe
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 1353b3fa1bb1d57ffb139017885c02e26c90231a24b5a615b8f1f2ae
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = c3116d9040e1ed4f7c9464d270fb302bd3f1561c25c5b95b8b4b53f6
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 185
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 0ca17e8f89bea67db48a8f132ef6c6df7a292914d401299af6bf3800
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 0ce543569e8187f3cec70399ff922e4903cb1d12f990f05613244cf6
+Result = Fail (1 - Adata changed)
+
+Count = 187
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = 3acdbc163a350f312791b152a41e57627b1cc8bf3e41c8aea5876de8
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = 604518e436edf7a0561d5e284f3915839a6d28cb06ef792a1970ed17
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = fc79b520d67da891e63654d7927db6c8012c96985a0059d5f68d8da4
+Result = Fail (1 - Adata changed)
+
+Count = 190
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = d86bb51a98770098d0feb39170bd979199a8f741041df13790ee4c14
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 51b6b928bdd1cc0bd0a0aed2cda302472d618ffaa60e179029c87855
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 192
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = d0abab9b8e9d6c11bb9c15bea8a486704bed32c57297055b4de8ed8d
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 193
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = 92fd519a966c0fbdd7087ff5a1bd946cd663502db378383531d69947
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 194
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f239b1916830161f3b52b7ab13542a5a0a97a17f30ca5fa30768d4d
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 195
+Nonce = 5a8aa485c316e9
+Adata = 3796cf51b8726652a4204733b8fbb047cf00fb91a9837e22ec22b1a268f88e2c
+CT = 6aab64c4787599d8f213446beadb16e08dba60e97f56dbd14d1d980d6fe0fb44b421992662b97975
+Result = Pass (0)
+Payload = a265480ca88d5f536db0dc6abc40faf0d05be7a966977768
+
+Count = 196
+Nonce = fdd2d6f503c915
+Adata = 5b92394f21ddc3ad49d9b0881b829a5935cb3a4d23e292a62fb66b5e7ab7020e
+CT = 4980b2ee49b1aaf393175f5ab9bae95ec7904557dfa206603c51d36c826f01384100886198a7f6a3
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 27d73d58100054
+Adata = f6468542923be79b4b06dfe70920d57d1da73a9c16f9c9a12d810d7de0d12467
+CT = 86a02bdd6ae733eee26f8eab898b336105978b5bbd6df781758a111aae4f735b7dd4d9802f2a8406
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = dd16e0ce1250e3
+Adata = bc65cfd65e9863c8b7457d58afa6bdb48a84170d8aa97ba5b397b52ad17a9242
+CT = 59cfab8956813c48e09332a2bb8a30dbcdf5afb2529532ab8cef14ebc2951069739d5d657d82addb
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = ccee19d037cf4a
+Adata = c026696e6425e6c33f45b4145febf1137e7ac26383c9f5aa4cd4e5e8abb19e07
+CT = 67d989ea935b9ce190e3a7f3b645305e1e308a7fe617f80f170a2b9c309de6c2326115a76efbdf98
+Result = Pass (0)
+Payload = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005
+
+Count = 200
+Nonce = 6c8ba94f09cbe6
+Adata = 774ad1a88f8bb063951486d4aec5bf82d5fc535bd0b952f86200c123c37fa496
+CT = 2522a5e4d157193ef2c264cfe877db8ac75b3cc5aab08a814bcd14af0205af716f2b864f0c397f65
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = 1f670302fcdcc8
+Adata = 1a9ff9698cfc96b581d7115c822e4363d7355ec5daed2eae5bf89ee944ac7d9c
+CT = 4536422bbad220079ee09e700e103efdaac832d016a20813762d5d8adafe75a191310a2618930c48
+Result = Fail (1 - Adata changed)
+
+Count = 202
+Nonce = 5d05f658c729a2
+Adata = dd9564c1431ed490b17ef69f6115805e54ef156ef4e10e58f7d57a7e86626352
+CT = d6711a78adf54f4effe647d531c4618cf32e3037eb700580206f80080dfa3e66e6371c0cde6cd205
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 22a77db9fcbc95
+Adata = 86bf1739c10f63df734ee3e60ac40ff5636c49f68ca4c16ece289609eb413e7a
+CT = e44034a397778e1c6babab27f5a50fa4aac0e83d6b3eb25db1b5b2b35c8a8125efccd1f4102f3e82
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 491e32b0bbfa4c
+Adata = 75bef075c79d6cfd7fc73aefd67b2d215be0648937477ba606b1fe1be591239e
+CT = b8e31c5910623e405f2ebf65821963e5b8814043612395feca36f53b01943f03cb8b69b5af53e505
+Result = Fail (1 - Adata changed)
+
+Count = 205
+Nonce = bc4b7d3a380be0
+Adata = 353dbb41e2d525a9f4fcd858d0f0aa1b1e86ac0f936d5c09c6b61c343f94e3fc
+CT = 4000faf8558f2f4e01e45e90796cd236e5211d1704270f31c3bfc6851049d32105fd16bd45b29f29
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = a840e98df72ae9
+Adata = 22c6607732ef1bdc7fcf6197e037cdadd7ee17c008552dd9f04b8564d34fb17c
+CT = 53bb608f6236798839af35888cb0fa4797b599271084cc13847b022733ca5a5e3c4d472332484b7f
+Result = Pass (0)
+Payload = a2f53385618b41301f4e3ea4c597f411103dac2b37abf5da
+
+Count = 207
+Nonce = 39d93c3cf31a6f
+Adata = 937dfac5cded938438f4e97aabd9beb50dba40f824198260a89729479cfe6869
+CT = be54551d1d2f1b3eb60ffe3b165524ff90ca09fb252bf21c1c79edbf38c50e0f240a2d70f65aa79f
+Result = Pass (0)
+Payload = c1bdef96dc868446be48491b160504546f2a40dd581f9582
+
+Count = 208
+Nonce = 0bbc177019321e
+Adata = f6e02678820f5ccbede6cbded02d6dd58d486166d7b18ee975a688af421fb795
+CT = f07c1072d8f8e077dfbb3ad86dd92d32b41f29e647dcd7e3a82cd3ebaf6c2d3e21749bdf570ad28d
+Result = Pass (0)
+Payload = 72a70954d22ad722fc32756afce67b344b2f3c55fe1d9eed
+
+Count = 209
+Nonce = ad048eb2ad7526
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+CT = 7f7cf7f4d0645934cb0a5e67b4227a909aa55dba09b2c39cef93a8759845326683a0d9c22151f486
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = a7aa635ea51b0bb20a092bd5573e728ccd4b3e8cdd2ab33d
+
+Count = 210
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = 16e543d0e20615ff0df15acd9927ddfe40668a54bb854cccc25e9fce
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 211
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = df35b109caf690656ae278bbd8f8bba687a2ce11b105dae98ecedb3e
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 7075da2291e2cb527eb926ed08d8020c5f8f0f2d4a6a4745728da544
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 18a77a66457b53286b1aea0845304cac8e66a02d5c642e4c02a9b9bc
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = 24e1d3820101412d8f4d57118cab8f7e489d5cac78802dd5ccf8ecf0
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 215
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = b5929bc9648e24a553c5cd953ecb9d67ee508d2d4ac7b46e661181d5
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 54aa018dc7fdf8a54809e1393d18031bab4aa5ca35c201907d74517d
+Result = Fail (1 - Adata changed)
+
+Count = 217
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = 69bcc300a459862b3cd284c15dd4af53dc7e95f3067bb8254a8edd83
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5c2d2df0d8aade3e5ae0f8d8b4b4d7c565817a31b2865dc270ad39a6
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = df1b3f98b6b0060191e7eb817f5908ddc0bc6f83860349e8ae423997
+Result = Fail (1 - Adata changed)
+
+Count = 220
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 16e59dd38395c7be7f580371edabb1e9bf21270de270aa283309108e
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = 0ef8981dd37c055a3c3e14786fc662b2a11065964911d35ebcc87096
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 222
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = fc1870cfc440f74f73f40e682cf4713d027c297b9426c3efe981e935
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 223
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 9fc2c462dff1ba9756772d73de5c4e822b5ea0bc88845a323b98de4f
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 224
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 05fc586d5c780b8e06f618b5bb85f591665a54390eba4e14af3b74e1
+Result = Fail (2 - CT changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+
+Count = 225
+Nonce = 5a8aa485c316e9403aff859fbb
+Adata = a16a2e741f1cd9717285b6d882c1fc53655e9773761ad697a7ee6410184c7982
+CT = c5b0b2ef17498c5570eb335df4588032958ba3d69bf6f3178464a6f7fa2b76744e8e8d95691cecb8
+Result = Pass (0)
+Payload = 8739b4bea1a099fe547499cbc6d1b13d849b8084c9b6acc5
+
+Count = 226
+Nonce = 0812757ad0cc4d17c4cfe7a642
+Adata = ec6c44a7e94e51a3ca6dee229098391575ec7213c85267fbf7492fdbeee61b10
+CT = d1f0518929f4ae2f0543de2a7dfe4bb0110bb3057e524a1c06bd6dc2e6bcc3436cffb969ae900388
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = eff510acc1b85f35029cf7dc00
+Adata = 0923b927b8295c5dfaf67da55e5014293bc8c708fda50af06c1e8aef31cccc86
+CT = 1aa7dfa3a9818142c4971cbf4f64d4cbdbd354c6958ef474bb56d90669c726d866fe2206b8828727
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 3d13d09057190366c63c8750e9
+Adata = 77e27aa9a7bf30e130c862a3296a1cd7a10195ed1d940f2c97bfff47c6f06e32
+CT = 90352a5ec92d4fa52a96ae28251a57933728b2a3670e2ecd9953fec4e091b3573214e1ecac1ac00c
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = e3c03ef7e1d31961ee0b97bd99
+Adata = 8a3676dd640821b58fb0f0329855fd5882c376ea166b958b7aaad223054e5784
+CT = eaa995946ed91d6a08ade14b260ac752cbd1081d5a7cad90783618374f6d03df28ee57a1a5aa38d8
+Result = Pass (0)
+Payload = 92973ce707733a73118c8ce6b5e3fc77a17f448310c0197f
+
+Count = 230
+Nonce = 5d165ddd4e599387af5967cae6
+Adata = e374f875ce829b62c98fbd67bcf128b5647f25fff9a643300eb95559b889baed
+CT = 0e320c4ece6ef0305a431a07a5a34d463ec4a37fc513c4b947bb3f30d6e674d10a496806c1c8933e
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = fcec171162a27a96066181fab2
+Adata = cf431cc3671ec468ea86f6cc09842fcf3a84b3ef0fa1c7b20b232145b4469d62
+CT = 10685888091597c50acc54b2fb65150b83a7115351d6f8bd7dd7ee3f75cfb47fa72433644f9cf62e
+Result = Fail (1 - Adata changed)
+
+Count = 232
+Nonce = 2fa8120398d1a946f391367cf6
+Adata = 92558a239c8e13230754f23aec67b153db29fdfc7daf641778185dd2931d89da
+CT = e456abf9ee83e0a68fbdb09c4a7afaba0efb0aa6d74a17c443314076072a0ebd253fe1ab4883ebea
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 88e0ae338bbca9d4299b294354
+Adata = 5db5c388dbadc9f175a5cd5a1472a458d25acd7fb9c951c0cd45edf64da473bb
+CT = 5adadfd296edaf4bea92c8245983dc31b11335f682fb222c16a72444f0949868f0e71907acbb29f4
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 4862e36296d6afc9399a95bbb4
+Adata = 36d82ebd0e0f5fe3b12946d041ae5aee16e6d17025406dd776f499bbd8e8b4c8
+CT = c2bb4d5a830646b3f8bf84044851c3b676c4ec02e43dcbf1ab2025208191d73041c038cf2562bb8c
+Result = Fail (1 - Adata changed)
+
+Count = 235
+Nonce = 2f360a4715074e942244ab7f9b
+Adata = f0087b0086a081c1071481f033a8be8e940c36763084329bb8461b9102238f4f
+CT = 9589b8abcb47e54e6e8fad3e64fec7ed4f70ac435bb3e548b7e6d183efa1f51b7ff31eaa52ed59ba
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 93e08854560edb096e5d654086
+Adata = bdc60dff08bfd5d44320b75c61e456fd4333c9c3d0294d4a48d936dfd5922ce2
+CT = af63f27e2a9e70f106477493dc141d16a1d059dd7a8a7810d990b642039f24755790332b3cc47c49
+Result = Pass (0)
+Payload = 569e4aec88dd51ca519c0a00c922ee33d3559b98a32d7906
+
+Count = 237
+Nonce = e3f37b68ff508cfe295441d9e3
+Adata = b2b6c5782e4f128467c589d2a6cf55ef12877adb771bbb6245c5bba9dcfd6208
+CT = 1d2ae88c878684a0b404986252b3a7583e1a5a51163ddc606d3968fdceaae5138c411a29d0d333ee
+Result = Pass (0)
+Payload = 02b5511204bd55f7c37973e26f6df5883c0a530f07c7f8c2
+
+Count = 238
+Nonce = ea98ec44f5a86715014783172e
+Adata = e4692b9f06b666c7451b146c8aeb07a6e30c629d28065c3dde5940325b14b810
+CT = 30c154c616946eccc2e241d336ad33720953e449a0e6b0f0dbf8e9464909bdf337e48093c082a10b
+Result = Pass (0)
+Payload = 4da40b80579c1d9a5309f7efecb7c059a2f914511ca5fc10
+
+Count = 239
+Nonce = 5a16a8902bd70fa06cfe184c57
+Adata = 399d6b0652836457ec4f701f0dc0e5aed73d16585d61cb1bb5b7ee824fc287c8
+CT = 0c95b692b07b39039b40c80cf52ff71608ae87c973ac9ccb88bba8f204bb98b17cb3c8644e472b1e
+Result = Fail (2 - CT changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp
new file mode 100644
index 0000000000..b8045d8291
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.rsp
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:26 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6
+
+Count = 0
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 469c90bb
+Result = Pass
+Payload = 00
+
+Count = 1
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 46a908ed
+Result = Fail
+
+Count = 2
+Nonce = e776620a3bd961
+Adata = 00
+CT = fdd35c4d
+Result = Fail
+
+Count = 3
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 869ce60e
+Result = Fail
+
+Count = 4
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = 1302d515
+Result = Pass
+Payload = 00
+
+Count = 5
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = 156416ee
+Result = Fail
+
+Count = 6
+Nonce = a259c114eaac89
+Adata = 00
+CT = 4fe06e92
+Result = Pass
+Payload = 00
+
+Count = 7
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 611091aa
+Result = Fail
+
+Count = 8
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 696e9371
+Result = Fail
+
+Count = 9
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = a0e0a2cb
+Result = Fail
+
+Count = 10
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 43cc0375
+Result = Fail
+
+Count = 11
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = e5417f6b
+Result = Pass
+Payload = 00
+
+Count = 12
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = fff8a068
+Result = Fail
+
+Count = 13
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = f8fa8e71
+Result = Pass
+Payload = 00
+
+Count = 14
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 0bfa2d9d
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 15
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 8207eb14d33855a52acceed17dbcbf6e
+Result = Pass
+Payload = 00
+
+Count = 16
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 60f8e127cb4d30db6df0622158cd931d
+Result = Fail
+
+Count = 17
+Nonce = e776620a3bd961
+Adata = 00
+CT = 4239f29871651e9a26b8b06ffc5b3748
+Result = Fail
+
+Count = 18
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 5d35364c621fe8959dfe70ab44700fbe
+Result = Fail
+
+Count = 19
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = e4dc5e03aacea691262ee69cee8ffbbe
+Result = Pass
+Payload = 00
+
+Count = 20
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = c8eb7643b4ed3c796c3873e8c6624e0d
+Result = Fail
+
+Count = 21
+Nonce = a259c114eaac89
+Adata = 00
+CT = f79c53fd5e69835b7e70496ea999718b
+Result = Pass
+Payload = 00
+
+Count = 22
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 687e00723a419fa81c0923b8b8e245ae
+Result = Fail
+
+Count = 23
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 499ab350309ad6091ec4aaf6bf0cbd00
+Result = Fail
+
+Count = 24
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = c27b9f14787dc5375f59d0c561a23446
+Result = Fail
+
+Count = 25
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 655c737722c78ac96582a883d407b2bb
+Result = Fail
+
+Count = 26
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = 10d3f6fe08280d45e67e58fe41a7f036
+Result = Pass
+Payload = 00
+
+Count = 27
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = b4e425e43edb92c606f7cb2de8a06932
+Result = Fail
+
+Count = 28
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = 2590df2453cb94c304ba0a2bff3f3c71
+Result = Pass
+Payload = 00
+
+Count = 29
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 1f344e30dfa95b2319e274caa5780e60
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 30
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 8a19a133
+Result = Pass
+Payload = 00
+
+Count = 31
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 2e317f1b
+Result = Fail
+
+Count = 32
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 979bdcfe
+Result = Fail
+
+Count = 33
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 8ef89acf
+Result = Fail
+
+Count = 34
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 154024b2
+Result = Pass
+Payload = 00
+
+Count = 35
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = 8dbcc439
+Result = Fail
+
+Count = 36
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 5c349fb2
+Result = Pass
+Payload = 00
+
+Count = 37
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = 79df3e02
+Result = Fail
+
+Count = 38
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = fbc2c500
+Result = Fail
+
+Count = 39
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 2fac1bca
+Result = Fail
+
+Count = 40
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = 99948f6e
+Result = Fail
+
+Count = 41
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = c59bf14c
+Result = Pass
+Payload = 00
+
+Count = 42
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = b764c393
+Result = Fail
+
+Count = 43
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 5b96f41d
+Result = Pass
+Payload = 00
+
+Count = 44
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = f7e12df1
+Result = Fail
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 45
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 97e1a8dd4259ccd2e431e057b0397fcf
+Result = Pass
+Payload = 00
+
+Count = 46
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 5a9596c511ea6a8671adefc4f2157d8b
+Result = Fail
+
+Count = 47
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 66f5c53efbc74fa02dedc303fd95133a
+Result = Fail
+
+Count = 48
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 2dfd3c852f68eace45acf433a6aa9c05
+Result = Fail
+
+Count = 49
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 5c8c9a5b97be8c7bc01ca8d693b809f9
+Result = Pass
+Payload = 00
+
+Count = 50
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = ec093121bdcd589285f2262be8db5c4e
+Result = Fail
+
+Count = 51
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 84201662b213c7a1ff0c1b3c25e4ec45
+Result = Pass
+Payload = 00
+
+Count = 52
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = bbe746d6d31e8e9745faed4095ab8d5d
+Result = Fail
+
+Count = 53
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = 646c1258dc4aa6fc380818e70e5f4328
+Result = Fail
+
+Count = 54
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 15fa37ca7f2883a4642c1ed41b8f6293
+Result = Fail
+
+Count = 55
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = c6acf5e5ded4efb2c314370ebb9e9cde
+Result = Fail
+
+Count = 56
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = 586e728193ce6db9a926b03b2d77dd6e
+Result = Pass
+Payload = 00
+
+Count = 57
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = 642a187e71feff5989e28184aded0199
+Result = Fail
+
+Count = 58
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 64864d21b6ee3fca13f07fc0486e232d
+Result = Pass
+Payload = 00
+
+Count = 59
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = 58c63ce68f132d30d177c5834344cc5d
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 60
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 64a1341679972dc5869fcf69b19d5c5ea50aa0b5e985f5b722aa8d59
+Result = Pass
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 61
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = c5b7f802bffc498c1626e3774f1d9f94045dfd8e1a10a20277d00a75
+Result = Fail
+
+Count = 62
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = bf432e246b7fa4aff8b3ada738432b51f6872ed92284db9d28588021
+Result = Fail
+
+Count = 63
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = 0d5760ad0e156e401120a1ebd1b139248784c88e10e3425437921120
+Result = Fail
+
+Count = 64
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 5acfbe5e488976d8b9b77e69a736e8c919053f9415551209dce2d25e
+Result = Pass
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 65
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = be8be6046ac58411a00c131dd4a72d565f98d87a2c89124b1ef530d0
+Result = Fail
+
+Count = 66
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = f00628e10e8e0115b4a4532a1212a23aade4090832c1972d750125f3
+Result = Pass
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 67
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = 9078151f674d5f7b56e2451b0316156f776459f17d277e0108aaaf93
+Result = Fail
+
+Count = 68
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 921cbecce3b06f3d655a5a0a4d212320d4f147575079fd23bd95e677
+Result = Fail
+
+Count = 69
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 8cab1ff22d474e9863c153e84680e2a66981f036051360477e2ebb1d
+Result = Fail
+
+Count = 70
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = 15f476b5aefe072548a54f59506d9c3b9ce29025340214be662f8684
+Result = Fail
+
+Count = 71
+Nonce = b672c91376f533
+Adata = 00
+CT = 758aa03dc72c362c43b5f85bfaa3db4a74860887a8c29e47d5642830
+Result = Pass
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 72
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ec645769b22161567e6a7e23aa06575bc767a34aa54d3cba01472fe1
+Result = Fail
+
+Count = 73
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 615cbeabbe163ba8bc9c073df9ad40833fcf3f424644ccc37aa999d7
+Result = Pass
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 74
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = 0ed6cc6451de57ca672d56dee45d4548a810d5c49dfe442dd27b7cf2
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 75
+Nonce = a544218dadd3c1
+Adata = 00
+CT = bc51c3925a960e7732533e4ef3a4f69ee6826de952bcb0fd374f3bb6db8377ebfc79674858c4f305
+Result = Pass
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 76
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = afa1fa8e8a70e26b02161150556d604101fdf423f332c3363275f2a4907d51b734fe7238cebbd48f
+Result = Fail
+
+Count = 77
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = 72bc8ef21a847047091b673ccf231d35ecf6f4049741703be672f1f22cbe4a5305f19aaa6967237b
+Result = Fail
+
+Count = 78
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = b719f6555fc4e5424273f5903d5672af460413110278707f400b152113c3976be63dcd9e7a84ddac
+Result = Fail
+
+Count = 79
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 4539bb13382b034ddb16a3329148f9243a4eee998fe444aff2870ce198af11f4fb698a67af6c89ad
+Result = Pass
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 80
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = 47cbb909cb12fa0a4b0f1aefd54c52d1edd1533290f76b8ccc98b3f5758972bf08ea9e88dc6e54ed
+Result = Fail
+
+Count = 81
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = 6d0f928352a17d63aca1899cbd305e1f831f1638d27c1e24432704eff9b6830476db3d30d4c103e4
+Result = Pass
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 82
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = e0e686d917f78b3b0058fed7b084976244789073a6305ff571256981db86f1e768170a104ebfb81d
+Result = Fail
+
+Count = 83
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 960c573f5d6934a4cac49d06998f827b3d665cf02c998fe55efbbae6a346863a93d52e0321cef8b2
+Result = Fail
+
+Count = 84
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 7cf8f4806848e34aa7d3bd7e2cb9f5d9ff21395ff6d34826ac2fdc3cc683f6120e405f446a10e0f3
+Result = Fail
+
+Count = 85
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = e4f6445ca36e7ee3323f11f6a5ca8ded0c85871e092aa687d254f7765b6155054a5efde28dd38750
+Result = Fail
+
+Count = 86
+Nonce = b672c91376f533
+Adata = 00
+CT = f23ac1426cb1130c9a0913b347d8efafb6ed125913aa678a9dc42d22a5436bc12eff5505edb25e19
+Result = Pass
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 87
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ac9f131389181b1023f1ee47633aa433fc5d93a87d9ece962db05feb368ab772d977fd97b35262fa
+Result = Fail
+
+Count = 88
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 773b8eea2e9830297ac11d3c1f6ea4008c96040e83d76d55789d2043179fdd8fdcbd52313b7b15cb
+Result = Pass
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 89
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = d3fae92043c419fe8ac0d7491ca8041ad089559d895103cf079a2bac0ab4bc249bbdb330181cdd16
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 90
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 63e00d30e4b08fd2a1cc8d70fab327b2368e77a93be4f4123d14fb3f
+Result = Pass
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 91
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = bb5425b3869b76856ec58e39886fb6f6f2ac13fe44cb132d8d0c0099
+Result = Fail
+
+Count = 92
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 2ca3be419d5be5ed682f8954d2c20efd9e6d360814735daeefd4365c
+Result = Fail
+
+Count = 93
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = 3d34bda62db39d6118d6fd5cd38f1a3820ca69ce584b94a2a4ccbef1
+Result = Fail
+
+Count = 94
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 377b2f1e7bd9e3d1077038e084f61950761361095f7eeebbf1a72afc
+Result = Pass
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 95
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 9cef6c889ff51666df9dd1dd2215c15f4b2078a29373c106be4f5f9a
+Result = Fail
+
+Count = 96
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = 6cab3060bf3b33b163b933c2ed0ba51406810b54d0edcf5c9d0ef4f7
+Result = Pass
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 97
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = f9543a659e9a8b7d75dd859df923817452735f5051726422c08a9e85
+Result = Fail
+
+Count = 98
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 0d20bf6a9d02da72091d94cdb38743bfea2473d3ab62dcad75dd819a
+Result = Fail
+
+Count = 99
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = 8bca01e6ebd7ebcdfe52b88e314670ffeb35882fc05394b386e205f9
+Result = Fail
+
+Count = 100
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 7061c84e2e1d9d58013543ff82666055a1f055c1296c42c8f73a8bf0
+Result = Fail
+
+Count = 101
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = c5aa500d1f7c09a590e9d15d6860c4433684e04dd6bc5c8f94f223f0
+Result = Pass
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 102
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = e3efa7971e27ba1245ee9491ebdbb28ad9b24b325da5760417af8b14
+Result = Fail
+
+Count = 103
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = 852cca903d7fdf899807bd14642057534c8a0ccacb8c7b8fb4d35d44
+Result = Pass
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 104
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e04fd4f5b60833021ed57c98de300bb68d0d892b2bf68e080bc044b1
+Result = Fail
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 105
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = f0050ad16392021a3f40207bed3521fb1e9f808f49830c423a578d179902f912f9ea1afbce1120b3
+Result = Pass
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 106
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = c408190d0fbf5034f83b24a8ed9657331a7ce141de4fae769084607b83bd06e6442eac8dacf583cc
+Result = Fail
+
+Count = 107
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 52b3d31d02d1b92b38cbae8c510204dde6bf9588e994296c9002a46cfb734290924a15e9c3d99924
+Result = Fail
+
+Count = 108
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = f80190470212ce1e64bf4c64ca0133d90469abf87a8233c2b238e316c3f9adccce95e8c8b9c7e8d2
+Result = Fail
+
+Count = 109
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 254b847d4175bbb44a82b4e805514fa444c224710933f3ec8aaa3f0133234c0cd91609982adc034b
+Result = Pass
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 110
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 7a5c7bc02aa69efc5a159d653f3993399f69e20752c3b00633255731cd88345860da913bc696fdc1
+Result = Fail
+
+Count = 111
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = c3618c991b15de641d291419ff6957e8b9ae5046dd8c6f08fafb76adf12f36740347e3edae62bca4
+Result = Pass
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 112
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = 240927bfd671a92aef0311395ad55ae42233ecee53873da4066f55f23d4e55bcbbbf2312ea2d8071
+Result = Fail
+
+Count = 113
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 4731a7e690c77cd47582ce54a1cec23d94c856b93a9fc767004753689cc84810b8414f1464c0c5b9
+Result = Fail
+
+Count = 114
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = f0ea12eaff20c3a50674aa1546aaae3bd5c9249108535b21504da83478ede24026ec91fb12769e4b
+Result = Fail
+
+Count = 115
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 5b164d9752ad6c497a7ab2d0bf8be68fea084ea5839b07b7c9fcf9b9fd5e99767a7b1679b57ea961
+Result = Fail
+
+Count = 116
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = bd37326da18e5ac79a1a9512f724bb539530868576b79c67acb5a51d10a58d6584fbe73f1063c31b
+Result = Pass
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 117
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = 0455b4dd1069281e10531c0dc180ced9a5ef5d3fe0007470ce54cd7623a80a176f29a01b3abb642e
+Result = Fail
+
+Count = 118
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = ecd337640022635ce1ed273756d02b7feeb2515614c1fadc95c66d3f411b478853886afd177d88c3
+Result = Pass
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 119
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e25d7c9fb388596b13a13b885d5b24e31579a3494ad256da830b2b6317716b3975e2b101aebdd920
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 120
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 92d00fbe
+Result = Pass
+Payload = 00
+
+Count = 121
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = 9143e5c4
+Result = Fail
+
+Count = 122
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 54337466
+Result = Fail
+
+Count = 123
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = bf0bf84c
+Result = Fail
+
+Count = 124
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = 11250056
+Result = Pass
+Payload = 00
+
+Count = 125
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 13de5339
+Result = Fail
+
+Count = 126
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = 4eed80fd
+Result = Pass
+Payload = 00
+
+Count = 127
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = 4bc2e450
+Result = Fail
+
+Count = 128
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = b30e6bbd
+Result = Fail
+
+Count = 129
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = f7c11fe2
+Result = Fail
+
+Count = 130
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 76673751
+Result = Fail
+
+Count = 131
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 9a5382c3
+Result = Pass
+Payload = 00
+
+Count = 132
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9e632f56
+Result = Fail
+
+Count = 133
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = e1842c46
+Result = Pass
+Payload = 00
+
+Count = 134
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 9f644671
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 135
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 93af11a08379eb37a16aa2837f09d69d
+Result = Pass
+Payload = 00
+
+Count = 136
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = d19b0c14ec686a7961ca7c386d125a65
+Result = Fail
+
+Count = 137
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 02ea916d60e2ceec6d9dc9b1185569b3
+Result = Fail
+
+Count = 138
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = fabd2d0c422b47d363ea9936ff4a311b
+Result = Fail
+
+Count = 139
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = b3884b69d117146cfa5529901753ddc0
+Result = Pass
+Payload = 00
+
+Count = 140
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 7162026b6306e74fe32ece8433801bc2
+Result = Fail
+
+Count = 141
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = b53d93cbfd3d5cf3720cef5080bc7224
+Result = Pass
+Payload = 00
+
+Count = 142
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = c8bbecf69ecf8d10f0863bb4b7cbed51
+Result = Fail
+
+Count = 143
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = 6037145cc23a175760ae4b573907c80c
+Result = Fail
+
+Count = 144
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = df7ea77425d631f652ffe096a8157f71
+Result = Fail
+
+Count = 145
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 7182b25ef5b113c13fa8f6769e74f1e2
+Result = Fail
+
+Count = 146
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 0a5d1bc02c5fe096a8b9d94d1267c49a
+Result = Pass
+Payload = 00
+
+Count = 147
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9eb6d9757ec7c56cc8c79461e0017486
+Result = Fail
+
+Count = 148
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = 1eda43bf07f2bf003107f3a0ba3a4c18
+Result = Pass
+Payload = 00
+
+Count = 149
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 5287cc160c5dd3a0f9c1986aac2a621c
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 150
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 866d4227
+Result = Pass
+Payload = 00
+
+Count = 151
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 94cb1127
+Result = Fail
+
+Count = 152
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = 82c2b67a
+Result = Fail
+
+Count = 153
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 8c8283f9
+Result = Fail
+
+Count = 154
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = c4ac0952
+Result = Pass
+Payload = 00
+
+Count = 155
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = c59aa931
+Result = Fail
+
+Count = 156
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = 27c3953d
+Result = Pass
+Payload = 00
+
+Count = 157
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = cb1ac8eb
+Result = Fail
+
+Count = 158
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4dcc55cc
+Result = Fail
+
+Count = 159
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 727d8f5e
+Result = Fail
+
+Count = 160
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 5aa56a54
+Result = Fail
+
+Count = 161
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = c38fbdff
+Result = Pass
+Payload = 00
+
+Count = 162
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 6be30c42
+Result = Fail
+
+Count = 163
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = d34e90bb
+Result = Pass
+Payload = 00
+
+Count = 164
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = 4a5d14bc
+Result = Fail
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 165
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 867b0d87cf6e0f718200a97b4f6d5ad5
+Result = Pass
+Payload = 00
+
+Count = 166
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 677a040d46ee3f2b7838273bdad14f16
+Result = Fail
+
+Count = 167
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = f650d46ade2cbabbc68ead6df1ea0c37
+Result = Fail
+
+Count = 168
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 11b8fe8c139ee38f77fd8fa552cbff67
+Result = Fail
+
+Count = 169
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = ad879c64425e6c1ec4841bbb0f99aa8b
+Result = Pass
+Payload = 00
+
+Count = 170
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = 3c64f8731930ae000162c10654531066
+Result = Fail
+
+Count = 171
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = e2751f153fc76c0dec5e0cf2d30c1a28
+Result = Pass
+Payload = 00
+
+Count = 172
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = 76127bf891141e73854752ed10c02bd0
+Result = Fail
+
+Count = 173
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4bd833f9da0496e5f6a08a05d02df385
+Result = Fail
+
+Count = 174
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 05f166328a67a8c58b10a7348f3df612
+Result = Fail
+
+Count = 175
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 42499bcd949a5163855a9794f11f917e
+Result = Fail
+
+Count = 176
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = fc85464a81fe372c12c9e4f0f3bf9c37
+Result = Pass
+Payload = 00
+
+Count = 177
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 8c7501f423647dee77668858c5e350bb
+Result = Fail
+
+Count = 178
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = b1c09b093788da19e33c5a6e82ed9627
+Result = Pass
+Payload = 00
+
+Count = 179
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = d2231ee1455b0bc337c4f8173fb8647c
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 180
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = c2fe12658139f5d0dd22cadf2e901695b579302a72fc56083ebc7720
+Result = Pass
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 181
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = 94748ba81229e53c38583a8564b23ebbafc6f6efdf4c2a81c44db2c9
+Result = Fail
+
+Count = 182
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 1d670ccf3e9ba59186c48da2e5bd0ab21973eee2ea2985bf83a09067
+Result = Fail
+
+Count = 183
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 2c8c80ff10fac1bf6c9c83533c1514ee032c0983730b0657392ae25d
+Result = Fail
+
+Count = 184
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = e1b4ec4279bb62902c12521e6b874171695c5da46c647cc03b91ff03
+Result = Pass
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 185
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = b5dda89fe879d6a665b99285b6d937fd5877ebef4de049fb64b837fb
+Result = Fail
+
+Count = 186
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = 224db21beb8cd0069007660e783c3f85706b014128368aab2a4e56a7
+Result = Pass
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 187
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = ba1ce3a799e1173178b6788723005566f9269d5828c85d28e960a769
+Result = Fail
+
+Count = 188
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 79d59e4bb251988c019c4eaaee2a2513f9cb0521334018fded14a5a5
+Result = Fail
+
+Count = 189
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = af4350795f24087aa05070d6d5f55ebb12d7ad3141066866d7d6c61d
+Result = Fail
+
+Count = 190
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 22d2da531be1f0d1da4bc21f984d29bf56bed2e92da6bf42d0605b84
+Result = Fail
+
+Count = 191
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = 61b46c9024eed3989064a52df90349c18e14e4b552779d3f8f9d6814
+Result = Pass
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 192
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 539799c2b22a33dd648fc4497d12f9455beaf932f1eaaff4d930f5ce
+Result = Fail
+
+Count = 193
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 52f8205534447d722be2b9377f7395938cc88af081a11ccb0d83fa19
+Result = Pass
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 194
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = d11c892ae155098f5e4b5fe60c7afd74fb2dbcc4db956556f243e273
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 195
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 3341168eb8c48468c414347fb08f71d2086f7c2d1bd581ce1ac68bd42f5ec7fa7e068cc0ecd79c2a
+Result = Pass
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 196
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = d543acda712b898cbb27b8f598b2e4438ce587a836e2785147c3338a2400809e739b63ba8227d2f9
+Result = Fail
+
+Count = 197
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 39a8af5c976b995ea8049e55b68bc65503592ab00915638646288ce9dd1c7088c752e35947fdca98
+Result = Fail
+
+Count = 198
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 950fbf6445f6ffb68178f52f5079d0c6081a48ae1f267a0b7fd89caef9388fbb82361b8d53d9edc6
+Result = Fail
+
+Count = 199
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = fbfed2c94f50ca10466da9903ef85833ad48ca00556e66d14d8b30df941f3536ffb42083ef0e1c30
+Result = Pass
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 200
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = 2ebfeb7a843618b37025352df3538526517ed320adfb486c04cf3426e8f975125a7eed00e5f33b6c
+Result = Fail
+
+Count = 201
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = dae13e6967c8b1ee0dd2d5ba1dd1de69f22c95da39528f9ef78e9e5e9faa058112af57f4ac78db2c
+Result = Pass
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 202
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = e683040a0bcf04c1748e7746400d6ef0f7cd8e77a29517790c63959ce534a0f87fb42a9b000dec84
+Result = Fail
+
+Count = 203
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 829e50e8c09e727a58287e6eb7d38edeb8ab39db279c06397d1a2111dc21aec79ef73193b306d31f
+Result = Fail
+
+Count = 204
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = 873c91e76dca0062ae66325aefb84ece3e98928f8dbc5fee7c516d2d1a8318893923f398ca249401
+Result = Fail
+
+Count = 205
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 343f6c86f2b852ac388a096faec4472107a924aba56d0cb88055e777bb57eb49497cd2e233ee06fd
+Result = Fail
+
+Count = 206
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = a654238fb8b05e293dba07f9d68d75a7f0fbf40fe20edaeba1586bf922412e73ce338e372615c3bc
+Result = Pass
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 207
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 4846816923ed9f0254bdd0be01028f75061d3594ad3a45bd03538d108df6ecd6f39acfe076ba5fb8
+Result = Fail
+
+Count = 208
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 765067ef768908d91ee4c3923943e0c7be70e2e06db99a4b3e3f51ee37fdcc5d81dd85d9e9d4f44e
+Result = Pass
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 209
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = e58ea6c1522e5a3e93a85edd05ae80d6cf5c4dd6d604a8f8d8a906488f79ad5d2234d72458dcfcd4
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 210
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = c0ea400b599561e7905b99262b4565d5c3dc49fad84d7c69ef891339
+Result = Pass
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 211
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 60871e03ea0eb968536c99f926ea24ef43d41272ad9fb7f63d488623
+Result = Fail
+
+Count = 212
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 81d7859dcbe51dcc94fe2591cd3b0540003d49a8c4dccbf4527e5ed0
+Result = Fail
+
+Count = 213
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = bef380ad725b65fb5fceeabf09c665bc35089f434ec831494d20d5fa
+Result = Fail
+
+Count = 214
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = fabe11c9629e598228f5209f3dbcc641fe4b1a22cadb0821d2898c3b
+Result = Pass
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 215
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = b7eb87f84951640de731d4093f1a4ed5f831138a27465d3941e92090
+Result = Fail
+
+Count = 216
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = d88f8fcd772125212ce09c2a6e5b5693dd35073f992004f0d18fc889
+Result = Pass
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 217
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = d2d7d52b11304fc1d15b8c20e296ba7c63d99f4ce86cc8ae0f39ecea
+Result = Fail
+
+Count = 218
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = ae1d9f82efb464d5dc2018cffa309634c09b34d1122c4bd994b1d516
+Result = Fail
+
+Count = 219
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 477c985d92ad1b69d22315235a29e3d3a5991487cbdc8d11d394d047
+Result = Fail
+
+Count = 220
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = d1c085c75d808dc6db493b8a0b4d884e0700d2844a1b4b46bd3d22eb
+Result = Fail
+
+Count = 221
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = 76bdd9a7b34bf14ae121a87fdfa144f71b848744af6a2f0b1c0d067c
+Result = Pass
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 222
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 413e2e8df9d65b4e5d3b63a738258aaee643f364be9a01b974192744
+Result = Fail
+
+Count = 223
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 617d8036e2039d516709062379e0550cbd71ebb90fea967c79018ad5
+Result = Pass
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 224
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 40e609c739e409750a6c41d9c6ea64ce36f70711b4ca3e365c916f91
+Result = Fail
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+
+Count = 225
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 8d34cdca37ce77be68f65baf3382e31efa693e63f914a781367f30f2eaad8c063ca50795acd90203
+Result = Pass
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 226
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 516c0095cc3d85fd55e48da17c592e0c7014b9daafb82bdc4b41096dfdbe9cc1ab610f8f3e038d16
+Result = Fail
+
+Count = 227
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 0293eae9f8d8bd7ad45357f733fc7b5d990d894783e18501d81ec96df41b8fa8262ed2db880b5e85
+Result = Fail
+
+Count = 228
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = 256bad8295e67d8d450f5ecc8276920ec23b1156c57be7c96ee80f60f72db2cbf25b2f8c6af8749c
+Result = Fail
+
+Count = 229
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = 6df09613ea986c2d91a57a45a0942cbf20e0dfca12fbda8c945ee6db24aea5f5098952f1203339ce
+Result = Pass
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 230
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = c5b64577d3c34e50f7da5072db5bda1d1d2c6db1a4f1183e2cc4c90ac3f798957cb09a05868a8ad5
+Result = Fail
+
+Count = 231
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = 2bfe51f1f43b982d47f76ea8206ddbf585d6f30cec0d4ef16b1556631d3b52bf24154afec1448ef6
+Result = Pass
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 232
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = 1622ae109073f44a4596722d9943fea774dfc2a1f939fc0914f42ec81e3af71c9a5de7e0ac16ca69
+Result = Fail
+
+Count = 233
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = 4c0b361a766d366d983c41e793d75635e17f6eab2eadcf9743d67d90850c4c76a43df1f95170b29b
+Result = Fail
+
+Count = 234
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 5b02347f30213df7f1506d7dca41b838c92aea0f190c5dba7bd5d5c8c098299394333b34fae9a110
+Result = Fail
+
+Count = 235
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = c77283ca15484d82469ce7249d1fb8e5f4c3bc8245fb4d97e26149d4a9711be81b4f69aa9fabd7f6
+Result = Fail
+
+Count = 236
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = bf0d219bb50fcc1d51f654bb0fd8b44efa25aef39e2f11afe47d00f2eebb544e6ba7559ac2f34edb
+Result = Pass
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 237
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 1609f8de59da4f50ce034977d132d4f9881a9b85ffa5bb886fa3fddc87690a359fe55f8fa12ba749
+Result = Fail
+
+Count = 238
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881567a6b4426f1667136bed4a5e32a2bc1
+Result = Pass
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 239
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 27c575be0b99af9b106f53f471c31cac4d54ea0bcb602a33fb67bb6092cd579f722ae9b680da083d
+Result = Fail
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt
new file mode 100644
index 0000000000..6d9a3eadcb
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/DVPT256.txt
@@ -0,0 +1,1589 @@
+# CAVS 11.0
+# "CCM-DVPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:26 2011
+
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = eda32f751456e33195f1f499cf2dc7c97ea127b6d488f211ccc5126fbb24afa6
+
+Count = 0
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 469c90bb
+Result = Pass (0)
+Payload = 00
+
+Count = 1
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 46a908ed
+Result = Fail (2 - CT changed)
+
+Count = 2
+Nonce = e776620a3bd961
+Adata = 00
+CT = fdd35c4d
+Result = Fail (1 - Adata changed)
+
+Count = 3
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 869ce60e
+Result = Fail (1 - Adata changed)
+
+Count = 4
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = 1302d515
+Result = Pass (0)
+Payload = 00
+
+Count = 5
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = 156416ee
+Result = Fail (2 - CT changed)
+
+Count = 6
+Nonce = a259c114eaac89
+Adata = 00
+CT = 4fe06e92
+Result = Pass (0)
+Payload = 00
+
+Count = 7
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 611091aa
+Result = Fail (2 - CT changed)
+
+Count = 8
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 696e9371
+Result = Fail (2 - CT changed)
+
+Count = 9
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = a0e0a2cb
+Result = Fail (2 - CT changed)
+
+Count = 10
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 43cc0375
+Result = Fail (1 - Adata changed)
+
+Count = 11
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = e5417f6b
+Result = Pass (0)
+Payload = 00
+
+Count = 12
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = fff8a068
+Result = Fail (1 - Adata changed)
+
+Count = 13
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = f8fa8e71
+Result = Pass (0)
+Payload = 00
+
+Count = 14
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 0bfa2d9d
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 15
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 8207eb14d33855a52acceed17dbcbf6e
+Result = Pass (0)
+Payload = 00
+
+Count = 16
+Nonce = d3d5424e20fbec
+Adata = 00
+CT = 60f8e127cb4d30db6df0622158cd931d
+Result = Fail (2 - CT changed)
+
+Count = 17
+Nonce = e776620a3bd961
+Adata = 00
+CT = 4239f29871651e9a26b8b06ffc5b3748
+Result = Fail (1 - Adata changed)
+
+Count = 18
+Nonce = 6c7a3be9f9ad55
+Adata = 00
+CT = 5d35364c621fe8959dfe70ab44700fbe
+Result = Fail (1 - Adata changed)
+
+Count = 19
+Nonce = dbb3923156cfd6
+Adata = 00
+CT = e4dc5e03aacea691262ee69cee8ffbbe
+Result = Pass (0)
+Payload = 00
+
+Count = 20
+Nonce = b390f67eaef8f5
+Adata = 00
+CT = c8eb7643b4ed3c796c3873e8c6624e0d
+Result = Fail (2 - CT changed)
+
+Count = 21
+Nonce = a259c114eaac89
+Adata = 00
+CT = f79c53fd5e69835b7e70496ea999718b
+Result = Pass (0)
+Payload = 00
+
+Count = 22
+Nonce = 7fc8804fef18ef
+Adata = 00
+CT = 687e00723a419fa81c0923b8b8e245ae
+Result = Fail (2 - CT changed)
+
+Count = 23
+Nonce = fbaf4cbc49fa0f
+Adata = 00
+CT = 499ab350309ad6091ec4aaf6bf0cbd00
+Result = Fail (2 - CT changed)
+
+Count = 24
+Nonce = 2ed0c8761dbf04
+Adata = 00
+CT = c27b9f14787dc5375f59d0c561a23446
+Result = Fail (2 - CT changed)
+
+Count = 25
+Nonce = 346bb04ea0db86
+Adata = 00
+CT = 655c737722c78ac96582a883d407b2bb
+Result = Fail (1 - Adata changed)
+
+Count = 26
+Nonce = e1be89af98ffd7
+Adata = 00
+CT = 10d3f6fe08280d45e67e58fe41a7f036
+Result = Pass (0)
+Payload = 00
+
+Count = 27
+Nonce = a6a0d57aaaf012
+Adata = 00
+CT = b4e425e43edb92c606f7cb2de8a06932
+Result = Fail (1 - Adata changed)
+
+Count = 28
+Nonce = 1aa758eb2f9a28
+Adata = 00
+CT = 2590df2453cb94c304ba0a2bff3f3c71
+Result = Pass (0)
+Payload = 00
+
+Count = 29
+Nonce = 2911167fc98fc3
+Adata = 00
+CT = 1f344e30dfa95b2319e274caa5780e60
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = e1b8a927a95efe94656677b692662000278b441c79e879dd5c0ddc758bdc9ee8
+
+Count = 30
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 8a19a133
+Result = Pass (0)
+Payload = 00
+
+Count = 31
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 2e317f1b
+Result = Fail (2 - CT changed)
+
+Count = 32
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 979bdcfe
+Result = Fail (1 - Adata changed)
+
+Count = 33
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 8ef89acf
+Result = Fail (1 - Adata changed)
+
+Count = 34
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 154024b2
+Result = Pass (0)
+Payload = 00
+
+Count = 35
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = 8dbcc439
+Result = Fail (2 - CT changed)
+
+Count = 36
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 5c349fb2
+Result = Pass (0)
+Payload = 00
+
+Count = 37
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = 79df3e02
+Result = Fail (2 - CT changed)
+
+Count = 38
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = fbc2c500
+Result = Fail (2 - CT changed)
+
+Count = 39
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 2fac1bca
+Result = Fail (2 - CT changed)
+
+Count = 40
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = 99948f6e
+Result = Fail (1 - Adata changed)
+
+Count = 41
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = c59bf14c
+Result = Pass (0)
+Payload = 00
+
+Count = 42
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = b764c393
+Result = Fail (1 - Adata changed)
+
+Count = 43
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 5b96f41d
+Result = Pass (0)
+Payload = 00
+
+Count = 44
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = f7e12df1
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 45
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 97e1a8dd4259ccd2e431e057b0397fcf
+Result = Pass (0)
+Payload = 00
+
+Count = 46
+Nonce = 3c0e2815d37d844f7ac240ba9d
+Adata = 00
+CT = 5a9596c511ea6a8671adefc4f2157d8b
+Result = Fail (2 - CT changed)
+
+Count = 47
+Nonce = 75549e7e5657e5fe19872fcee0
+Adata = 00
+CT = 66f5c53efbc74fa02dedc303fd95133a
+Result = Fail (1 - Adata changed)
+
+Count = 48
+Nonce = d071ff72735820d73485870e83
+Adata = 00
+CT = 2dfd3c852f68eace45acf433a6aa9c05
+Result = Fail (1 - Adata changed)
+
+Count = 49
+Nonce = 79ac204a26b9fee1132370c20f
+Adata = 00
+CT = 5c8c9a5b97be8c7bc01ca8d693b809f9
+Result = Pass (0)
+Payload = 00
+
+Count = 50
+Nonce = a64bbc3d6d377dab513f7d9ce8
+Adata = 00
+CT = ec093121bdcd589285f2262be8db5c4e
+Result = Fail (2 - CT changed)
+
+Count = 51
+Nonce = 0545fd9ecbc73ccdbbbd4244fd
+Adata = 00
+CT = 84201662b213c7a1ff0c1b3c25e4ec45
+Result = Pass (0)
+Payload = 00
+
+Count = 52
+Nonce = 182fb47a12becf0bfe65df1287
+Adata = 00
+CT = bbe746d6d31e8e9745faed4095ab8d5d
+Result = Fail (2 - CT changed)
+
+Count = 53
+Nonce = f342059a6f9dc14226b40debc4
+Adata = 00
+CT = 646c1258dc4aa6fc380818e70e5f4328
+Result = Fail (2 - CT changed)
+
+Count = 54
+Nonce = 6cbfe6bb4c9b171b93d28e9f8f
+Adata = 00
+CT = 15fa37ca7f2883a4642c1ed41b8f6293
+Result = Fail (2 - CT changed)
+
+Count = 55
+Nonce = 82877df921c6ade43064ad963e
+Adata = 00
+CT = c6acf5e5ded4efb2c314370ebb9e9cde
+Result = Fail (1 - Adata changed)
+
+Count = 56
+Nonce = 0a37f2e7c66490e97285f1b09e
+Adata = 00
+CT = 586e728193ce6db9a926b03b2d77dd6e
+Result = Pass (0)
+Payload = 00
+
+Count = 57
+Nonce = d7b9c346ce2f8bad9623122e10
+Adata = 00
+CT = 642a187e71feff5989e28184aded0199
+Result = Fail (1 - Adata changed)
+
+Count = 58
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+Adata = 00
+CT = 64864d21b6ee3fca13f07fc0486e232d
+Result = Pass (0)
+Payload = 00
+
+Count = 59
+Nonce = b6ce7d00731184b24428df046b
+Adata = 00
+CT = 58c63ce68f132d30d177c5834344cc5d
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = af063639e66c284083c5cf72b70d8bc277f5978e80d9322d99f2fdc718cda569
+
+Count = 60
+Nonce = a544218dadd3c1
+Adata = 00
+CT = 64a1341679972dc5869fcf69b19d5c5ea50aa0b5e985f5b722aa8d59
+Result = Pass (0)
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 61
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = c5b7f802bffc498c1626e3774f1d9f94045dfd8e1a10a20277d00a75
+Result = Fail (2 - CT changed)
+
+Count = 62
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = bf432e246b7fa4aff8b3ada738432b51f6872ed92284db9d28588021
+Result = Fail (1 - Adata changed)
+
+Count = 63
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = 0d5760ad0e156e401120a1ebd1b139248784c88e10e3425437921120
+Result = Fail (1 - Adata changed)
+
+Count = 64
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 5acfbe5e488976d8b9b77e69a736e8c919053f9415551209dce2d25e
+Result = Pass (0)
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 65
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = be8be6046ac58411a00c131dd4a72d565f98d87a2c89124b1ef530d0
+Result = Fail (2 - CT changed)
+
+Count = 66
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = f00628e10e8e0115b4a4532a1212a23aade4090832c1972d750125f3
+Result = Pass (0)
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 67
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = 9078151f674d5f7b56e2451b0316156f776459f17d277e0108aaaf93
+Result = Fail (2 - CT changed)
+
+Count = 68
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 921cbecce3b06f3d655a5a0a4d212320d4f147575079fd23bd95e677
+Result = Fail (2 - CT changed)
+
+Count = 69
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 8cab1ff22d474e9863c153e84680e2a66981f036051360477e2ebb1d
+Result = Fail (2 - CT changed)
+
+Count = 70
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = 15f476b5aefe072548a54f59506d9c3b9ce29025340214be662f8684
+Result = Fail (1 - Adata changed)
+
+Count = 71
+Nonce = b672c91376f533
+Adata = 00
+CT = 758aa03dc72c362c43b5f85bfaa3db4a74860887a8c29e47d5642830
+Result = Pass (0)
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 72
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ec645769b22161567e6a7e23aa06575bc767a34aa54d3cba01472fe1
+Result = Fail (1 - Adata changed)
+
+Count = 73
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 615cbeabbe163ba8bc9c073df9ad40833fcf3f424644ccc37aa999d7
+Result = Pass (0)
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 74
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = 0ed6cc6451de57ca672d56dee45d4548a810d5c49dfe442dd27b7cf2
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 75
+Nonce = a544218dadd3c1
+Adata = 00
+CT = bc51c3925a960e7732533e4ef3a4f69ee6826de952bcb0fd374f3bb6db8377ebfc79674858c4f305
+Result = Pass (0)
+Payload = d3d5424e20fbec43ae495353ed830271515ab104f8860c98
+
+Count = 76
+Nonce = bfcda8b5a2d0d2
+Adata = 00
+CT = afa1fa8e8a70e26b02161150556d604101fdf423f332c3363275f2a4907d51b734fe7238cebbd48f
+Result = Fail (2 - CT changed)
+
+Count = 77
+Nonce = 6bae7f35c56b27
+Adata = 00
+CT = 72bc8ef21a847047091b673ccf231d35ecf6f4049741703be672f1f22cbe4a5305f19aaa6967237b
+Result = Fail (1 - Adata changed)
+
+Count = 78
+Nonce = c5e4214b1bf209
+Adata = 00
+CT = b719f6555fc4e5424273f5903d5672af460413110278707f400b152113c3976be63dcd9e7a84ddac
+Result = Fail (1 - Adata changed)
+
+Count = 79
+Nonce = 9d773a31fe2ec7
+Adata = 00
+CT = 4539bb13382b034ddb16a3329148f9243a4eee998fe444aff2870ce198af11f4fb698a67af6c89ad
+Result = Pass (0)
+Payload = 839d8cfa2c921c3cceb7d1f46bd2eaad706e53f64523d8c0
+
+Count = 80
+Nonce = f42cb0cce9efb6
+Adata = 00
+CT = 47cbb909cb12fa0a4b0f1aefd54c52d1edd1533290f76b8ccc98b3f5758972bf08ea9e88dc6e54ed
+Result = Fail (2 - CT changed)
+
+Count = 81
+Nonce = 24b7a65391f88b
+Adata = 00
+CT = 6d0f928352a17d63aca1899cbd305e1f831f1638d27c1e24432704eff9b6830476db3d30d4c103e4
+Result = Pass (0)
+Payload = 3bed52236182c19418867d468dbf47c8aac46c02445f99bb
+
+Count = 82
+Nonce = d2a7eb45780df3
+Adata = 00
+CT = e0e686d917f78b3b0058fed7b084976244789073a6305ff571256981db86f1e768170a104ebfb81d
+Result = Fail (2 - CT changed)
+
+Count = 83
+Nonce = 046cbfd26093d8
+Adata = 00
+CT = 960c573f5d6934a4cac49d06998f827b3d665cf02c998fe55efbbae6a346863a93d52e0321cef8b2
+Result = Fail (2 - CT changed)
+
+Count = 84
+Nonce = 51b13b0b04d077
+Adata = 00
+CT = 7cf8f4806848e34aa7d3bd7e2cb9f5d9ff21395ff6d34826ac2fdc3cc683f6120e405f446a10e0f3
+Result = Fail (2 - CT changed)
+
+Count = 85
+Nonce = ce2e9967bf9eb7
+Adata = 00
+CT = e4f6445ca36e7ee3323f11f6a5ca8ded0c85871e092aa687d254f7765b6155054a5efde28dd38750
+Result = Fail (1 - Adata changed)
+
+Count = 86
+Nonce = b672c91376f533
+Adata = 00
+CT = f23ac1426cb1130c9a0913b347d8efafb6ed125913aa678a9dc42d22a5436bc12eff5505edb25e19
+Result = Pass (0)
+Payload = 4f7a561e61b7861719e4445057ac9b74a9be953b772b09ec
+
+Count = 87
+Nonce = 62f6f1872462d8
+Adata = 00
+CT = ac9f131389181b1023f1ee47633aa433fc5d93a87d9ece962db05feb368ab772d977fd97b35262fa
+Result = Fail (1 - Adata changed)
+
+Count = 88
+Nonce = a6d01fb88ca547
+Adata = 00
+CT = 773b8eea2e9830297ac11d3c1f6ea4008c96040e83d76d55789d2043179fdd8fdcbd52313b7b15cb
+Result = Pass (0)
+Payload = a36155de477364236591e453008114075b4872120ef17264
+
+Count = 89
+Nonce = 46ad6ebbd8644a
+Adata = 00
+CT = d3fae92043c419fe8ac0d7491ca8041ad089559d895103cf079a2bac0ab4bc249bbdb330181cdd16
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = f7079dfa3b5c7b056347d7e437bcded683abd6e2c9e069d333284082cbb5d453
+
+Count = 90
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = 63e00d30e4b08fd2a1cc8d70fab327b2368e77a93be4f4123d14fb3f
+Result = Pass (0)
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 91
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = bb5425b3869b76856ec58e39886fb6f6f2ac13fe44cb132d8d0c0099
+Result = Fail (2 - CT changed)
+
+Count = 92
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 2ca3be419d5be5ed682f8954d2c20efd9e6d360814735daeefd4365c
+Result = Fail (1 - Adata changed)
+
+Count = 93
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = 3d34bda62db39d6118d6fd5cd38f1a3820ca69ce584b94a2a4ccbef1
+Result = Fail (1 - Adata changed)
+
+Count = 94
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 377b2f1e7bd9e3d1077038e084f61950761361095f7eeebbf1a72afc
+Result = Pass (0)
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 95
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 9cef6c889ff51666df9dd1dd2215c15f4b2078a29373c106be4f5f9a
+Result = Fail (2 - CT changed)
+
+Count = 96
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = 6cab3060bf3b33b163b933c2ed0ba51406810b54d0edcf5c9d0ef4f7
+Result = Pass (0)
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 97
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = f9543a659e9a8b7d75dd859df923817452735f5051726422c08a9e85
+Result = Fail (2 - CT changed)
+
+Count = 98
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 0d20bf6a9d02da72091d94cdb38743bfea2473d3ab62dcad75dd819a
+Result = Fail (2 - CT changed)
+
+Count = 99
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = 8bca01e6ebd7ebcdfe52b88e314670ffeb35882fc05394b386e205f9
+Result = Fail (2 - CT changed)
+
+Count = 100
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 7061c84e2e1d9d58013543ff82666055a1f055c1296c42c8f73a8bf0
+Result = Fail (1 - Adata changed)
+
+Count = 101
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = c5aa500d1f7c09a590e9d15d6860c4433684e04dd6bc5c8f94f223f0
+Result = Pass (0)
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 102
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = e3efa7971e27ba1245ee9491ebdbb28ad9b24b325da5760417af8b14
+Result = Fail (1 - Adata changed)
+
+Count = 103
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = 852cca903d7fdf899807bd14642057534c8a0ccacb8c7b8fb4d35d44
+Result = Pass (0)
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 104
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e04fd4f5b60833021ed57c98de300bb68d0d892b2bf68e080bc044b1
+Result = Fail (1 - Adata changed)
+
+[Alen = 0, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 105
+Nonce = a544218dadd3c10583db49cf39
+Adata = 00
+CT = f0050ad16392021a3f40207bed3521fb1e9f808f49830c423a578d179902f912f9ea1afbce1120b3
+Result = Pass (0)
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+
+Count = 106
+Nonce = 894dcaa61008eb8fb052c60d41
+Adata = 00
+CT = c408190d0fbf5034f83b24a8ed9657331a7ce141de4fae769084607b83bd06e6442eac8dacf583cc
+Result = Fail (2 - CT changed)
+
+Count = 107
+Nonce = 8feba0d720aa4a5e35abc99e82
+Adata = 00
+CT = 52b3d31d02d1b92b38cbae8c510204dde6bf9588e994296c9002a46cfb734290924a15e9c3d99924
+Result = Fail (1 - Adata changed)
+
+Count = 108
+Nonce = ed04c9ca8702aec8d0a58e09a0
+Adata = 00
+CT = f80190470212ce1e64bf4c64ca0133d90469abf87a8233c2b238e316c3f9adccce95e8c8b9c7e8d2
+Result = Fail (1 - Adata changed)
+
+Count = 109
+Nonce = 1501a243bf60b2cb40d5aa20ca
+Adata = 00
+CT = 254b847d4175bbb44a82b4e805514fa444c224710933f3ec8aaa3f0133234c0cd91609982adc034b
+Result = Pass (0)
+Payload = f5730a05fec31a11662e2e14e362ccc75c7c30cdfccbf994
+
+Count = 110
+Nonce = c6edaf35f0cb433500a8c3a613
+Adata = 00
+CT = 7a5c7bc02aa69efc5a159d653f3993399f69e20752c3b00633255731cd88345860da913bc696fdc1
+Result = Fail (2 - CT changed)
+
+Count = 111
+Nonce = d65e0e53f765f9d5e6795c0c5e
+Adata = 00
+CT = c3618c991b15de641d291419ff6957e8b9ae5046dd8c6f08fafb76adf12f36740347e3edae62bca4
+Result = Pass (0)
+Payload = 20e394c7cc90bdfa6186fc1ba6fff158dfc690e24ba4c9fb
+
+Count = 112
+Nonce = 2b0163418a341588db0f5786d8
+Adata = 00
+CT = 240927bfd671a92aef0311395ad55ae42233ecee53873da4066f55f23d4e55bcbbbf2312ea2d8071
+Result = Fail (2 - CT changed)
+
+Count = 113
+Nonce = f16bba081bddda83546eabc9a5
+Adata = 00
+CT = 4731a7e690c77cd47582ce54a1cec23d94c856b93a9fc767004753689cc84810b8414f1464c0c5b9
+Result = Fail (2 - CT changed)
+
+Count = 114
+Nonce = ace99268a32b9c1b5ccd8b0d84
+Adata = 00
+CT = f0ea12eaff20c3a50674aa1546aaae3bd5c9249108535b21504da83478ede24026ec91fb12769e4b
+Result = Fail (2 - CT changed)
+
+Count = 115
+Nonce = 24570517bbb0df1b3fbd32f57a
+Adata = 00
+CT = 5b164d9752ad6c497a7ab2d0bf8be68fea084ea5839b07b7c9fcf9b9fd5e99767a7b1679b57ea961
+Result = Fail (1 - Adata changed)
+
+Count = 116
+Nonce = a6b2371acf8321864c08ddb4d8
+Adata = 00
+CT = bd37326da18e5ac79a1a9512f724bb539530868576b79c67acb5a51d10a58d6584fbe73f1063c31b
+Result = Pass (0)
+Payload = 1a43ca628026219c5a430c54021a5a3152ae517167399635
+
+Count = 117
+Nonce = f8e2d4e043f5fe7a72b6117811
+Adata = 00
+CT = 0455b4dd1069281e10531c0dc180ced9a5ef5d3fe0007470ce54cd7623a80a176f29a01b3abb642e
+Result = Fail (1 - Adata changed)
+
+Count = 118
+Nonce = c2b60f14c894ec6178fe79919f
+Adata = 00
+CT = ecd337640022635ce1ed273756d02b7feeb2515614c1fadc95c66d3f411b478853886afd177d88c3
+Result = Pass (0)
+Payload = 3e707d98f19972a63d913e6ea7533af2f41ff98aee2b2a36
+
+Count = 119
+Nonce = 4de4c909ac0cc5fc608baf45ac
+Adata = 00
+CT = e25d7c9fb388596b13a13b885d5b24e31579a3494ad256da830b2b6317716b3975e2b101aebdd920
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 4]
+
+Key = 1b0e8df63c57f05d9ac457575ea764524b8610ae5164e6215f426f5a7ae6ede4
+
+Count = 120
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 92d00fbe
+Result = Pass (0)
+Payload = 00
+
+Count = 121
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = 9143e5c4
+Result = Fail (2 - CT changed)
+
+Count = 122
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 54337466
+Result = Fail (1 - Adata changed)
+
+Count = 123
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = bf0bf84c
+Result = Fail (1 - Adata changed)
+
+Count = 124
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = 11250056
+Result = Pass (0)
+Payload = 00
+
+Count = 125
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 13de5339
+Result = Fail (2 - CT changed)
+
+Count = 126
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = 4eed80fd
+Result = Pass (0)
+Payload = 00
+
+Count = 127
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = 4bc2e450
+Result = Fail (2 - CT changed)
+
+Count = 128
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = b30e6bbd
+Result = Fail (2 - CT changed)
+
+Count = 129
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = f7c11fe2
+Result = Fail (2 - CT changed)
+
+Count = 130
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 76673751
+Result = Fail (1 - Adata changed)
+
+Count = 131
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 9a5382c3
+Result = Pass (0)
+Payload = 00
+
+Count = 132
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9e632f56
+Result = Fail (1 - Adata changed)
+
+Count = 133
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = e1842c46
+Result = Pass (0)
+Payload = 00
+
+Count = 134
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 9f644671
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 7, Tlen = 16]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 135
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 93af11a08379eb37a16aa2837f09d69d
+Result = Pass (0)
+Payload = 00
+
+Count = 136
+Nonce = 78c46e3249ca28
+Adata = 232e957c65ffa11988e830d4617d500f1c4a35c1221f396c41ab214f074ca2dc
+CT = d19b0c14ec686a7961ca7c386d125a65
+Result = Fail (2 - CT changed)
+
+Count = 137
+Nonce = c18d9e7971e2ae
+Adata = 0d40324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+CT = 02ea916d60e2ceec6d9dc9b1185569b3
+Result = Fail (1 - Adata changed)
+
+Count = 138
+Nonce = 162d061351d82d
+Adata = 106d1fb32d948b0d8884f178ad2332a599445fae0f6f71f9ebe53a60b2df9b8e
+CT = fabd2d0c422b47d363ea9936ff4a311b
+Result = Fail (1 - Adata changed)
+
+Count = 139
+Nonce = 3fcb328bc96404
+Adata = 10b2ffed4f95af0f98ed4f77c677b5786ad01b31c095bbc6e1c99cf13977abba
+CT = b3884b69d117146cfa5529901753ddc0
+Result = Pass (0)
+Payload = 00
+
+Count = 140
+Nonce = b3fd1eb1422277
+Adata = fa5398cf4cddbe4b45e9f5d7491cd9eefc5e494255961ba3f4b40d22b5f5fe76
+CT = 7162026b6306e74fe32ece8433801bc2
+Result = Fail (2 - CT changed)
+
+Count = 141
+Nonce = c42ac63de6f12a
+Adata = 7ff8d06c5abcc50d3820de34b03089e6c5b202bcbaabca892825553d4d30020a
+CT = b53d93cbfd3d5cf3720cef5080bc7224
+Result = Pass (0)
+Payload = 00
+
+Count = 142
+Nonce = d4a7a672237e17
+Adata = d1cdad7fe886d07625a4334be6de4df0645d2a8b4008a8d35f04e6bcf87bfa56
+CT = c8bbecf69ecf8d10f0863bb4b7cbed51
+Result = Fail (2 - CT changed)
+
+Count = 143
+Nonce = b23255372455c6
+Adata = d2e2c3607c40e0a807b86c6ebbc502ab42bdb7f85ab26299cd963bbba3a3a8fa
+CT = 6037145cc23a175760ae4b573907c80c
+Result = Fail (2 - CT changed)
+
+Count = 144
+Nonce = 92272d40475fbb
+Adata = 2f3af695ee33a9ebe6a48ed1b00e337261857110bb104191a54fd13bd960d8bc
+CT = df7ea77425d631f652ffe096a8157f71
+Result = Fail (2 - CT changed)
+
+Count = 145
+Nonce = c4a756f6024a9d
+Adata = 2317b324b6420ada9ea7bf52b71c5faf2485528da5f56b42c517be6355cdb28b
+CT = 7182b25ef5b113c13fa8f6769e74f1e2
+Result = Fail (1 - Adata changed)
+
+Count = 146
+Nonce = 3a1701b185d33a
+Adata = e5d54df8ed9f89b98c5ebb1bc5d5279c2e182784ff4cd9c869ae152e29d7a2b2
+CT = 0a5d1bc02c5fe096a8b9d94d1267c49a
+Result = Pass (0)
+Payload = 00
+
+Count = 147
+Nonce = e4db2e80dc3f63
+Adata = 7616bdf5737d01f936072b6576fa76556dfa072f7e2d7de16b9dc96ac8de409c
+CT = 9eb6d9757ec7c56cc8c79461e0017486
+Result = Fail (1 - Adata changed)
+
+Count = 148
+Nonce = 4f490ce07e0150
+Adata = 3e12d09632c644c540077c6f90726d4167423a679322b2000a3f19cfcea02b33
+CT = 1eda43bf07f2bf003107f3a0ba3a4c18
+Result = Pass (0)
+Payload = 00
+
+Count = 149
+Nonce = b4aaf9ad1bde60
+Adata = 8c96c891456ddec29fe04299506723db2079a6667f96db5d198bf085acf2a4ef
+CT = 5287cc160c5dd3a0f9c1986aac2a621c
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 4]
+
+Key = a4bc10b1a62c96d459fbaf3a5aa3face7313bb9e1253e696f96a7a8e36801088
+
+Count = 150
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 866d4227
+Result = Pass (0)
+Payload = 00
+
+Count = 151
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 94cb1127
+Result = Fail (2 - CT changed)
+
+Count = 152
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = 82c2b67a
+Result = Fail (1 - Adata changed)
+
+Count = 153
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 8c8283f9
+Result = Fail (1 - Adata changed)
+
+Count = 154
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = c4ac0952
+Result = Pass (0)
+Payload = 00
+
+Count = 155
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = c59aa931
+Result = Fail (2 - CT changed)
+
+Count = 156
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = 27c3953d
+Result = Pass (0)
+Payload = 00
+
+Count = 157
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = cb1ac8eb
+Result = Fail (2 - CT changed)
+
+Count = 158
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4dcc55cc
+Result = Fail (2 - CT changed)
+
+Count = 159
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 727d8f5e
+Result = Fail (2 - CT changed)
+
+Count = 160
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 5aa56a54
+Result = Fail (1 - Adata changed)
+
+Count = 161
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = c38fbdff
+Result = Pass (0)
+Payload = 00
+
+Count = 162
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 6be30c42
+Result = Fail (1 - Adata changed)
+
+Count = 163
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = d34e90bb
+Result = Pass (0)
+Payload = 00
+
+Count = 164
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = 4a5d14bc
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 0, Nlen = 13, Tlen = 16]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 165
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 867b0d87cf6e0f718200a97b4f6d5ad5
+Result = Pass (0)
+Payload = 00
+
+Count = 166
+Nonce = e8de970f6ee8e80ede933581b5
+Adata = 89f8b068d34f56bc49d839d8e47b347e6dae737b903b278632447e6c0485d26a
+CT = 677a040d46ee3f2b7838273bdad14f16
+Result = Fail (2 - CT changed)
+
+Count = 167
+Nonce = 6de75d3c05e83755083399a5f7
+Adata = 504b08cf34cbe17acf631ef219ae01437ebb6a980ab2f00121bb3073701b6511
+CT = f650d46ade2cbabbc68ead6df1ea0c37
+Result = Fail (1 - Adata changed)
+
+Count = 168
+Nonce = 58d43b9f1581c590daab1a5c56
+Adata = 749f149ef306c70a5d006d9777adbbf7c0de453898c2978ef7c281535ea9b24c
+CT = 11b8fe8c139ee38f77fd8fa552cbff67
+Result = Fail (1 - Adata changed)
+
+Count = 169
+Nonce = dfdcbdff329f7af70731d8e276
+Adata = 2ae56ddde2876d70b3b34eda8c2b1d096c836d5225d53ec460b724b6e16aa5a3
+CT = ad879c64425e6c1ec4841bbb0f99aa8b
+Result = Pass (0)
+Payload = 00
+
+Count = 170
+Nonce = 199ec321d1d24d5408076912d6
+Adata = a77526f3614cd974498a76d8b3cb7bacc623fdc9c85503289c462df888b199ed
+CT = 3c64f8731930ae000162c10654531066
+Result = Fail (2 - CT changed)
+
+Count = 171
+Nonce = 60f2490ba0c658848859fcbea8
+Adata = 3ad743283064929bf4fe4e0807f710f5e6a273e22614c728c3280a27b6c614a0
+CT = e2751f153fc76c0dec5e0cf2d30c1a28
+Result = Pass (0)
+Payload = 00
+
+Count = 172
+Nonce = 6f29ca274190400720bba27651
+Adata = c0850aaf141bd3f1b24f4d882590f58682b41f874748f29f8925b4914f444842
+CT = 76127bf891141e73854752ed10c02bd0
+Result = Fail (2 - CT changed)
+
+Count = 173
+Nonce = f1dfb6fdb31cb423226f181c09
+Adata = ac6b08900fc1c9463e7dfdb60eee444c4989d7b200e675f3220ba1e14eed0ab4
+CT = 4bd833f9da0496e5f6a08a05d02df385
+Result = Fail (2 - CT changed)
+
+Count = 174
+Nonce = 0d45226c98eaa9bb445a3aa4f9
+Adata = b9cb3e1a5bcccb0b0599414c9822275b66fa0f913d51bdb0a2228cbb5aad0e0a
+CT = 05f166328a67a8c58b10a7348f3df612
+Result = Fail (2 - CT changed)
+
+Count = 175
+Nonce = 39cdbb24bd273a3fe96f42ca9d
+Adata = ddfe6c22f4cdc3128050072005f5bd4ecdef1d836e891683f1ba921d33fafba7
+CT = 42499bcd949a5163855a9794f11f917e
+Result = Fail (1 - Adata changed)
+
+Count = 176
+Nonce = db113f38f0504615c5c9347c3d
+Adata = 3b71bc84e48c6dadf6ead14621d22468a3d4c9c103ac96970269730bcfce239b
+CT = fc85464a81fe372c12c9e4f0f3bf9c37
+Result = Pass (0)
+Payload = 00
+
+Count = 177
+Nonce = d16a20ef5f6587f1ee3cb7850b
+Adata = b1133e1cd369617a9f937e9a1eb86a0979ee30b5b7b0b6ff838d9e11301d6b72
+CT = 8c7501f423647dee77668858c5e350bb
+Result = Fail (1 - Adata changed)
+
+Count = 178
+Nonce = d35f531f714694b5e49303a980
+Adata = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc553c6c996e354a4b5
+CT = b1c09b093788da19e33c5a6e82ed9627
+Result = Pass (0)
+Payload = 00
+
+Count = 179
+Nonce = 220624db34a022b758473994a2
+Adata = 5b3b2ae87b0d6759f38a858423227f8687f35478a8f565409b741eadcac4d8c4
+CT = d2231ee1455b0bc337c4f8173fb8647c
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 4]
+
+Key = 8c5cf3457ff22228c39c051c4e05ed4093657eb303f859a9d4b0f8be0127d88a
+
+Count = 180
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = c2fe12658139f5d0dd22cadf2e901695b579302a72fc56083ebc7720
+Result = Pass (0)
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 181
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = 94748ba81229e53c38583a8564b23ebbafc6f6efdf4c2a81c44db2c9
+Result = Fail (2 - CT changed)
+
+Count = 182
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 1d670ccf3e9ba59186c48da2e5bd0ab21973eee2ea2985bf83a09067
+Result = Fail (1 - Adata changed)
+
+Count = 183
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 2c8c80ff10fac1bf6c9c83533c1514ee032c0983730b0657392ae25d
+Result = Fail (1 - Adata changed)
+
+Count = 184
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = e1b4ec4279bb62902c12521e6b874171695c5da46c647cc03b91ff03
+Result = Pass (0)
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 185
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = b5dda89fe879d6a665b99285b6d937fd5877ebef4de049fb64b837fb
+Result = Fail (2 - CT changed)
+
+Count = 186
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = 224db21beb8cd0069007660e783c3f85706b014128368aab2a4e56a7
+Result = Pass (0)
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 187
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = ba1ce3a799e1173178b6788723005566f9269d5828c85d28e960a769
+Result = Fail (2 - CT changed)
+
+Count = 188
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 79d59e4bb251988c019c4eaaee2a2513f9cb0521334018fded14a5a5
+Result = Fail (2 - CT changed)
+
+Count = 189
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = af4350795f24087aa05070d6d5f55ebb12d7ad3141066866d7d6c61d
+Result = Fail (2 - CT changed)
+
+Count = 190
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 22d2da531be1f0d1da4bc21f984d29bf56bed2e92da6bf42d0605b84
+Result = Fail (1 - Adata changed)
+
+Count = 191
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = 61b46c9024eed3989064a52df90349c18e14e4b552779d3f8f9d6814
+Result = Pass (0)
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 192
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 539799c2b22a33dd648fc4497d12f9455beaf932f1eaaff4d930f5ce
+Result = Fail (1 - Adata changed)
+
+Count = 193
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 52f8205534447d722be2b9377f7395938cc88af081a11ccb0d83fa19
+Result = Pass (0)
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 194
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = d11c892ae155098f5e4b5fe60c7afd74fb2dbcc4db956556f243e273
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 7, Tlen = 16]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 195
+Nonce = a544218dadd3c1
+Adata = d3d5424e20fbec43ae495353ed830271515ab104f8860c988d15b6d36c038eab
+CT = 3341168eb8c48468c414347fb08f71d2086f7c2d1bd581ce1ac68bd42f5ec7fa7e068cc0ecd79c2a
+Result = Pass (0)
+Payload = 78c46e3249ca28e1ef0531d80fd37c124d9aecb7be6668e3
+
+Count = 196
+Nonce = 6ba004fd176791
+Adata = 5a053b2a1bb87e85d56527bfcdcd3ecafb991bb10e4c862bb0751c700a29f54b
+CT = d543acda712b898cbb27b8f598b2e4438ce587a836e2785147c3338a2400809e739b63ba8227d2f9
+Result = Fail (2 - CT changed)
+
+Count = 197
+Nonce = 45c5c284836414
+Adata = 8f01a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a264c9dcf7d93
+CT = 39a8af5c976b995ea8049e55b68bc65503592ab00915638646288ce9dd1c7088c752e35947fdca98
+Result = Fail (1 - Adata changed)
+
+Count = 198
+Nonce = c69f7679c80546
+Adata = 5d6c04a5b422b46065a79a889e30ac8d1b53b65d230d4c88190903a24e1fe1ea
+CT = 950fbf6445f6ffb68178f52f5079d0c6081a48ae1f267a0b7fd89caef9388fbb82361b8d53d9edc6
+Result = Fail (1 - Adata changed)
+
+Count = 199
+Nonce = 57b940550a383b
+Adata = 33c2c3a57bf8393b126982c96d87daeacd5eadad1519073ad8c84cb9b760296f
+CT = fbfed2c94f50ca10466da9903ef85833ad48ca00556e66d14d8b30df941f3536ffb42083ef0e1c30
+Result = Pass (0)
+Payload = 6fb5ce32a851676753ba3523edc5ca82af1843ffc08f1ef0
+
+Count = 200
+Nonce = 11edd12ea5873d
+Adata = e32e5384038379e2b7382ba337b6f7a72a1569e110ee89c4dd6aa6f7e69f5250
+CT = 2ebfeb7a843618b37025352df3538526517ed320adfb486c04cf3426e8f975125a7eed00e5f33b6c
+Result = Fail (2 - CT changed)
+
+Count = 201
+Nonce = f32222e9eec4bd
+Adata = 684595e36eda1db5f586941c9f34c9f8d477970d5ccc14632d1f0cec8190ae68
+CT = dae13e6967c8b1ee0dd2d5ba1dd1de69f22c95da39528f9ef78e9e5e9faa058112af57f4ac78db2c
+Result = Pass (0)
+Payload = 2c29d4e2bb9294e90cb04ec697e663a1f7385a39f90c8ccf
+
+Count = 202
+Nonce = e0a0a7f262cb51
+Adata = 1d93b2856ad2bf3700440f9a281bd8947ba209e9ffd18e69921ed0678c957c6c
+CT = e683040a0bcf04c1748e7746400d6ef0f7cd8e77a29517790c63959ce534a0f87fb42a9b000dec84
+Result = Fail (2 - CT changed)
+
+Count = 203
+Nonce = 40316e7b38bdad
+Adata = 6e49acd9c26944740c778e74b1dbaa8d640c7e18e949a1661f8a77543db69e1f
+CT = 829e50e8c09e727a58287e6eb7d38edeb8ab39db279c06397d1a2111dc21aec79ef73193b306d31f
+Result = Fail (2 - CT changed)
+
+Count = 204
+Nonce = 33008ef5baf263
+Adata = a726f31d9a22bfc0e7e4c3111b0d304e106ab04ed318f8bfe6ec9cb3a811285b
+CT = 873c91e76dca0062ae66325aefb84ece3e98928f8dbc5fee7c516d2d1a8318893923f398ca249401
+Result = Fail (2 - CT changed)
+
+Count = 205
+Nonce = b48a16fb9a065d
+Adata = be05e9c934c1dcba45223d47c6646a2d13c3b93265e354ae4970484b5101d809
+CT = 343f6c86f2b852ac388a096faec4472107a924aba56d0cb88055e777bb57eb49497cd2e233ee06fd
+Result = Fail (1 - Adata changed)
+
+Count = 206
+Nonce = 14c9bd561c47c1
+Adata = 141ae365f8e65ab9196c4e8cd4e62189b304d67de38f2117e84ec0ec8f260ebd
+CT = a654238fb8b05e293dba07f9d68d75a7f0fbf40fe20edaeba1586bf922412e73ce338e372615c3bc
+Result = Pass (0)
+Payload = c22524a1ea444be3412b0d773d4ea2ff0af4c1ad2383cba8
+
+Count = 207
+Nonce = 5fb871eac2e52a
+Adata = ff23906e9067da8999842318f2a867759ca2d171395c2ff31fa5a4e2ab349c45
+CT = 4846816923ed9f0254bdd0be01028f75061d3594ad3a45bd03538d108df6ecd6f39acfe076ba5fb8
+Result = Fail (1 - Adata changed)
+
+Count = 208
+Nonce = 1ccec9923aa6e8
+Adata = 88a6d037009a1c1756f72bb4589d6d940bd514ed55386baefacc6ac3ca6f8795
+CT = 765067ef768908d91ee4c3923943e0c7be70e2e06db99a4b3e3f51ee37fdcc5d81dd85d9e9d4f44e
+Result = Pass (0)
+Payload = 518a7fb11c463bf23798982118f3cfe4d7ddde9184f37d4f
+
+Count = 209
+Nonce = 68a5351e4422c8
+Adata = 303c767468f48ac9f6e331bbad535b06aa00ab593327320799e17eff63afd3fe
+CT = e58ea6c1522e5a3e93a85edd05ae80d6cf5c4dd6d604a8f8d8a906488f79ad5d2234d72458dcfcd4
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 4]
+
+Key = 705334e30f53dd2f92d190d2c1437c8772f940c55aa35e562214ed45bd458ffe
+
+Count = 210
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = c0ea400b599561e7905b99262b4565d5c3dc49fad84d7c69ef891339
+Result = Pass (0)
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 211
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 60871e03ea0eb968536c99f926ea24ef43d41272ad9fb7f63d488623
+Result = Fail (2 - CT changed)
+
+Count = 212
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 81d7859dcbe51dcc94fe2591cd3b0540003d49a8c4dccbf4527e5ed0
+Result = Fail (1 - Adata changed)
+
+Count = 213
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = bef380ad725b65fb5fceeabf09c665bc35089f434ec831494d20d5fa
+Result = Fail (1 - Adata changed)
+
+Count = 214
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = fabe11c9629e598228f5209f3dbcc641fe4b1a22cadb0821d2898c3b
+Result = Pass (0)
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 215
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = b7eb87f84951640de731d4093f1a4ed5f831138a27465d3941e92090
+Result = Fail (2 - CT changed)
+
+Count = 216
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = d88f8fcd772125212ce09c2a6e5b5693dd35073f992004f0d18fc889
+Result = Pass (0)
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 217
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = d2d7d52b11304fc1d15b8c20e296ba7c63d99f4ce86cc8ae0f39ecea
+Result = Fail (2 - CT changed)
+
+Count = 218
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = ae1d9f82efb464d5dc2018cffa309634c09b34d1122c4bd994b1d516
+Result = Fail (2 - CT changed)
+
+Count = 219
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 477c985d92ad1b69d22315235a29e3d3a5991487cbdc8d11d394d047
+Result = Fail (2 - CT changed)
+
+Count = 220
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = d1c085c75d808dc6db493b8a0b4d884e0700d2844a1b4b46bd3d22eb
+Result = Fail (1 - Adata changed)
+
+Count = 221
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = 76bdd9a7b34bf14ae121a87fdfa144f71b848744af6a2f0b1c0d067c
+Result = Pass (0)
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 222
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 413e2e8df9d65b4e5d3b63a738258aaee643f364be9a01b974192744
+Result = Fail (1 - Adata changed)
+
+Count = 223
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 617d8036e2039d516709062379e0550cbd71ebb90fea967c79018ad5
+Result = Pass (0)
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 224
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 40e609c739e409750a6c41d9c6ea64ce36f70711b4ca3e365c916f91
+Result = Fail (1 - Adata changed)
+
+[Alen = 32, Plen = 24, Nlen = 13, Tlen = 16]
+
+Key = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+
+Count = 225
+Nonce = a544218dadd3c10583db49cf39
+Adata = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e09a1005e024f6907
+CT = 8d34cdca37ce77be68f65baf3382e31efa693e63f914a781367f30f2eaad8c063ca50795acd90203
+Result = Pass (0)
+Payload = e8de970f6ee8e80ede933581b5bcf4d837e2b72baa8b00c3
+
+Count = 226
+Nonce = 8fa501c5dd9ac9b868144c9fa5
+Adata = 5bb40e3bb72b4509324a7edc852f72535f1f6283156e63f6959ffaf39dcde800
+CT = 516c0095cc3d85fd55e48da17c592e0c7014b9daafb82bdc4b41096dfdbe9cc1ab610f8f3e038d16
+Result = Fail (2 - CT changed)
+
+Count = 227
+Nonce = 9bc0d1502a47e46350fe8667ca
+Adata = 07203674260208d5bd4d39506836f7e76ffc58e938799f21aff7bb4dea4410d2
+CT = 0293eae9f8d8bd7ad45357f733fc7b5d990d894783e18501d81ec96df41b8fa8262ed2db880b5e85
+Result = Fail (1 - Adata changed)
+
+Count = 228
+Nonce = 611cb4c66e88f6acf96fea1919
+Adata = 327ee3657e49d4d988362fabae303ccea6638e5cb45993d9d56269bc3d3af32b
+CT = 256bad8295e67d8d450f5ecc8276920ec23b1156c57be7c96ee80f60f72db2cbf25b2f8c6af8749c
+Result = Fail (1 - Adata changed)
+
+Count = 229
+Nonce = 0dd613c0fe28e913c0edbb8404
+Adata = 2ad306575b577c2f61da7212ab63e3db3941f1f751f2356c7443531a90b9d141
+CT = 6df09613ea986c2d91a57a45a0942cbf20e0dfca12fbda8c945ee6db24aea5f5098952f1203339ce
+Result = Pass (0)
+Payload = 9522fb1f1aa58493cba682d788186d902cfc93e80fd6b998
+
+Count = 230
+Nonce = 68806dfe720d0a9a84697de5f2
+Adata = c6b0e4dfd723d7637510f887b7852f60ecdf72e0d33396560fed6534d5b7f015
+CT = c5b64577d3c34e50f7da5072db5bda1d1d2c6db1a4f1183e2cc4c90ac3f798957cb09a05868a8ad5
+Result = Fail (2 - CT changed)
+
+Count = 231
+Nonce = 3e0fe3427eeda80f02dda4fed5
+Adata = ae0d1c9c834d60ff0ecfb3c0d78c72ddb789e58adfc166c81d5fc6395b31ec33
+CT = 2bfe51f1f43b982d47f76ea8206ddbf585d6f30cec0d4ef16b1556631d3b52bf24154afec1448ef6
+Result = Pass (0)
+Payload = 38333ce78110bf53a2c2abc7db99e133ad218ca43ff7a7bc
+
+Count = 232
+Nonce = 7c0c76d9f9316ff6c98758b464
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+CT = 1622ae109073f44a4596722d9943fea774dfc2a1f939fc0914f42ec81e3af71c9a5de7e0ac16ca69
+Result = Fail (2 - CT changed)
+
+Count = 233
+Nonce = 07c728135bdfede0e0c8036b17
+Adata = 25a152850b4b80b19d8f0b504b2a8a241824b3a1fca8d85c8713b2c0c84b5e02
+CT = 4c0b361a766d366d983c41e793d75635e17f6eab2eadcf9743d67d90850c4c76a43df1f95170b29b
+Result = Fail (2 - CT changed)
+
+Count = 234
+Nonce = 710c96d7a6f09de83f0507f28a
+Adata = 2d64acfdbfc582cd9a933790eb1b739fb02e53f511255e49f421bb7acc98a130
+CT = 5b02347f30213df7f1506d7dca41b838c92aea0f190c5dba7bd5d5c8c098299394333b34fae9a110
+Result = Fail (2 - CT changed)
+
+Count = 235
+Nonce = 977bbcdeb6a7d9dcf8664bc2d8
+Adata = 135786125258a49475338ac1961d2718433b9e84cf64f63ca52913e8dd12e505
+CT = c77283ca15484d82469ce7249d1fb8e5f4c3bc8245fb4d97e26149d4a9711be81b4f69aa9fabd7f6
+Result = Fail (1 - Adata changed)
+
+Count = 236
+Nonce = 60122cbd219e5cf17415e8bc09
+Adata = 895a45ddbe0c80793eccbf820de13a233b6aa7045cfd5313388e7184c392b216
+CT = bf0d219bb50fcc1d51f654bb0fd8b44efa25aef39e2f11afe47d00f2eebb544e6ba7559ac2f34edb
+Result = Pass (0)
+Payload = 794e734966e6d0001699aec3f8ab8f194de7653d3091b1b9
+
+Count = 237
+Nonce = 83a07f2e685959cb50a1bd2bce
+Adata = 02afe300ec0cf0acb59108b2f70e069300294e34f40bb032cb59907599664408
+CT = 1609f8de59da4f50ce034977d132d4f9881a9b85ffa5bb886fa3fddc87690a359fe55f8fa12ba749
+Result = Fail (1 - Adata changed)
+
+Count = 238
+Nonce = 3542fbe0f59a6d5f3abf619b7d
+Adata = dd4531f158a2fa3bc8a339f770595048f4a42bc1b03f2e824efc6ba4985119d8
+CT = 39c2e8f6edfe663b90963b98eb79e2d4f7f28a5053ae8881567a6b4426f1667136bed4a5e32a2bc1
+Result = Pass (0)
+Payload = c5b3d71312ea14f2f8fae5bd1a453192b6604a45db75c5ed
+
+Count = 239
+Nonce = 48f2d4c0b17072e0a9c300d90b
+Adata = c56175e2cfe0d37454d989afcc36686fb34c015439601567506a4d0003182be7
+CT = 27c575be0b99af9b106f53f471c31cac4d54ea0bcb602a33fb67bb6092cd579f722ae9b680da083d
+Result = Fail (1 - Adata changed)
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt
new file mode 100644
index 0000000000..88bdc95fd0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/Readme.txt
@@ -0,0 +1,9 @@
+There are two sets of CCM example files:
+
+1. The response (.rsp) files contain properly formatted CAVS response files.
+
+2. The three DVPT{128/192/256}.txt files contain the same values as the
+ DVPT{128/192/256}.rsp files but have additional information. For the cases
+ that fail, the reason for failure is in parentheses following the result:
+ e.g., Result = Fail (2 - CT changed)
+ This additional information is not in properly formatted response files.
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp
new file mode 100644
index 0000000000..a4fe9130a0
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT128.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = d24a3d3dde8c84830280cb87abad0bb3
+Nonce = f1100035bb24a8d26004e0e24b
+
+Count = 0
+Adata = 00
+Payload = 7c86135ed9c2a515aaae0e9a208133897269220f30870006
+CT = 1faeb0ee2ca2cd52f0aa3966578344f24e69b742c4ab37ab1123301219c70599b7c373ad4b3ad67b
+
+Count = 1
+Adata = 00
+Payload = 48df73208cdc63d716752df7794807b1b2a80794a2433455
+CT = 2bf7d09079bc0b904c711a0b0e4a70ca8ea892d9566f03f8b77a140819f39ef045103e785e1df8c2
+
+Count = 2
+Adata = 00
+Payload = b99de8168e8c13ea4aef66bdb93133dff5d57e9837ff6ccb
+CT = dab54ba67bec7bad10eb5141ce3344a4c9d5ebd5c3d35b664b01098842a618390619b86e00850b2e
+
+Count = 3
+Adata = 00
+Payload = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce
+CT = 6ad4821cbf7f2b9973662b5084aff39b69c6276d8636c0638bd518724ab84fb814fe7b5570769f7f
+
+Count = 4
+Adata = 00
+Payload = cb43320d7488dfd6eed9efd88f440ea3f6f77a0df09d0727
+CT = a86b91bd81e8b791b4ddd824f84679d8caf7ef4004b1308a7229cbcecef221570cee8345b38cd6ec
+
+Count = 5
+Adata = 00
+Payload = a350ed58c04473e113b9088b1fb9dad92807f6b63b0d690c
+CT = c0784ee835241ba649bd3f7768bbada2140763fbcf215ea1fee47fec27d7764e5e2819c850088bac
+
+Count = 6
+Adata = 00
+Payload = 0709e691faf41383fab5d1848a8eee77101d1c99e526a264
+CT = 642145210f947bc4a0b1e678fd8c990c2c1d89d4110a95c954d610bc1ab4bc9a8a28c7306f7c539e
+
+Count = 7
+Adata = 00
+Payload = e7b913c2f0630562eb1c16b3b1ed84090c011a15c09e5471
+CT = 8491b07205036d25b118214fc6eff37230018f5834b263dc2e31657ecc51f5ec8590482fc053230d
+
+Count = 8
+Adata = 00
+Payload = 6b909697074900d41ce8c7d559b229af11fb3cec334784d4
+CT = 08b83527f229689346ecf0292eb05ed42dfba9a1c76bb379d500827f2081b00397102f90fc9ccd88
+
+Count = 9
+Adata = 00
+Payload = 495ff03335bcb39a317b9ea3f8bb6306fa771f3c55adebce
+CT = 2a775383c0dcdbdd6b7fa95f8fb9147dc6778a71a181dc63e2e7997803029476598c0e8d4fc63857
+
+[Alen = 1]
+
+Key = 08b0da255d2083808a1b4d367090bacc
+Nonce = 777828b13679a9e2ca89568233
+
+Count = 10
+Adata = dd
+Payload = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0
+CT = e8b80af4960d5417c15726406e345c5c46831192b03432eed16b6282283e16602331bcca9d51ce76
+
+Count = 11
+Adata = c5
+Payload = 032fee9dbffccc751e6a1ee6d07bb218b3a7ec6bf5740ead
+CT = f0828917020651c085e42459c544ec52e99372005362baf308ebeed45f67ef8733737c9c6f82daad
+
+Count = 12
+Adata = 68
+Payload = 9c4cd65b92070bc382fd18146611defb4204acddfdf6b276
+CT = 6fe1b1d12ffd9676197322ab732e80b1183032b65be00628f9b477e3a23bfdfdb619c7bc531fbcce
+
+Count = 13
+Adata = be
+Payload = 2ff93ef2fc5fe2c297ace05f3f7585aed75ef90ade3acf89
+CT = dc54597841a57f770c22dae02a4adbe48d6a6761782c7bd7aa82130f5a86c0cd0433585e5c208cf7
+
+Count = 14
+Adata = 7a
+Payload = 62766e9acd41285eeed9b4007340dbb611699624274ad117
+CT = 91db091070bbb5eb75578ebf667f85fc4b5d084f815c65499d60012a2f25463e036ceecea57b3c97
+
+Count = 15
+Adata = 13
+Payload = ea689c268a04912d0527b16d9d9406df38302fb11cb64a99
+CT = 19c5fbac37fe0c989ea98bd288ab58956204b1dabaa0fec7e337897c90eb260729a729aed1c8a244
+
+Count = 16
+Adata = e5
+Payload = f31e35953beb211efcce487ba8c0cd1a8446343d5851b9fd
+CT = 00b3521f8611bcab674072c4bdff9350de72aa56fe470da373dc2911c75b37cd995481d42b04524a
+
+Count = 17
+Adata = e3
+Payload = c4ac3c645387584c2a95b1f16b8317730592924dd831a388
+CT = 37015beeee7dc5f9b11b8b4e7ebc49395fa60c267e2717d684f76ecf3dc5f3307ce982f185321248
+
+Count = 18
+Adata = d5
+Payload = 81af394c2ea3a85e1ea954596e3772f01635d007794c0b19
+CT = 72025ec6935935eb85276ee67b082cba4c014e6cdf5abf472c38d0fe4e4eba054c1420c39a3dcc61
+
+Count = 19
+Adata = ed
+Payload = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304
+CT = 13bec5676842f61e167bf32b183552cc1e4c5fc6e470375a7cfa6c9945f5aee3c799eee37b0605db
+
+[Alen = 2]
+
+Key = 1538cc03b60880bf3e7d388e29f27739
+Nonce = 9e734de325026b5d7128193973
+
+Count = 20
+Adata = c93c
+Payload = e7b819a853ffe79baaa72097ff0d04f02640ae62bcfd3da5
+CT = 1d8f42f9730424fa27240bd6277f4882604f440324b11b003ca01d874439b4e1f79a26d8c6dc433a
+
+Count = 21
+Adata = 4cf9
+Payload = dc6cf325ed6d968efba9f57e48a58f4578cc3540fe121ba2
+CT = 265ba874cd9655ef762ade3f90d7c3373ec3df21665e3d07b40653cd23afc7cc7a31fa13ba8f4e49
+
+Count = 22
+Adata = b469
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = d89c315c8f6ef204502b4f8d3699345c6153e166b2a1f421c8c10aaf90b1116be216f912c82ca96a
+
+Count = 23
+Adata = cf6b
+Payload = a35f62a431fee63468dc02fdf7bef78d3a5937de56151939
+CT = 596839f511052555e55f29bc2fccbbff7c56ddbfce593f9c2f568ef41324189fb3644edcd76dc19c
+
+Count = 24
+Adata = af7c
+Payload = 548840cb0400824af809fb68447500b77e977128200d3b81
+CT = aebf1b9a24fb412b758ad0299c074cc538989b49b8411d242548c244a875d3681d715db3da19962f
+
+Count = 25
+Adata = 61dc
+Payload = 440b6095c77495e73fff54c785b7ceb5eb358731c213ffcd
+CT = be3c3bc4e78f5686b27c7f865dc582c7ad3a6d505a5fd968b599bc8927ad8d43067807f4b858f854
+
+Count = 26
+Adata = b97e
+Payload = 50c59ca54eb64575b82b13c6dac96488af369e9f5f86cdf2
+CT = aaf2c7f46e4d861435a8388702bb28fae93974fec7caeb577454774ee78f76e555cf743df340381e
+
+Count = 27
+Adata = 57ab
+Payload = 21b8eb1f0bda26ca36167ce7bc2e796818bf11fc8c192885
+CT = db8fb04e2b21e5abbb9557a6645c351a5eb0fb9d14550e20e0a22a5ee031978271c7dd2a0d4e7018
+
+Count = 28
+Adata = 5f9c
+Payload = b4d84fb1e81e18c89391a7a59fc05fedaf160e0d0d027a7c
+CT = 4eef14e0c8e5dba91e128ce447b2139fe919e46c954e5cd99a242ebae5c6da57ee38e5c227c46b32
+
+Count = 29
+Adata = e0c4
+Payload = 54dc5a0e1b67577cda4e7dbd48b769c120c1d13dd567cfad
+CT = aeeb015f3b9c941d57cd56fc90c525b366ce3b5c4d2be908a5f8a92f4201c4658289307167cee810
+
+[Alen = 3]
+
+Key = f149e41d848f59276cfddd743bafa9a9
+Nonce = 14b756d66fc51134e203d1c6f9
+
+Count = 30
+Adata = f5827e
+Payload = 9759e6f21f5a588010f57e6d6eae178d8b20ab59cda66f42
+CT = f634bf00f1f9f1f93f41049d7f3797b05e805f0b14850f4e78e2a23411147a6187da6818506232ee
+
+Count = 31
+Adata = e9699b
+Payload = 1555bc87d6c688fd221a2c75cd1e4dd1c1693207ac421d24
+CT = 7438e575386521840dae5685dc87cdec14c9c65575617d28f10835db9897b7528e3204fe3a81424f
+
+Count = 32
+Adata = 972896
+Payload = b72b2a080d92f3f3bb7d96222982de82a28c9eebaddba247
+CT = d64673fae3315a8a94c9ecd2381b5ebf772c6ab974f8c24b3efa05ba4a73ec2234461d459f54acd2
+
+Count = 33
+Adata = 3053f3
+Payload = b5417ed6933ffe2b57ea601d77e97eb12fa1fb8fdc06c86f
+CT = d42c27247d9c5752785e1aed6670fe8cfa010fdd0525a863b557537c6525e827750917a1ed49602f
+
+Count = 34
+Adata = 24db75
+Payload = 4e7f42666035a00e62783283c54b027603917685d27326bc
+CT = 2f121b948e9609774dcc4873d4d2824bd63182d70b5046b0dfd06b037e9094f120eb3d8649d48918
+
+Count = 35
+Adata = ff27a4
+Payload = 7bf180699c294421ad9565cacc27227a4b3a7cf9637290c6
+CT = 1a9cd99b728aed5882211f3addbea2479e9a88abba51f0cabfa8cfabbd79b3e3210482e6f3822fee
+
+Count = 36
+Adata = 77ec24
+Payload = 3d47071c13f994cb42fb2887e5c6e53a542be7ddad9779e0
+CT = 5c2a5eeefd5a3db26d4f5277f45f6507818b138f74b419ec3b9575e347051e98d0c8646ad46318e6
+
+Count = 37
+Adata = 6d7748
+Payload = 317d5da0a2ec12c3b96c83dd61cc955242a9c1c640e2b92f
+CT = 501004524c4fbbba96d8f92d7055156f9709359499c1d92378e7af65eb0388ae7a52f58f6ba32109
+
+Count = 38
+Adata = 029674
+Payload = c9bb21306ee1b4a6c4fa5443af2e181716993cbb374e177c
+CT = a8d678c280421ddfeb4e2eb3beb7982ac339c8e9ee6d77708019fa97ff70d4d21c0bd83caa434b3a
+
+Count = 39
+Adata = 60dfe8
+Payload = 44eb7edd6bee501ad97873aa7ecbf7ed8b613760d7c95e15
+CT = 2586272f854df963f6cc095a6f5277d05ec1c3320eea3e191814ed48a21d97ea02e86d7e6e8834cb
+
+[Alen = 4]
+
+Key = 9a57a22c7f26feff8ca6cceff214e4c2
+Nonce = 88f30fd2b04fb8ddbce8fc26e6
+
+Count = 40
+Adata = a95bdff6
+Payload = 035c516776c706a7dd5f181fa6aa891b04dd423042ea0667
+CT = b92f7ec2ebecebdbd2977b3874e61bf496a382153b2529fc9b6443a35f329b2068916fb6ab8227eb
+
+Count = 41
+Adata = d2672cbb
+Payload = 3ba306bcec94615c347f990b62841a16df7b321f113f1714
+CT = 81d0291971bf8c203bb7fa2cb0c888f94d05f23a68f0388f19e2aa492ce9ddfb6de0ab7a447f5351
+
+Count = 42
+Adata = 737f4d00
+Payload = 68313a29ace3efe521c3ca1e5bac8e98d6b4434c80a7dc74
+CT = d242158c31c802992e0ba93989e01c7744ca8369f968f3ef2bf683b1209f104e82ba39f7c62cd666
+
+Count = 43
+Adata = 3610b1ae
+Payload = 963bfe556138317bebe3936b18a2c1dd100dc73be6fde556
+CT = 2c48d1f0fc13dc07e42bf04ccaee53328273071e9f32cacd4fc7d5cac043f182edbe5c2658f73092
+
+Count = 44
+Adata = f1aa7f72
+Payload = 52d5c53ee4f23cb050a95db54112b44033c34ac31de96be8
+CT = e8a6ea9b79d9d1cc5f613e92935e26afa1bd8ae664264473b8234f3fbaca3dc2c497418219151b05
+
+Count = 45
+Adata = 6b1013aa
+Payload = a302aebc0f8fd61badc8371991beacf5933de46effacb8ce
+CT = 1971811992a43b67a200543e43f23e1a0143244b866397558fa5f9539e0500f139016e4a4337d86b
+
+Count = 46
+Adata = 33028129
+Payload = f7d653c23254875625b20e1ef60ae92847046d84bb4ce857
+CT = 4da57c67af7f6a2a2a7a6d3924467bc7d57aada1c283c7ccfa2379fde155e64b5b84e336056445c3
+
+Count = 47
+Adata = 2cab4a09
+Payload = 872a3f7230e626abff519e5aeecc93897249405daeaffc98
+CT = 3d5910d7adcdcbd7f099fd7d3c800166e0378078d760d30358208335cb81e4fb10923fca4ddb9ff9
+
+Count = 48
+Adata = 73142ba7
+Payload = 766f94e7d9b1ce74bbaf2c99d215350f060122767fc1953f
+CT = cc1cbb42449a2308b4674fbe0059a7e0947fe253060ebaa42d6ecfb49ac8983415503efef1e21950
+
+Count = 49
+Adata = bc9f967e
+Payload = 5f089ed9267363bc23c6c7b8f73208a36f61fa8ea8084ff7
+CT = e57bb17cbb588ec02c0ea49f257e9a4cfd1f3aabd1c7606c1978a62d15430fc20b87940292b49641
+
+[Alen = 5]
+
+Key = 54caf96ef6d448734700aadab50faf7a
+Nonce = a3803e752ae849c910d8da36af
+
+Count = 50
+Adata = 5f476348dd
+Payload = c69f7c5a50f3e72123371bbfd6bdf532b99ef78500508dfe
+CT = 20c43ad83610880249f1632dd418ec9a5ed333b50e996d1a4e5a32fbe7961b832b722bc07a18595b
+
+Count = 51
+Adata = 07db8aada5
+Payload = 9cf8b638f2b295b85cf782fabab11153dc091b4afcd761a9
+CT = 7aa3f0ba9451fa9b3631fa68b81408fb3b44df7af21e814d401a2222443696021b5faa520129b563
+
+Count = 52
+Adata = 31ef6561ff
+Payload = 62b8263dc015ef873cd16272e4da89799b910f2b04204420
+CT = 84e360bfa6f680a456171ae0e67f90d17cdccb1b0ae9a4c4f842681d2e90da5718234ed893197662
+
+Count = 53
+Adata = e97dfcbafb
+Payload = 810bed3a2bc0f9d75389155b7a39d9d014c08646814f9718
+CT = 6750abb84d2396f4394f6dc9789cc078f38d42768f8677fc33a08eb30ee154f71279682ab02eff27
+
+Count = 54
+Adata = 4981c51fcc
+Payload = 063d23fc3ec344c1ba3486802e01e55617455d5cfbfb5279
+CT = e066657e58202be2d0f2fe122ca4fcfef008996cf532b29d8d3071c79f0cf86fe4148cb5e8ace0ce
+
+Count = 55
+Adata = c8437dba76
+Payload = 41db5b245ea0fab985b93e7fc0a00cd3cca5bdbb642b7ebf
+CT = a7801da63843959aef7f46edc205157b2be8798b6ae29e5b842700619dc1599603f3f3f6cfdf5e0b
+
+Count = 56
+Adata = 6f65a24344
+Payload = b0e36734b2ba871d59df0b029c7f32af68e003a689ac4911
+CT = 56b821b6d459e83e331973909eda2b078fadc7968765a9f539a0cd8d8bbf211b907f34411f868c79
+
+Count = 57
+Adata = cd62d6d203
+Payload = 747e53e627eabde0cd77d78d1bd720bea518f8a2f76e57a2
+CT = 922515644109d2c3a7b1af1f1972391642553c92f9a7b746c4a90e5fc11266bab77eea1d24fbdbb9
+
+Count = 58
+Adata = 9663b3c8e6
+Payload = c70c92ec4c518802662fa4c41a6a33a22599f79f8f7264b3
+CT = 2157d46e2ab2e7210ce9dc5618cf2a0ac2d433af81bb8457b3c1246f7dd6462ce757db82db45f36e
+
+Count = 59
+Adata = 35c4720d3c
+Payload = a26835605b66fc08abdbb5dc77e39783d60b8e8f2314e95f
+CT = 443373e23d85932bc11dcd4e75468e2b31464abf2ddd09bbd472c06a5f4c04f97d06ec401d3e7fd9
+
+[Alen = 6]
+
+Key = cc0c084d7de011e2f031616a302e7a31
+Nonce = f0b4522847f6f8336fe534a4e7
+
+Count = 60
+Adata = da853a27aee2
+Payload = 15b369889699b6de1fa3ee73e5fe19814e46f129074c965b
+CT = f39755d160a64611368a8eccf6fcbc45ef7f1f56240eb19a2e3ca4ec3c776ab58843f617d605fd72
+
+Count = 61
+Adata = d4ed4584678e
+Payload = a18c0460b56a5bcd5bf6842cec6ed44d90b2bfa968a6a7e7
+CT = 47a838394355ab0272dfe493ff6c7189318b51d64be48026327804c44c8f17a4446a3d5ba85f9c7f
+
+Count = 62
+Adata = 590a27721a36
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = a7eadcb559a39501de6924b5e07bf12be89c6b08be689c0bbcd00e9cb726d75e4283820ee81d933a
+
+Count = 63
+Adata = 58830fb0b1f3
+Payload = dce983e4e3734a9bd8848dba0d744d07bbeba602f4006025
+CT = 3acdbfbd154cba54f1aded051e76e8c31ad2487dd74247e4d5d71a1f0f1b6518c35f0632a30931fd
+
+Count = 64
+Adata = eedd0d767a25
+Payload = 4653b3e879ab18b65c5c3706a5139698262cb830a22d943b
+CT = a0778fb18f94e879757557b9b611335c8715564f816fb3fa3ad112899e9ba442660eb5dfe33b2f96
+
+Count = 65
+Adata = 618bcf2e3e79
+Payload = 8586383281925363ac15fb19c26d64c639c75920c792dc2c
+CT = 63a2046b77ada3ac853c9ba6d16fc10298feb75fe4d0fbed54fba446028919342b2fe86ee67efcc7
+
+Count = 66
+Adata = 549c9b84c7f7
+Payload = 95c25ae4445cd8c4d267df82687484667e309992fcf1e737
+CT = 73e666bdb263280bfb4ebf3d7b7621a2df0977eddfb3c0f69fc23013142f62881ccfa3037067e1ef
+
+Count = 67
+Adata = 92d7fa6a8135
+Payload = e58034bbb0e6f5e724e32ee56896dadae25c2a3efb8c6f2f
+CT = 03a408e246d905280dca4e5a7b947f1e4365c441d8ce48ee8263568d56fae8bf35b2f2cdecbffe0a
+
+Count = 68
+Adata = f43e126c0f83
+Payload = d98f0dddfe9cb3cae1336970d5efb55316a65e2c51e316f4
+CT = 3fab318408a34305c81a09cfc6ed1097b79fb05372a13135de2c2fbfdddc7dd6672714af174c5121
+
+Count = 69
+Adata = f02074812dde
+Payload = 548747b1669c6383b793054d93957f9e99d605761c6c23b5
+CT = b2a37be890a3934c9eba65f28097da5a38efeb093f2e04743704560ff23ce0000fba8812c45940ad
+
+[Alen = 7]
+
+Key = d7572ed0e37261efa02f8c83e695efdc
+Nonce = f4f96d7b4384a3930b3d830f82
+
+Count = 70
+Adata = 922340ec94861f
+Payload = 1edef80c57d17f969f8bde10ab38a1a8811a124de72c526e
+CT = de14558cc686e1836f1f121ea1b941a9ebd4f0fb916dc870fd541b988a801cb5751c7faaf5b0c164
+
+Count = 71
+Adata = 4eb379f21b1531
+Payload = ddd5282a207c1dcb03c1c3bbc9eb12a7bd28534118db2735
+CT = 1d1f85aab12b83def3550fb5c36af2a6d7e6b1f76e9abd2bc068bd1b1c309dfbd52d9a24be07c630
+
+Count = 72
+Adata = 7fa89e9d6e3fec
+Payload = c5b7c462eb166f48bb59c8102ee7b3dc67a28e5de7570c51
+CT = 057d69e27a41f15d4bcd041e246653dd0d6c6ceb9116964f2d114d6ab082738d05d60acca8e8ccfb
+
+Count = 73
+Adata = fda8665f87c618
+Payload = af793815e147e3180f5146aa6a582e343dc479f26b4226b2
+CT = 6fb3959570107d0dffc58aa460d9ce35570a9b441d03bcac1cc84bd77fe00e1a13433f2c10e3b799
+
+Count = 74
+Adata = 46bde207491ebd
+Payload = 47c76a0bbd5b1616b278089d41a050c509c7a1c280574bf7
+CT = 870dc78b2c0c880342ecc4934b21b0c463094374f616d1e9990c81f1bae32c953bf02ddbde047632
+
+Count = 75
+Adata = a799f5f895fd7a
+Payload = d554806ffc3900a0952a3c094c745808950697a6e5d62c1d
+CT = 159e2def6d6e9eb565bef00746f5b809ffc875109397b6031af19f1f080dd1dd2da799059755e49f
+
+Count = 76
+Adata = 20225831a9ee06
+Payload = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b
+CT = 7a8f4c050fad7d7754decd18abcfa88ac9a738da00820b2523d3b9a0060834ac4860dae0eac570ef
+
+Count = 77
+Adata = 785360916464eb
+Payload = 57bc338946ff78cf76adf5021e2e44e34e687fb68ad703f3
+CT = 97769e09d7a8e6da8639390c14afa4e224a69d00fc9699edff96e7cf841a66c50bbb6fb2bac7ef51
+
+Count = 78
+Adata = 57b946369226db
+Payload = 9ac5be9929c4fe5a9992749a38dc69874866db3d4747da97
+CT = 5a0f1319b893604f6906b894325d898622a8398b3106408986e1c33a45f9d52755c374650635bef6
+
+Count = 79
+Adata = 73e4da8973c1e3
+Payload = 5a05410aa3a71f5f1a253b8576eba269c06a4c30591144cc
+CT = 9acfec8a32f0814aeab1f78b7c6a4268aaa4ae862f50ded2d78592c2d89c15edc5bb7486aa93f896
+
+[Alen = 8]
+
+Key = 98a42d7a0c5917deaf3b4de3f0cbe0a1
+Nonce = 03d33ab0c2df7bfce88b5ee4c4
+
+Count = 80
+Adata = 2d5438b728b950d9
+Payload = 9aa9c8358117564371366beeec923051ef433252197aaad5
+CT = 9ff942baa60f440c17a78e9581216b9a947a67f04d54911feecfff971fdfaa856310b014aa59c978
+
+Count = 81
+Adata = 6e430b497a16e7f5
+Payload = 5758a500978c71a9b90f6e5beae9d96ef05a41486b10ea2e
+CT = 52082f8fb09463e6df9e8b20875a82a58b6314ea3f3ed1e46a4d7b4b4df6c831ee32116ee4dad98c
+
+Count = 82
+Adata = e12f98507d6514c3
+Payload = 49efe18c76a8355127d914a3a830c1c6ff2a163d728526e1
+CT = 4cbf6b0351b0271e4148f1d8c5839a0d8413439f26ab1d2b3243fc75cd1624e152f451678edcac87
+
+Count = 83
+Adata = eecf8d641ee0bee9
+Payload = 49ae2309fbe6ce4e9421516b8f79ae64b1316cb849eaf638
+CT = 4cfea986dcfedc01f2b0b410e2caf5afca08391a1dc4cdf2dd6d8ca57da1880e1baff43736b3da34
+
+Count = 84
+Adata = 9066367c784de0a4
+Payload = b1bda5fa4242aa6aad0f5a5b1d31d86b8d4a97588b3e315d
+CT = b4ed2f75655ab825cb9ebf20708283a0f673c2fadf100a97f05439a661001513a96b896de46b7081
+
+Count = 85
+Adata = edf848b2510f7803
+Payload = eaa8608f6763d968576a7e89056b9828a1686c8441b06377
+CT = eff8ea00407bcb2731fb9bf268d8c3e3da513926159e58bdcf20709b2dc2ff9946094190b5ea09d1
+
+Count = 86
+Adata = 0f49cae81c8628d2
+Payload = f32029cf51609f0df9832ad1b283ea94a5356f70112c1328
+CT = f670a34076788d429f12cfaadf30b15fde0c3ad2450228e2a5bb6b4f87b9b198665203e4fdf9e7f7
+
+Count = 87
+Adata = b0c47e9cce46a276
+Payload = 7a550ef9254a8da6e4fee290a76ea838ffb61d3533d4d31f
+CT = 7f05847602529fe9826f07ebcaddf3f3848f489767fae8d529f416f89f1a34bbbf2ce40d943c6d8b
+
+Count = 88
+Adata = a6fe7c9ce2d49f85
+Payload = e67c486dd7ba9a9061844b9354f55890321ae626efaa28cc
+CT = e32cc2e2f0a288df0715aee83946035b4923b384bb8413067eb95550b91b955d5c2d72d5c189b704
+
+Count = 89
+Adata = eb1d11cc4876f58f
+Payload = 35f2c810091e930a52e4a3f28c9c8184967f1554c2675eb5
+CT = 30a2429f2e06814534754689e12fda4fed4640f69649657f0e8e8a5a7e0ea6860bab4a4320f03ae5
+
+[Alen = 9]
+
+Key = 2a68e3fe746f593c1b97cb637079c3e5
+Nonce = cd62d0f27b7f4864dc7c343acd
+
+Count = 90
+Adata = abe4f1d3812bfe3ccf
+Payload = 13b4a874888db0e5d8fd814b5e7e04f7fdfbc1601ccc02bc
+CT = 032835a3dbf688d09cf2a32a92b101959d33ff47500f92f4fd49840440f866d1a22b0854996111d8
+
+Count = 91
+Adata = 2e21f466814d3d6340
+Payload = 08b5c773364cded74d7b308984313c17ff90eed496a27a2b
+CT = 18295aa46537e6e2097412e848fe39759f58d0f3da61ea63de2f5c335df537fbbc6ae59cd562732f
+
+Count = 92
+Adata = dba22aabcea0e694fc
+Payload = bbac1790abb7aafe272ec472c897e6363e335b3c4126c762
+CT = ab308a47f8cc92cb6321e6130458e3545efb651b0de5572acc5ed6e4a907ff4742ab6c835a427f92
+
+Count = 93
+Adata = 97e9d16bd757395ec1
+Payload = 7249612dc09809bbca9dd311e720f7da2cb54ce33e3eb9c3
+CT = 62d5fcfa93e3318e8e92f1702beff2b84c7d72c472fd298b1714b5a3df454f3bc35869da75adc882
+
+Count = 94
+Adata = 866cf710470cac74d3
+Payload = 060ae0ab9857324a3b2ac79f3b6e6f90f5de884ce9c7b930
+CT = 16967d7ccb2c0a7f7f25e5fef7a16af29516b66ba5042978aa33dffe2596832f98a9c8413bd898b9
+
+Count = 95
+Adata = 2dd7a7f832b29ccce2
+Payload = f77a9fd5363836deefd34e1bea0882484a7ab746b4495d59
+CT = e7e6020265430eebabdc6c7a26c7872a2ab28961f88acd11dd5049f7c53d6a7fe5d7f959689ee960
+
+Count = 96
+Adata = 502349a60e897356b5
+Payload = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34
+CT = 868d1068b64f0cedead7a50869faee6eeb9077fbed0b8c7ced9c3a0d0de8788471c5f6c2f9638b7c
+
+Count = 97
+Adata = debed45c9acf129268
+Payload = df5a47d3eb5c0b6cabb6711a45400602d205b82ecae9e849
+CT = cfc6da04b8273359efb9537b898f0360b2cd8609862a7801d49b4b9bead1b7de2021cff280d6f93b
+
+Count = 98
+Adata = 2726702dd62a6e5344
+Payload = 5a7649cb001fbb6f653cbca17756c5c1a078c2e240d92085
+CT = 4aead41c5364835a21339ec0bb99c0a3c0b0fcc50c1ab0cd69df31aba209d87ee22bd6a1dcadb168
+
+Count = 99
+Adata = e8006cfb0536696ac7
+Payload = 95186d41f927cdbef42157f21d966e88061b6558b5ec932f
+CT = 8584f096aa5cf58bb02e7593d1596bea66d35b7ff92f03677cc5b60c881fe834a789d28447d8fb54
+
+[Alen = 10]
+
+Key = 46b067cf9b1a28cf187002e90b14e130
+Nonce = bad8c03292bf01cfd8d34f860c
+
+Count = 100
+Adata = 8d65880eddb9fd96d276
+Payload = cc0915194218d4536e467433cd6d79ff1d9eb9ff160ab684
+CT = bd56edc015692c6ab9bec493a9893863598414a3d11a6a0f27ecdcb257d0d30491e5bf1aa8f90958
+
+Count = 101
+Adata = 8a65cde13149d9d54a5b
+Payload = 28257133b1d8b0b2be4faecd6e819ac783707a5c5f50c302
+CT = 597a89eae6a9488b69b71e6d0a65db5bc76ad70098401f89b10f9fc201e4128696dcd899dd2e24ea
+
+Count = 102
+Adata = e999ec3e1bfb25b5877c
+Payload = 96ab0cfc204bafc4f5851d6c682d631d0c5ad03ac925a943
+CT = e7f4f425773a57fd227dadcc0cc9228148407d660e3575c8c522e5ba5adbc6a639cbd06f103ebc9e
+
+Count = 103
+Adata = a8554441e073d6065dce
+Payload = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+CT = 21cda08aff3bcbc6eed9e44483d3ae5dc9d564d38a42e922e1a4e0f7ebc3cff3915d27971cce7e91
+
+Count = 104
+Adata = 838f0be8d04d28d77549
+Payload = d0700658d5f4010ff21091f3d119c99645e339198029c3a9
+CT = a12ffe818285f93625e82153b5fd880a01f9944547391f22c215c88d80bffc881aff10ba40f11976
+
+Count = 105
+Adata = 20f014d928d5b25fbaf4
+Payload = 4bdf28748a0c281dd49c7294ae8e55fe7a52d45ff6384db3
+CT = 3a80d0addd7dd0240364c234ca6a14623e487903312891382cc9391bc06aa6ca9d486a4e2a218c54
+
+Count = 106
+Adata = 56c026b8a71974ff7ecd
+Payload = f75db057f0276fff85014f54ecdec8f90b96a2a982db14cb
+CT = 8602488ea75697c652f9fff4883a89654f8c0ff545cbc840778b05c6c582a0bb7d1d9dcf6a46b9f6
+
+Count = 107
+Adata = 75c3b9e52648a4f9aca9
+Payload = c15c554169dbb9b08494afaa44819a10dc9ddad54199ab54
+CT = b003ad983eaa4189536c1f0a2065db8c98877789868977dff47d9ebbd3cff14623b10cecc94b53d6
+
+Count = 108
+Adata = 1c76c3014a14b7fa1ca8
+Payload = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032
+CT = 68b10e2ecf8d9031bd55ac7a099d37518bfc15f3b3495cb9d2b74b84dc170c00dce85b56e346a976
+
+Count = 109
+Adata = a4eb60d4eb7ead1bd0e6
+Payload = e06e5dba5ac35cfd07949e5cc12ad70507d4a86a952ecca3
+CT = 9131a5630db2a4c4d06c2efca5ce969943ce0536523e1028d92e19fd8b5c1fcbff36adaa5e47ae84
+
+[Alen = 11]
+
+Key = e94dac9c90984790a7c0c867536615ff
+Nonce = c19f06f91e645d4199365f18c0
+
+Count = 110
+Adata = 537038b5357e358a930bd6
+Payload = 4d64461c55eb16bf7b9120f22be349598f2f394da8460dc6
+CT = e9fc5004c2359724e1e4411ae6f834ef6bea046d549753c88790c1648f461a31c84e62ea8592a074
+
+Count = 111
+Adata = 7e3d7b3eada988668f3784
+Payload = eab7d5dbd91d4cbbac8d79fadd70b5dcb3baadac5cb713a3
+CT = 4e2fc3c34ec3cd2036f81812106bc86a577f908ca0664dadacb1d1c9231d2c22ecfeed622792dfd0
+
+Count = 112
+Adata = 78b107b29c4878ff18f749
+Payload = 3c6ae2e2578875a1f5611582528e058aece2ddc33a4dde3d
+CT = 98f2f4fac056f43a6f14746a9f95783c0827e0e3c69c8033fffe60299768f048e7098033cde046b0
+
+Count = 113
+Adata = d293908bb516c5f3a411b9
+Payload = d7a46e726ed43f1580eb52141a93390982cc809dc833e3f0
+CT = 733c786af90abe8e1a9e33fcd78844bf6609bdbd34e2bdfe4ee6ebc0d90a0de05b428495c93e1801
+
+Count = 114
+Adata = 33ef208faad4d2948c9e67
+Payload = b1fe5d9d34157193fc0608cd8ecb872e17720f5f6814a466
+CT = 15664b85a3cbf0086673692543d0fa98f3b7327f94c5fa687e7e64cc0fcd6a92c79ceb6ce2abd8ee
+
+Count = 115
+Adata = b7f7ed9ccac3c2b4fbfee0
+Payload = de6bb539fb7a9c87414f62a7cf25a4cfca176509e991af41
+CT = 7af3a3216ca41d1cdb3a034f023ed9792ed258291540f14fb02b53bc779e0976b634b0d1b88fc0a9
+
+Count = 116
+Adata = a6e287383927f76e4927af
+Payload = 8719d20c20c8959068b8adcd65e6f6bc7b3693828f0735a0
+CT = 2381c414b716140bf2cdcc25a8fd8b0a9ff3aea273d66bae3c37fa936243b393f07fcccb0fc13e41
+
+Count = 117
+Adata = 70828be6dd93954f4e7b6b
+Payload = 30b39426831f61c8ba5f2ef5b71f0c4b2f916e3b5a578110
+CT = 942b823e14c1e053202a4f1d7a0471fdcb54531ba686df1e0d7534a489e6d242966ebea4455f8f79
+
+Count = 118
+Adata = 506015fc2831df293f4da0
+Payload = 818d5d810f678629f078723f5c6c3657271077533bfb7c29
+CT = 25154b9998b907b26a0d13d791774be1c3d54a73c72a2227ccbf64f04e95b180d09e843847d22104
+
+Count = 119
+Adata = e9394b0245b379e68e3dea
+Payload = f0613205a7a0822849df9e8a3cf6caf281f3adfa966c5507
+CT = 54f9241d307e03b3d3aaff62f1edb744653690da6abd0b0927b546ef8cd717073832584fb25a0645
+
+[Alen = 12]
+
+Key = f6bb5d59b0fa9de0828b115303bf94aa
+Nonce = 05358f33e1fc6a53ab5a5c98ce
+
+Count = 120
+Adata = 040b25771239cc2a39446e3c
+Payload = 011fc50329bfd63a85ebd4f7693363602f1a4147371270b7
+CT = 4432d7eb42980734d34f19c50cf8abf71ac1b19ed75a727854e5d050a405f755047d09cb0f49546a
+
+Count = 121
+Adata = 50a1d37fa2f3462bd304631b
+Payload = c90e40540d372ab1eb00ea5d5b8de5bf7c94ce4e376d6949
+CT = 8c2352bc6610fbbfbda4276f3e462d28494f3e97d7256b862abee8547ee3f24cfa677468ecc1d121
+
+Count = 122
+Adata = ac3bb872a41df35e415d2b0c
+Payload = 9e7be78c0ab9e6a4c6c257e77c63681bea35d951f168b0c5
+CT = db56f564619e37aa90669ad519a8a08cdfee29881120b20a61cef865ce4080e7c7abfc43f62c03a3
+
+Count = 123
+Adata = e3106ae6456153dd922640a1
+Payload = 00df0c5a5d3eceb2bd293066529799544f846672a9a1d31b
+CT = 45f21eb236191fbceb8dfd54375c51c37a5f96ab49e9d1d4e1d19c321a1e0852adba939b447220ab
+
+Count = 124
+Adata = 297b4498bf5427e6341aa927
+Payload = 14967a0476dbaea03b07fa8d40d344eabaf479be2443243a
+CT = 51bb68ec1dfc7fae6da337bf25188c7d8f2f8967c40b26f579ea5fb65018abdcde1a39f6859ecb56
+
+Count = 125
+Adata = 5de60dc0e3b5bda0b33a9520
+Payload = 2da3716d76d10b6766a1f9cbf9f420316fd5f396e7b9a2ba
+CT = 688e63851df6da69300534f99c3fe8a65a0e034f07f1a075c2629ff871ee15745fd8c1ddbdae4c29
+
+Count = 126
+Adata = 1c9b8541943ad50b4243c179
+Payload = 8c1b3ba18d1f5cff74a457aadd6b3e7d093d06ad2622e6a0
+CT = c9362949e6388df122009a98b8a0f6ea3ce6f674c66ae46f04e198ad16ad1106d3ba6172f4a13a8f
+
+Count = 127
+Adata = 51e926d2542ac8faef61465a
+Payload = 88936e97db070c0ec2aa58d1c6f5b34df3d32ddf7db34a8b
+CT = cdbe7c7fb020dd00940e95e3a33e7bdac608dd069dfb484475981131e3934ec6d41e00d502729799
+
+Count = 128
+Adata = ebefbac97b363e6f32526aac
+Payload = c20742e4b410c5b661da373a905fb0ed55b20e0e879eff5c
+CT = 872a500cdf3714b8377efa08f594787a6069fed767d6fd93e2c005b5bebe07ff578b1b4bc51971cd
+
+Count = 129
+Adata = 1ef059ac7d648e9e32d9b1f2
+Payload = 65c55ca21a89a8325365bf2be861d700559de2eabb41b37f
+CT = 20e84e4a71ae793c05c172198daa1f97604612335b09b1b021a25f15b5b4229a872a9199972c85b3
+
+[Alen = 13]
+
+Key = d1da2e961e78063af8de41865b226873
+Nonce = 03739f5474857006340cce554d
+
+Count = 130
+Adata = e3afd091d2b588465872a6300f
+Payload = 8e5fa1a6662a8378cda15697e926841594f2f394fa5a34ab
+CT = ca0d95e3ff186ad6b88d45fc4079e6b7b4a615e7e8dd5f4742d522cc9dc19c47a4fa0b1528069cf8
+
+Count = 131
+Adata = ce3186bb737753b59ee76b748c
+Payload = 311ebc5ff2f625944562ea699b2690df3e6e64a17c62bd3a
+CT = 754c881a6bc4cc3a304ef9023279f27d1e3a82d26ee5d6d659b26510b8f25610799e011d7c850ecd
+
+Count = 132
+Adata = bfd636989dfbcb0edc9f014cc8
+Payload = c96cee5ba7b799f16254a17b1870cdb85fe0ef3f42110c13
+CT = 8d3eda1e3e85705f1778b210b12faf1a7fb4094c509667ff52942aa0d39649f3d9ed535bebc2b603
+
+Count = 133
+Adata = 4812b092aa59d57451bfd812c3
+Payload = 13b1b4404dc5735655139414fcbd02c5327ae9fb148bd324
+CT = 57e38005d4f79af8203f877f55e26067122e0f88060cb8c8c1e61efb9c1d84ddac2d24f43531f569
+
+Count = 134
+Adata = f6ef9ac4f4c9ce1e4309c64fa8
+Payload = 6c5b59319e2710f5d63407f85b424d1860425ef8ce0cfe53
+CT = 28096d740715f95ba3181493f21d2fba4016b88bdc8b95bf13350de0ef34df12fb945b0ae0a0d9bd
+
+Count = 135
+Adata = 9bf12168bb3d79ebd25262f2b4
+Payload = 968e1d78008da78611e82985c4028e86770858cfe61c3723
+CT = d2dc293d99bf4e2864c43aee6d5dec24575cbebcf49b5ccfa0734563638598d8c4bf1fcd94009925
+
+Count = 136
+Adata = 7d870d7e52d3053c65eefad477
+Payload = 6a1306d911434cc7400d2f9a95e36aedceddca2b3d583f51
+CT = 2e41329c8871a56935213cf13cbc084fee892c582fdf54bda1f5fc53b08aca82bccfba6fbcb27e69
+
+Count = 137
+Adata = e95099f04371e445e5eaa1d80e
+Payload = b9197eb50c8168d16b8a12bd261d553ffcc521d979b26fee
+CT = fd4b4af095b3817f1ea601d68f42379ddc91c7aa6b3504027d1a922953facbd630d7fea6b63594ec
+
+Count = 138
+Adata = 3e80eb03db6545204ef4241ad6
+Payload = 95f59e36eac8eb3b51709d635b07fa2da0976ea20e25807f
+CT = d1a7aa7373fa0295245c8e08f258988f80c388d11ca2eb9383fa000d10078256b71249d9d1f1846c
+
+Count = 139
+Adata = 9748798c0f3cc766795c8ce0e4
+Payload = a48db9add9ecdeb49e51d3ab7bb2075202ed2aa50c0195b1
+CT = e0df8de840de371aeb7dc0c0d2ed65f022b9ccd61e86fe5d2773c2f55b752477c489facee812c614
+
+[Alen = 14]
+
+Key = 1eee667267ef10b03624cf9c341e3f75
+Nonce = 0630a3eae27e505c61c56e6560
+
+Count = 140
+Adata = d24651ef0561282d3e20e834960c
+Payload = 798e31cce0a83702a95171fb1162a17b9ce00ec3592ce262
+CT = f3c3e52f1a1ff528a8d3783ee4e75f114e3e6416334815d2d9236d5c5c9319092078411b72c51ba8
+
+Count = 141
+Adata = c527d309ab29ee91c5fc53117e71
+Payload = d79cd4c8891ec4ce2c51136712d23b32266b2b73768aeb1e
+CT = 5dd1002b73a906e42dd31aa2e757c558f4b541a61cee1caed8ad2a48cb734e3f93e602c15c7c775e
+
+Count = 142
+Adata = a93dfc3944514ddfc5acdd89fab7
+Payload = d7fa81c949f1f2af29dbd56529b307e3b348e996d0936455
+CT = 5db7552ab34630852859dca0dc36f98961968343baf793e5f34b297f3f106a9cdae255f7634fbd0f
+
+Count = 143
+Adata = e502abe21c7b22120693a08ef3e6
+Payload = 6330caaeddf0473d564d175b9408c6f12e6d3cd4ee2c423f
+CT = e97d1e4d2747851757cf1e9e618d389bfcb356018448b58f4f5d9c3dbfe3e2fe03a002e55039ebe6
+
+Count = 144
+Adata = a49b34dfad43333fb2ffd701a2d6
+Payload = 45671482c390e65f75de15ca91b93596e9bf3d6fc9178bcb
+CT = cf2ac06139272475745c1c0f643ccbfc3b6157baa3737c7b6f7bb0749c99d75740f2d193fef36c60
+
+Count = 145
+Adata = 9e4d8aa3dbdc4d4b4b8d72734f52
+Payload = c8f34bea8bdc403a48d8ed9268429141cd03c29558050ef4
+CT = 42be9f09716b8210495ae4579dc76f2b1fdda8403261f944ceec82fc674da9efa6926e8641729ed8
+
+Count = 146
+Adata = 052327ad59cc791259817fd0ed96
+Payload = d8d1c57b16c23894b66023c29f8648ce4a6074647e1f5f69
+CT = 529c1198ec75fabeb7e22a076a03b6a498be1eb1147ba8d92ff19e93f60c8f3a511300fddc38ee59
+
+Count = 147
+Adata = 14bc3c44c001ccb261a2a0526523
+Payload = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b78
+CT = fb8c9e93cbb4ff9b5a7c2a72aa6863c55a58b7c4534efcc87fa00fb244eda0d77cf6c05c8fd590af
+
+Count = 148
+Adata = 3477384c396a9e9efb3e169722cb
+Payload = afa795f836763a1210bb36fef167864f73ba3b6abc593537
+CT = 25ea411bccc1f83811393f3b04e27825a16451bfd63dc287bae19612657c87d3bb73cfb8cee7c8a8
+
+Count = 149
+Adata = 0c3b9a6924ad506038cb2d6590c9
+Payload = ca4a186f116a179579e3d327aec3f5be358bc7094f853bc3
+CT = 4007cc8cebddd5bf7861dae25b460bd4e755addc25e1cc733d9713d2e916c23ac3039de34c295fc4
+
+[Alen = 15]
+
+Key = dbbd26f5d9e970e4e384b2273961be5a
+Nonce = 0b1eabe504ef4822542e397fec
+
+Count = 150
+Adata = 477937301c83ba02d50760b603e0ea
+Payload = 553714e17a208a2eceb847a4a2d95088388b1ac8d8ca43e0
+CT = 1c80213268bad5402c4dc9b5d836ab7499810d0d8a974716df9a0e986ab2890736423bb3772cec3e
+
+Count = 151
+Adata = c91eb5a07ff19c044023e5cf339203
+Payload = c94d0b9e728413c58202cb3f6b82dba7aa9e3ca0a72c40c7
+CT = 80fa3e4d601e4cab60f7452e116d205b0b942b65f571443139f907a92cb01215e3cda84ae13af48b
+
+Count = 152
+Adata = 38c71a8e9b279c605c7f0418a0afc1
+Payload = b4e8c4fd5ad98a1be8b5a11677c57ca1c1694e3528092aa9
+CT = fd5ff12e4843d5750a402f070d2a875d606359f07a542e5f3dbd8dbf7485106cdf9ea0e7088a5650
+
+Count = 153
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe8
+Payload = 578ce26cdb5ba2e8798e23588e5cd04ef782820b80e49a42
+CT = 1e3bd7bfc9c1fd869b7bad49f4b32bb2568895ced2b99eb4853fde6f4dca88ff11bbce20ed9e5012
+
+Count = 154
+Adata = 36004342dd74e7966692a848b2c11e
+Payload = 78733c635d4d4e8b0729732f1e174dfcec4e020a7ac3870d
+CT = 31c409b04fd711e5e5dcfd3e64f8b6004d4415cf289e83fbd94e979108fcecbd32f6bdf72f0ccb4d
+
+Count = 155
+Adata = db92bc3fe5d4141aeb39baea6f114c
+Payload = c7aafe7760945e45703c1e19f1032dfd56ddc216c3b03826
+CT = 8e1dcba4720e012b92c990088becd601f7d7d5d391ed3cd0229c8f9d4e39fc16cbdb44236ef125c7
+
+Count = 156
+Adata = 34ec2d5b6f0d950509b47a0637d74c
+Payload = 2345e36a63be0b78df95e60907c78da0e48e61e70685a1f3
+CT = 6af2d6b9712454163d6068187d28765c4584762254d8a5051c9ab7cb0a779c3fa78c9ee12603802b
+
+Count = 157
+Adata = 6ab658d177c2dd87c9b8787cd70182
+Payload = b0725f735543eb0c0ec88ae69b140f5787d28ef4a2e36d57
+CT = f9c56aa047d9b462ec3d04f7e1fbf4ab26d89931f0be69a1648c6307ec5ea304045a7cdc93f36b9d
+
+Count = 158
+Adata = 483f135c61250fa610b4d14b99ecf0
+Payload = 315a947bf5291278d446d332ee5ca0def7655d5c957a8fb4
+CT = 78eda1a8e7b34d1636b35d2394b35b22566f4a99c7278b42364ff3b1ad915347b1c7f062b10d3da4
+
+Count = 159
+Adata = bb022aed60819ef84ae83ce27db9d0
+Payload = f78d00755bcb45e6822121fe7cb03c8e627c9f548ccd7e7c
+CT = be3a35a649511a8860d4afef065fc772c3768891de907a8a7569808dab58d42181543b2e2d05992c
+
+[Alen = 16]
+
+Key = 10a7720f2e18f739c26924925af6b670
+Nonce = 8c4e7813ab9bce9dafee01c628
+
+Count = 160
+Adata = a209941fab710fda38d11c68b13d930f
+Payload = e59782a9aea45f467b90e51a0fdf166baba05663def2d8b6
+CT = e357b1ccdaca6f3506dc45279c2e4c59f5307a5fd6a99cd72341ea8c0785569973f90ee9ee645acc
+
+Count = 161
+Adata = 2e2f6f9755a492ee54df77b2ecab9808
+Payload = 042a072f6ebf11f79fcb4f5a64f7946dc837d9d2355785ea
+CT = 02ea344a1ad12184e287ef67f706ce5f96a7f5ee3d0cc18b703eb81224cdb1fd2e1cfb2fbfe1e402
+
+Count = 162
+Adata = 99e98c9983c85d1f49ae43ebad67a652
+Payload = 5db6bda27910e7b8b61ac476c6532570b71b3932bd6a698c
+CT = 5b768ec70d7ed7cbcb56644b55a27f42e98b150eb5312ded64c4aea7f17f18f068897557c93ffaaa
+
+Count = 163
+Adata = 37a837d73fa15793f6f823fb99c2ea74
+Payload = 8cac261a461c3ddd2642b8e4e5c3389e491fcb2ff8356412
+CT = 8a6c157f32720dae5b0e18d9763262ac178fe713f06e20736f3b2e70e6e2dc7acc74a823a7f49722
+
+Count = 164
+Adata = 11119a4e779cfb64c736d425e4ff554d
+Payload = 3429f9b088b501d7944c462694d0799568282e7ce07d3e61
+CT = 32e9cad5fcdb31a4e900e61b072123a736b80240e8267a000dc3b57096f0df1d4eb5328c416921bc
+
+Count = 165
+Adata = 962d7d4305f23d1692747b504960c0a4
+Payload = a46ae4c71d4c9eb72fabfa76b8074aa02e07653eca10eef5
+CT = a2aad7a26922aec452e75a4b2bf6109270974902c24baa94f62ed804e9f2ac0f7001d0f35ea9f3c1
+
+Count = 166
+Adata = bbb1fdfefcf3657ba6cd93ff341a04e1
+Payload = 92f5e3083f57c77ac9553a2024a66489698bd2261f05d415
+CT = 9435d06d4b39f709b4199a1db7573ebb371bfe1a175e9074907dcd7ac1e0bb248d46c3036c39fb02
+
+Count = 167
+Adata = 74be126f7c596642dafa8fe3da904e69
+Payload = 41ecc3aae5cfebfad7921a47a0684601ffe73816380f8716
+CT = 472cf0cf91a1db89aadeba7a33991c33a177142a3054c37787cbb80fd21127feca7e76fd6947d5b7
+
+Count = 168
+Adata = d72cc521c90a468522af8966c24799f3
+Payload = 8850bdda4bd0271e333db344a47b837183eb48269c3dc0b6
+CT = 8e908ebf3fbe176d4e711379378ad943dd7b641a946684d7cdb5d1243b6e73b8e380d8ca041647db
+
+Count = 169
+Adata = 28f427fba8d0bb0380bbe5072ccfa519
+Payload = fdd3ca2f193f93f5a349b50357d26748b767cde6ab5cbfe7
+CT = fb13f94a6d51a386de05153ec4233d7ae9f7e1daa307fb864a0ae8604b103f882f17db893ed5c576
+
+[Alen = 17]
+
+Key = 6bffab1f4f4c1ff66b4a669b515b2f8d
+Nonce = ddb34d5e0140fb96d690e1a2b7
+
+Count = 170
+Adata = 5cbba9ea778e01af00afb2a934f28c7211
+Payload = d91b12e8655dd92b1332fc1d71c391c96a17111562d90ba3
+CT = d302e5b2d5d90433186b804cd7717e2db2f22cdc34fb2942ab30780a2c4f12af8f35350d65284c59
+
+Count = 171
+Adata = 1583138aa307401dddc40804ac0f414d33
+Payload = eeafb08d4a4819f5682a01d44371e34cc5729079e74e73a6
+CT = e4b647d7faccc4ed63737d85e5c30ca81d97adb0b16c514746577901b7f6feb88b8e2b8562f9cb5f
+
+Count = 172
+Adata = 23931c258c84086500c6a3b6eda457e6b5
+Payload = b8737d5bbfc976c2d8d9786148dea664dd83cee98df537b5
+CT = b26a8a010f4dabdad3800430ee6c49800566f320dbd715548735a59390ba7a892741694f3a89b0bf
+
+Count = 173
+Adata = e12f98507d6514c3b551d240595346bc9e
+Payload = eb021b63c61c0b194bd44870608d7ef0b932b6104412d7a9
+CT = e11bec397698d601408d3421c63f911461d78bd91230f548f4f81ed18cc1820375a7bec2318cde1e
+
+Count = 174
+Adata = e14b87d49d231c0199eec627fd7f1b5332
+Payload = 93b42584c4956078359d77e80aef52281b9228a1f66aa36b
+CT = 99add2de7411bd603ec40bb9ac5dbdccc3771568a048818a187b430caa60d98dc3e2aeefe6249b44
+
+Count = 175
+Adata = ca095aec96a8b093e62b10f0950ce35ce7
+Payload = 6a788d8238c7b313b8eba27b210a71c36819d719115b9b76
+CT = 60617ad888436e0bb3b2de2a87b89e27b0fcead04779b9970a77372b727408e1bf5a70790b9eba3a
+
+Count = 176
+Adata = d1cac02b34ad33c0e77a5bda2c3baf5e5d
+Payload = 3bc1ee54d0094603dfc68eee118e547d031fb36e464e776d
+CT = 31d8190e608d9b1bd49ff2bfb73cbb99dbfa8ea7106c558cdc1f5cb4d4fa2204e82eedcb3784443d
+
+Count = 177
+Adata = 065c06b49a49898e20bb679e35edbb1f76
+Payload = 8a12adb8b746216baa8a418725e608e4377f13816a036a10
+CT = 800b5ae207c2fc73a1d33dd68354e700ef9a2e483c2148f12413f9496592a75a1d6e42ee3a258607
+
+Count = 178
+Adata = 98a42d7a0c5917deaf3b4de3f0cbe0a191
+Payload = 30a226c07401d0ae24c73d682e3a6e7e377ec1613bafba17
+CT = 3abbd19ac4850db62f9e41398888819aef9bfca86d8d98f6b571a3150887df1ac5f813676b2eb24f
+
+Count = 179
+Adata = e245a7528931841b52a5f59d861d98d7b7
+Payload = 3d17bcdf30445ebd8a9b6aa2fe11d443c1161bb1ee69ced0
+CT = 370e4b8580c083a581c216f358a33ba719f32678b84bec3131aa5e4657c92e31c69ab18d447d3578
+
+[Alen = 18]
+
+Key = ae6136df9ab43631ef143515dacedbe7
+Nonce = c5c445792208a50c8e93d64aa3
+
+Count = 180
+Adata = e04006b68c83a5dd4ceac3cde238e48895ae
+Payload = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731
+CT = c7584c0203c2535c5702c6ae93b7cbfb066f4a055c627a180d6d676d11fce907b5c93fa1ed7bff2b
+
+Count = 181
+Adata = 5da64e368f45153ea5b7ddca966b6c5b699a
+Payload = 15e0c672c6764f3699d9d3e7120f8ce5daab166f08fdd074
+CT = b8f1b62e36c280a68fdacefb6a8ea6fb67012bca0351ad5d2cd45f211b1a1364c91ad07959bf0ee5
+
+Count = 182
+Adata = 1b315d024bb5d1e03d7510e61f37d8adb10a
+Payload = de907d58cd8f5a72acaa1d329b937dfbbfed65a4e45eb029
+CT = 73810d043d3b95e2baa9002ee31257e502475801eff2cd0018f021a98b2edfb0b7500363099c2a1a
+
+Count = 183
+Adata = 8691ba4f9232ca86f919fe72ddb39c91d707
+Payload = c7fa314d27be79f9d3e2d1e188c1785b0c970f91b8ed4290
+CT = 6aeb4111d70ab669c5e1ccfdf0405245b13d3234b3413fb92ac9aeb018c48f3902276ac759710b6d
+
+Count = 184
+Adata = ff0baf1cbb5884a9290ea7b5ee49915efb4b
+Payload = 33b05b20f3c849fac091a5028cbfa0bc9a1c32514136fee3
+CT = 9ea12b7c037c866ad692b81ef43e8aa227b60ff44a9a83ca7dac49f606dadb9f7034e0a1860d519b
+
+Count = 185
+Adata = 2d118cda20700bc2748ea1753fbca6f74933
+Payload = f43832e420e2eccd5d80502bea2ba1804e17d4433318fc86
+CT = 592942b8d056235d4b834d3792aa8b9ef3bde9e638b481af623ccbab19c1442806e21c5a820945da
+
+Count = 186
+Adata = 0c7a5fd2010c999a8a0efa81f89ff5bfefe0
+Payload = ceb203c842a962183f22e602644fc66e4290b3d5be445fb4
+CT = 63a37394b21dad882921fb1e1cceec70ff3a8e70b5e8229ddbcd18947ac1800856c9c92eb0388c70
+
+Count = 187
+Adata = 73fdddb9e0a64f5671fd70c4ea8443507789
+Payload = d6015b6bd5f5eabb2a649129f8f727c06a3ad59499f21caf
+CT = 7b102b372541252b3c678c3580760dded790e831925e618639c29ea73b0c5aa130d8b14f7b9926a9
+
+Count = 188
+Adata = 82c4484e3a6e18b6bbfd78b69b00c40b30c5
+Payload = c288b810fb533441bd549d02c0b28d5b834293683eaacda2
+CT = 6f99c84c0be7fbd1ab57801eb833a7453ee8aecd3506b08bf0a0f148ae138c2ea02538c8fd7ac76c
+
+Count = 189
+Adata = 267d8385b14721eded743cffd69e4d595f7e
+Payload = 667cc47d13c34923be2441300066a6c150b24d66c947ca7b
+CT = cb6db421e37786b3a8275c2c78e78cdfed1870c3c2ebb75285eb537e7583f04e040a0ddc41106213
+
+[Alen = 19]
+
+Key = f1908328edf2996ebfc9655472ca5ad0
+Nonce = 4c693364546930b6c5250e2699
+
+Count = 190
+Adata = 4a3634e5028df97fbe00eb016e8ea4f1918faa
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 90c850790b0b380f5aeb2488fdf43c9d5ef1759861e86f6e52570e769629dcc2e568737ba53a1195
+
+Count = 191
+Adata = 041b93e3fc059fa44aa755e88df277b9b6e499
+Payload = e61ca7310172eec16745a73e34516f65844eecd0dbc5566a
+CT = 980af6f885e3e6f2e2ba4a2bb3e020d1a87976ba1bf63feff1d82ec19a2e3ec43bbdb34e10999d90
+
+Count = 192
+Adata = d1be393376cb5d23cf8139da0fd92f3d520ae9
+Payload = ea887edee68ad5fa6bae928aa480dda898037f820700ec52
+CT = 949e2f17621bddc9ee517f9f2331921cb434e5e8c73385d7f2abb0ce4de9eeb5e8af9cdf3391d3cc
+
+Count = 193
+Adata = f3e551b34d2db1286a9f41085e4dda95ec3f75
+Payload = 71fe1ba5d299495d2a56039c64032ec6263d437f55e3f5be
+CT = 0fe84a6c5608416eafa9ee89e3b261720a0ad91595d09c3b239c73b01ba49a8498b5ff4833851069
+
+Count = 194
+Adata = a69ddc66e63a3415f21009d53adcf26bc1a9a5
+Payload = bd04d854216740a6ceb9827cbddd83761d19feb2a21d78ef
+CT = c312899da5f648954b466f693a6cccc2312e64d8622e116a2248dacd3903c26a2dc5ae649566ad67
+
+Count = 195
+Adata = 5735d6f5882d8f27155eb4cc285a65138ad64a
+Payload = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda
+CT = 4da219ba2330ed8378449366c0d371fb8dfb435d3e81065fd4156cf7d97b2e744351b6960a807cf8
+
+Count = 196
+Adata = 5d94ed976ab2063512690ae704c3b115519742
+Payload = d3909d577a4e89642227cc6fc146b61bc18392175e342898
+CT = ad86cc9efedf8157a7d8217a46f7f9afedb4087d9e07411d5a50086b6711ac72533c3c5717f6892c
+
+Count = 197
+Adata = db20b384620ab8691aed2fed14a745188d94c0
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c56699029
+CT = c41147fcdb6eb0dc1182c7006ce978ee33c69226965af9ac54fb74ecb9a5163b01b9dbf97ff2f999
+
+Count = 198
+Adata = 94897cdd04e0c8480b2ef7b5201dda37558ba9
+Payload = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9cc
+CT = 215d1e5e323b409e36cc81509d1d78cbf27d452d494cb049d2a81702f665ff5c54f586defd268c94
+
+Count = 199
+Adata = 95c44e1e5ad256b3ce1cc1d87137a1e09f1fd4
+Payload = 598e91d39c414496fd5e69f2cf80826b4e7d59ba28e0a0d8
+CT = 2798c01a18d04ca578a184e74831cddf624ac3d0e8d3c95dfa641889723e163825ab65727e8a5343
+
+[Alen = 20]
+
+Key = 61cb8eb792e95d099a1455fb789d8d16
+Nonce = 1f37b3e59137f2a60dc09d16ac
+
+Count = 200
+Adata = 09db3efac9473f713da630ae92c2c8604c61c51e
+Payload = 6ad541695a37c32d73ff6d5f870abd5b0f362a8968c4fce0
+CT = e65fcc975865c1499b088b58ba163283085d8ca68dc3b235d89756e5d78753ef22c012ae34b39a20
+
+Count = 201
+Adata = b6d07035aed9c141c713cc3bce60f7ba8ac2545f
+Payload = 9cce4c82fe9d38ef64ac8abdf0619f201a25ce6903675627
+CT = 1044c17cfccf3a8b8c5b6cbacd7d10f81d4e6846e66018f2fc78ebae9c143a7283b0641e1f83f5a0
+
+Count = 202
+Adata = 80a5ab693378af29cd5a33555cb3579f9ae540aa
+Payload = 7295a7aed3e987baef19ad68c33ba5a5dcbff27875ff5236
+CT = fe1f2a50d1bb85de07ee4b6ffe272a7ddbd4545790f81ce35a7e44348d2b3085348f787128a4e96a
+
+Count = 203
+Adata = 220817144a15a0a654fc1beaabce60270aa72df8
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 67ab73defe1d9021c3d1f8ab3067ffd9681fcf803af0ed2024dfc096cd8a09d2d81f6146fb54082a
+
+Count = 204
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01
+Payload = 23bf80f51dfd83f63986910e69d54a315c2bfb43f432b7de
+CT = af350d0b1faf8192d171770954c9c5e95b405d6c1135f90b5da82204f4dd8f535cb2fec2f133d882
+
+Count = 205
+Adata = f2c76ef617fa2bfc8a4d6bcbb15fe88436fdc216
+Payload = fc3a50cc8a68778327923ea697f5388da4c814381e29c5e4
+CT = 70b0dd32883a75e7cf65d8a1aae9b755a3a3b217fb2e8b31108630135498ba409f4b6c8caee8a85b
+
+Count = 206
+Adata = b40c8c1d2cee490653105ca2443356cdb63e4fd0
+Payload = 465e41c69928d08c33e063ea119595a04d0de6bffd17bba5
+CT = cad4cc389b7ad2e8db1785ed2c891a784a6640901810f570f89c515837d129ba41f9c24b0229ddcf
+
+Count = 207
+Adata = 6ebfa1e8f80b3cdb1bedf2e3c7e74f30f55c38e1
+Payload = 3f98ee3922f8f1086e3135ae66c5465426b13c8794954880
+CT = b31263c720aaf36c86c6d3a95bd9c98c21da9aa871920655a352fa6b9c4e40733ddcd3fcdaf9ae63
+
+Count = 208
+Adata = 6d0159861031c1a5f01aab35927fe2ab28154d19
+Payload = 5b43067a5ab3a9f9e633fdc084c44ffa7f11edd12ea5873d
+CT = d7c98b8458e1ab9d0ec41bc7b9d8c022787a4bfecba2c9e82c1aa13f062c0f1f5008e27ff2191942
+
+Count = 209
+Adata = 15e5ade017b30ab41878a2747e93aa91c61c2908
+Payload = e40b7e9e46e339e64891526e730b3bf6562fa37acefce307
+CT = 6881f36044b13b82a066b4694e17b42e514405552bfbadd2e149dd02bc7face0c4dfe4e501c2ac2a
+
+[Alen = 21]
+
+Key = be1ed49e2cb0caf6b6a0940c58453b93
+Nonce = b78ad129457681fa7346435b97
+
+Count = 210
+Adata = 161d92c7df1ebb0924719e066e08b95eb4914a5eda
+Payload = a9eec383f63892521e4616fcbadc5485942ffaf4669c43a7
+CT = 949be340720c4fdc4adc05cb777dd81a2549628d33fba07e62d2b338a7b34ebd9d85c244c952d681
+
+Count = 211
+Adata = 6b1d94bc0c6e45fc905c509ea667853e4b2c5a8848
+Payload = 7b44a093162bfc8b4d65f1031d890a6b08a3705b142c0c26
+CT = 46318050921f210519ffe234d02886f4b9c5e822414befff8a4defafeb3d61dad8c007b68d8fb9b3
+
+Count = 212
+Adata = 868dd3e241f60f097a7a2fe571307ee5eb961218ca
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447cad9d5
+CT = 15b1f61dba183895d001006a515cbc1b41858d2d12ad3a0c57cbab553b511d68a4f41db211d0a2fc
+
+Count = 213
+Adata = 3776f37fbf8803bdfd246ffaff2e59658a6c3f0ebb
+Payload = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+CT = 2ba665a3ee05875c14f0a8fc8e6c0034582e8802f3b699ab0290fd7dbf0afa3e597274e3c9fe170b
+
+Count = 214
+Adata = d0f2769eba9b8e618f00eed6b34c261c59322a253b
+Payload = fcbbcdd9599a86e7c8ccb9347065789a9728ca1220fa51ca
+CT = c1ceed1addae5b699c56aa03bdc4f405264e526b759db2139c7dec3960e6aba3174d793b4e08f449
+
+Count = 215
+Adata = 2be180892faed0bb75887668d187807666d3c66c68
+Payload = 8d145b1f792cc31a2e5b86216609bb018e7aea3012ff70a5
+CT = b0617bdcfd181e947ac19516aba8379e3f1c72494798937c7057b9e2d844e86ee5c3ecfb3270804e
+
+Count = 216
+Adata = 52859849a5b7c1d432c3bfb35271cd8141db2ec774
+Payload = 741db990b43ef34993c33d1c4953b67b128b9299dfe86d74
+CT = 49689953300a2ec7c7592e2b84f23ae4a3ed0ae08a8f8ead1150fa899152eef7a30ae0f20986818e
+
+Count = 217
+Adata = aa192759625f4e42d1d1fa73dc0f62199142155615
+Payload = 51dca5c0f8e5d49596f32d3eb87437bcae866640310ce1e3
+CT = 6ca985037cd1091bc2693e0975d5bb231fe0fe39646b023aba7ff9203608089558698ec29472dda7
+
+Count = 218
+Adata = 6de564226884188ec7bea3894535a875cff2a42fdb
+Payload = dfaa7aa8b28626210d5c24e2ddfe516189be05aabe26f3b2
+CT = e2df5a6b36b2fbaf59c637d5105fddfe38d89dd3eb41106b85bd0a5074ef852575baf5f12c22663e
+
+Count = 219
+Adata = f245f2ee23755df863dee55d7ef0c3c09a0b6f0b0c
+Payload = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc57
+CT = d3aa206931d9325331d3c04919e2d47ead3e145da4263f8e9eb617436bae012331daf020fce24e47
+
+[Alen = 22]
+
+Key = 34ab6fd7f54a2e0276fcb7cf1e203aba
+Nonce = 6091afb62c1a8eed4da5624dd7
+
+Count = 220
+Adata = 1ab5cc3d7b01dc74e6cf838bb565fea3187d33d552a2
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 0d30ab07153b5153637969e6bd3539448c541e42b3d432fd7ef14622a9b621d1721b944c60f7fd67
+
+Count = 221
+Adata = 1f1ac4674b272bc7a4ee9f4eae33e969b16fa90a69ba
+Payload = 14e99a2ef0de650adbd785c692342cdb765e6d20d5fca09a
+CT = 94cf7e706b44755193be855740cdcde455605601adf35bb6dfa4ec2c92671c64ee07946527be67f0
+
+Count = 222
+Adata = 43ee77f12ea42e82a02275a68aa95cbd1bb440442bcf
+Payload = 383242c709fe5f2ce782bf8c83b645d171f2bd238abc655d
+CT = b814a69992644f77afebbf1d514fa4ee52cc8602f2b39e71173572fbf3d9495760aae4347397b110
+
+Count = 223
+Adata = ae2ff288199be25bf640811541394ad7e1dd0dc0d24d
+Payload = 9c16a5b638c35c97c5c981c1b8dbcba11aec30e72e45a936
+CT = 1c3041e8a3594ccc8da081506a222a9e39d20bc6564a521a4d2327956e030b9df753e063b5b71201
+
+Count = 224
+Adata = 4ccfb4281852b5ca7e787723d689384a68ff9437db31
+Payload = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878
+CT = 6cbb6a8169cc55094068b67903b3cefc92ade051adea1354e4dac0c9130f5641afd035dd884b6271
+
+Count = 225
+Adata = d3a2fffc798fd9cc2f409471faf18caa2ff3dcf4e652
+Payload = 0db33eda4188a9165147e24e40f79fee1985eb68d5162728
+CT = 8d95da84da12b94d192ee2df920e7ed13abbd049ad19dc0448807dd50a9cf41651083c49c7493ceb
+
+Count = 226
+Adata = 7b5121aa4d1e314f209ffe3e92cd26ee4f74d91e27f2
+Payload = e0d3ea4308376423c4322503f56e427a64e2e6d8b4f5e668
+CT = 60f50e1d93ad74788c5b25922797a34547dcddf9ccfa1d448ea0da53046733f522ded40a09c6d7a6
+
+Count = 227
+Adata = 6e12c112720ef346bbbe7d1c19483721b1c52c438dad
+Payload = 491f2bca585d6b5fdf38d18890e4d1bc923fe26930b3d2f1
+CT = c939cf94c3c77b049751d119421d3083b101d94848bc29dd345cb5a968f39654b994686699d532c2
+
+Count = 228
+Adata = 20433402a2d869c95ac4a070c7a3da838c928a385f89
+Payload = f45908d691ddaf89c0bc129ffada94c3ceda5f47d63ef76a
+CT = 747fec880a47bfd288d5120e282375fcede46466ae310c46cce85eb55339b886b7121b306fccc0b2
+
+Count = 229
+Adata = 42f944c21cc221beaacb288115ac628346b8a1d94bd5
+Payload = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b
+CT = 63261824c00c9038caaa5a64603b09dd40bc4e3a210ef667a37ca5ce12aa6f0659467642deb8bfcd
+
+[Alen = 23]
+
+Key = ea96f90fbae12a857f5c97e0cba57943
+Nonce = 21cc46d9ced1539b0ad946e600
+
+Count = 230
+Adata = 105258d2f25f62675aee975cfdb668aff833f05b61eb2a
+Payload = 49db80f22bc267a70e5636dfbc8a21c83d9691fe4b9c3051
+CT = d2fcc8b7809b5fc07e44083e437d8180157f1782a9ce9f65c7fa9ee2e7cdc1b755258f2212a8a8f4
+
+Count = 231
+Adata = 0f5938540651fa4ca03867e67518eb2b73f60dd8750fa0
+Payload = 26618e21099a79d6c517335389551323065ad89c8848ea12
+CT = bd46c664a2c341b1b5050db276a2b36b2eb35ee06a1a4526bfdb9bfcd3b969fb2e41221eb92b0147
+
+Count = 232
+Adata = d6b228960fcbcf07c7bede616139db62b3808718a5b511
+Payload = 4de1d6d57144896ddea1c30f49afecd27bdf4840ed9928b5
+CT = d6c69e90da1db10aaeb3fdeeb6584c9a5336ce3c0fcb8781f8beea22cba93203c912209c78c03aa1
+
+Count = 233
+Adata = 75f8f071e229355e286882917ce5dd4f1db591fee51b6c
+Payload = 785359b1dc754a1e1b6d8731bd2d917ce3e91507401310e8
+CT = e37411f4772c72796b7fb9d042da3134cb00937ba241bfdc69a2e3ea4a40f7c491912c1a0778ebde
+
+Count = 234
+Adata = 4afb62aa8648ac7474dd16fcc376f8909c69e1ce36e6d1
+Payload = ab627aac1496d011ed2edcb2fc6b2afbcc394654f56124f6
+CT = 304532e9bfcfe8769d3ce253039c8ab3e4d0c02817338bc2a75c7ba2a769c27903e99b72639b0841
+
+Count = 235
+Adata = 736fdf94db820a2efe89e7fc9dcfe7c23d5754ac2bcc7c
+Payload = 40722cffb37f1455c2618408e777ed0f4b1bd039952730cc
+CT = db5564ba18262c32b273bae918804d4763f2564577759ff8f84f4ca4a69fde75d7207e50494819b6
+
+Count = 236
+Adata = 8a9a0367137c28db4c4e78d9cd9a68cde0d1b4583532ae
+Payload = dcaabf7a061502618541c09ea59dbbbd52b2692fd0064747
+CT = 478df73fad4c3a06f553fe7f5a6a1bf57a5bef533254e873a0c34a24d3ee0946034c71fba4dbb333
+
+Count = 237
+Adata = 34dbbff560ef04ea731b8979aef2ae50972f4db3efe14a
+Payload = dd641a893b16e0e173ea2eda20638bb01849ac11e64e8ddb
+CT = 464352cc904fd88603f8103bdf942bf830a02a6d041c22ef0f5e24a435a39a716c39f43dabdc4281
+
+Count = 238
+Adata = f3d1fcd912252431db9d8ccfc3e203d5b34d537468b4c6
+Payload = 9aa3e8ad92777dfeb121a646ce2e918d1e12b30754bc0947
+CT = 0184a0e8392e4599c13398a731d931c536fb357bb6eea673f623d59f66764d859a772bb50ec91fc3
+
+Count = 239
+Adata = 513b4cdc551c203ed5f1e659813584862023911590b672
+Payload = c8f44ae4b02fffdbce0df773c24075f877945fc7a86be460
+CT = 53d302a11b76c7bcbe1fc9923db7d5b05f7dd9bb4a394b543b6549eb16fba96318afb3df51f4675f
+
+[Alen = 24]
+
+Key = 35b403a15212097085d6e2b77ec3d4f2
+Nonce = daa423bf9256c3fcc347a293aa
+
+Count = 240
+Adata = d3c0ed74e5f25e4c1e479e1a51182bb018698ec267269149
+Payload = 7dd7396db6613eb80909a3b8c0029b624912aabedda0659b
+CT = 5b00cf8a66baa7fe22502ed6f4861af71fa64b550d643f95eee82c19ecba34280604b58d92dacd3f
+
+Count = 241
+Adata = 62f4fe53e99a9b0c51e9561d910d7e2ffe19a5176c9dec06
+Payload = 897f0dfd90213f64a9277a0eda4f134f303fa89f56ca54fb
+CT = afa8fb1a40faa622827ef760eecb92da668b4974860e0ef5ab4999e9689d52b8afeb87923efa3b48
+
+Count = 242
+Adata = 191c4dfa653c20292657f7694c6b6a4a410c49a879abd217
+Payload = 2b7cf9e6e2d6abcd7775f8a6eb6294e822041c4c45f09c3c
+CT = 0dab0f01320d328b5c2c75c8dfe6157d74b0fda79534c632cdc71e556c34fd4e1b5ebc50d38da8b3
+
+Count = 243
+Adata = ba34741f8edb51470eb20f891869aabeab562d92571ac943
+Payload = dccb9a4625512496b372a2b8b768f75741d8c2e30e57d638
+CT = fa1c6ca1f58abdd0982b2fd683ec76c2176c2308de938c3646223d381090661c2ee2370d29a572a9
+
+Count = 244
+Adata = 8b922aca6125722ec490b134a45864397f4e2c281d6e2089
+Payload = e0e452c990665465160b02cad6367ca89723613488d8efbf
+CT = c633a42e40bdcd233d528fa4e2b2fd3dc19780df581cb5b1f78af50466646b7c7e652f787afe5357
+
+Count = 245
+Adata = afb9fd78e3f8eaf4e8c91da62b2da534508e54f7dfa214fc
+Payload = b536fdb8839f87080ae65ec35da347e792622ffe18a61d46
+CT = 93e10b5f53441e4e21bfd3ad6927c672c4d6ce15c8624748cc9d9a1270f78648a6b66cb8c0f2471b
+
+Count = 246
+Adata = ecf942ccee7396cb3ee177eadd4d96a4af1d90afdce97376
+Payload = c81233826e5125e1f31fe275184ccba8f1a743e58e146e4d
+CT = eec5c565be8abca7d8466f1b2cc84a3da713a20e5ed03443b17d3d6f1fc4f530841b749d9f3a0a7a
+
+Count = 247
+Adata = 16fea92ffcaad563792aa924bffe7ef690edc90ea4e29cc0
+Payload = 24ab253b5b06552665c3c810254c0ed15e68a783180d7eee
+CT = 027cd3dc8bddcc604e9a457e11c88f4408dc4668c8c924e05852ed48cf88d9ab2326aa46b6541b60
+
+Count = 248
+Adata = 76f110eecd369d79e21fb208058359d3a2f37581d1f7f691
+Payload = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4a
+CT = 598e9d2078ce4845c6c6e0aa1c328fe7f8192a7852088444c62dff6bcade5ac2edb8ec9797ce433e
+
+Count = 249
+Adata = 8834c776a3237f060ae0ab9857324a3b2ac79f3b6e6f90f5
+Payload = 11cbfb3d348c7abef99f562607e289de34a2bb379a5dfe50
+CT = 371c0ddae457e3f8d2c6db483366084b62165adc4a99a45eb936ac4764575f85352c24ab23209d42
+
+[Alen = 25]
+
+Key = 7a459aadb48f1a528edae71fcf698b84
+Nonce = fa4616b715ea898772b0e89dd4
+
+Count = 250
+Adata = 0c0b4a45df5c3919c1e1669c5af5d398d9545e44307d95c481
+Payload = 0b3d947de8632dc8ff752f619ba7c84716fac7a23e101641
+CT = 7db9f3f7dc26fc2adf58d4525d26d5601e977de5a7c33911a1138cff7b624f9908b5b4d7e90a824a
+
+Count = 251
+Adata = aa27a28a36b5a2cee57ffeca0233feb4bdd4eacb2cae28e98f
+Payload = e6dedce2c278c44e5678d13e7d5b5d3501d61bb0bb6b5558
+CT = 905abb68f63d15ac76552a0dbbda401209bba1f722b87a08e23f92b598f7a248a894e6b8f5691bee
+
+Count = 252
+Adata = 66220aa9b40a1772caba7749a544bff938e804dbc6e556498f
+Payload = a276b0922fbd5094bf89b9329d07341e039d6204397b81c0
+CT = d4f2d7181bf881769fa442015b8629390bf0d843a0a8ae90e94043c0d80fd651469232fe9d47a81f
+
+Count = 253
+Adata = 3d765d20e03a4cebfda50316c4b7d8b6c55078d5b3e9cbc567
+Payload = b99afbc2dbb377350cc58d4bfe8e954cef25d7b27b82fad4
+CT = cf1e9c48eff6a6d72ce87678380f886be7486df5e251d58425088b522fc0731097e729448236b317
+
+Count = 254
+Adata = e91b6265879153e1692b00a112b4205111c8eb1a7b7f2c6898
+Payload = 56114cc783b80ca2dd2881387b6d92a59a237dfc8e976d8b
+CT = 20952b4db7fddd40fd057a0bbdec8f82924ec7bb174442db2208cf07574cc4f3f83ed6301b904404
+
+Count = 255
+Adata = 340b16f352817babb4fb70e9e6e18784b3e67bdd449872158c
+Payload = eb21fe20fc4f92452b261eac0d7b70016f7469afdff7a3f5
+CT = 9da599aac80a43a70b0be59fcbfa6d266719d3e846248ca514b0a900068e55cd24c92bbb78c521ad
+
+Count = 256
+Adata = 5a2423c2ff2d642c80ac1ca27dd779321f3e9c01445be684dc
+Payload = b15083a73607c9d7e197a8cc884ad3be98ac343f6493df67
+CT = c7d4e42d02421835c1ba53ff4ecbce9990c18e78fd40f0373f8ba66d74321c80c057f010078d2f28
+
+Count = 257
+Adata = 5fe8bb27a59a5f4e370adbba96484c2365fc0d8c6e58d7d3e6
+Payload = 07542d18e8f2d3e199fca0f90cabb78b169525fdce81666a
+CT = 71d04a92dcb70203b9d15bcaca2aaaac1ef89fba5752493a0a189319e4f06d53c1405d37b06cc8eb
+
+Count = 258
+Adata = 23e5422e8d7560a9e65642b5e723a47536c16791f3a0cf918d
+Payload = cd574ed56bdfd1408f7831e0b24b4345ee979ac906a7aa22
+CT = bbd3295f5f9a00a2af55cad374ca5e62e6fa208e9f748572dd72f48ae03670249d74f8460b63b1ae
+
+Count = 259
+Adata = fcc9422ba5023a9997baa9c4ee6cb196ffe96e08eb9c2b8a75
+Payload = 8c9abe94beed4c9bd46adb1d04fbfe7016dd50d324525abb
+CT = fa1ed91e8aa89d79f447202ec27ae3571eb0ea94bd8175eb1717c00c93d36a77141b723d573c8c65
+
+[Alen = 26]
+
+Key = ca748225057f735f712ecc64791367f0
+Nonce = 1341a6998eb1f50d4b710a13ac
+
+Count = 260
+Adata = 5fb96b045f494808c02014f06074bd45b8a8ad12b4cb448ec162
+Payload = e92cd0cb97afe4fb00c4f12e9b9abe1d08db98f49a27f461
+CT = 82b666694232e86e82295beae66ae67d56aceb5d6b1484ceb4a6843ec16078038c10afedc41f5362
+
+Count = 261
+Adata = 87db0d9d69bc0cf69cabeb92570e482bbc8ff3e1ba72f12f3225
+Payload = a6dbad96ad23ff61479df39b99f0673a09f2a7eaebbd34b9
+CT = cd411b3478bef3f4c570595fe4003f5a5785d4431a8e4416a7c6566d0b8ff97f946d7c7773a845f2
+
+Count = 262
+Adata = a061a09024f1e03b223695d4703ee202e90e07156b95859a22e3
+Payload = b1dd81cc3b2b0efe540a3194d6fe304cd2de53db7929ebe1
+CT = da47376eeeb6026bd6e79b50ab0e682c8ca92072881a9b4ee1d66a4728b67b42602e23c8500b0115
+
+Count = 263
+Adata = 0dd513c5d8d62b723ab8b0a3aaa477e843d9149dc8a2f878e585
+Payload = fb30c2e98f3d7e4ed7431da285711d3d287884db13a474e7
+CT = 90aa744b5aa072db55aeb766f881455d760ff772e297044803c51e8c59ed13b3e5d9b489d4ea2ccf
+
+Count = 264
+Adata = 3ff59c40bd796048e586eccc23a82e4d09fc5e779f38eb4afbed
+Payload = 886f9f91a6566ceb99c39462ab675a3ae3be98f68787626f
+CT = e3f5293373cb607e1b2e3ea6d697025abdc9eb5f76b412c0f1ec270b43fc5a9811b56ccf033789c6
+
+Count = 265
+Adata = 0df7ef91f7124da867e992bcbc6fb38232ff6d5205f38768da72
+Payload = ed370d1c2d6dc03e4fae4deb9343a7d4339562cffd427587
+CT = 86adbbbef8f0ccabcd43e72feeb3ffb46de211660c710528bb4ed25940d58cba64271fe1d2e8013d
+
+Count = 266
+Adata = 6777de159c34d005b94f67c33ae4a35ebab09d9cb9c56b4c9c81
+Payload = 2f77c2eb07db14bd713c5af10c0760ea3a6ca5ff8d046d36
+CT = 44ed7449d2461828f3d1f03571f7388a641bd6567c371d99392636a5e373c1354ea9b969abb4932a
+
+Count = 267
+Adata = 75559898f4ba03c55afc25ea91aa61a93c2f8270a5fa51b6f6dc
+Payload = 360fb89429dc9b48358097d930c8561b2bd18dc0a470d1d6
+CT = 5d950e36fc4197ddb76d3d1d4d380e7b75a6fe695543a17959a7e8bc0570f19159f91fc14ac6532a
+
+Count = 268
+Adata = 5e03fc430473c5de96d68907fa506f9da353ae48a965445e1f24
+Payload = f2d8d67b9f291c3edc264893922622b2693f3e7231137eba
+CT = 994260d94ab410ab5ecbe257efd67ad237484ddbc0200e1507e559568c27a30b5676f98cc66f57d6
+
+Count = 269
+Adata = 7eee4869e77f6db12c91d1f647cad2340d33a3defaeb362d311d
+Payload = 7fd6fb81c36e44b150af10e04683b1ec9b5dda87c71ff939
+CT = 144c4d2316f34824d242ba243b73e98cc52aa92e362c89964910615920f6f3c3421a9c2bec1bec7e
+
+[Alen = 27]
+
+Key = fdf2b2c7fcb3789b4e90abe607dca2af
+Nonce = a69ddc66e63a3415f21009d53a
+
+Count = 270
+Adata = c76846da496ed87b9c0f65c6266c9a822224acde9775efb186a4a5
+Payload = d7aa4efa5d75195a400018bd38f7d8cd53fdffe88df1837f
+CT = 150d9a8b78d9c04239d66207a1f95021bbb1b7c70d7c354825d05e5a2e76a90f6fe489fd74cab2a3
+
+Count = 271
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d
+Payload = 5f94a2e48d348a1d56c55a659306e319c3d2ad78b9fe43a7
+CT = 9d337695a89853052f1320df0a086bf52b9ee5573973f590be6af49ce97d5e0e77c7fd5d9cc6d932
+
+Count = 272
+Adata = 7631cf7822a545daefa16a5ec43c877d475a82d5aa2d51cec7fbb4
+Payload = a44b010fc1c659eac9241a58b11a73d7ce33156ddfc54c3c
+CT = 66ecd57ee46a80f2b0f260e22814fb3b267f5d425f48fa0b924b268cab915f999aea3e1cc3a88ccd
+
+Count = 273
+Adata = e4da34663edc44370bfd8aa8315945471a893a1cc069628a071ee0
+Payload = 28d157f5741f1be057d5219711414c0638b47d165a905a6a
+CT = ea76838451b3c2f82e035b2d884fc4ead0f83539da1dec5dc368f5af8e311e67209e02dfa2613377
+
+Count = 274
+Adata = 077509eae1dc367540f87832c5780f6c5b29e180bc6c1fee38e826
+Payload = ba7432a8e34bfaa91b35c8dfd822d86850be39e63150257f
+CT = 78d3e6d9c6e723b162e3b265412c5084b8f271c9b1dd9348ad175fcad35d29396380b79a28784cff
+
+Count = 275
+Adata = a513d750ca1e8bf6cb7b8cea5204e064c15c2dc40d742b31cf5459
+Payload = 3f5830b0ce8849a660af7d58a60c19a9824a3033bb5fed43
+CT = fdffe4c1eb2490be197907e23f0291456a06781c3bd25b7493b4b3e33d325359c9c651290ce73bed
+
+Count = 276
+Adata = e439db829c1291df49fc42c2fa1a92118c2665f11e13f28dc6f11a
+Payload = e69b2a243340df5dc70b2cb05be12e5992ee36f7d9f4ca84
+CT = 243cfe5516ec0645bedd560ac2efa6b57aa27ed859797cb371f88ca5857c6d801e726a01c621a0c3
+
+Count = 277
+Adata = a12c690568114fd7a677f49d74e84fc1a6b7f7d2a08693266c0a91
+Payload = 9de35b840a69a84701ffae1b1d2bf13c34b42a57d14c524d
+CT = 5f448ff52fc5715f7829d4a1842579d0dcf8627851c1e47a0592d360fc6a46aa18c4ce5d74fa4532
+
+Count = 278
+Adata = 1813bf176a1127f4d508d7663ae750f9c4bcb84a6e26811ac60d46
+Payload = 9e2fa20bf76768a5a1467d90a048bb503a2c33bbbaa71653
+CT = 5c88767ad2cbb1bdd890072a394633bcd2607b943a2aa0648b772cef893495cf0a94e8ebf06e920b
+
+Count = 279
+Adata = cc6e9cc2699d3ba0e624e715599480d6b7dbc6eeea0d12a9236444
+Payload = 6681b1cbeceea57a828324831407280b00f4917ed52a10df
+CT = a42665bac9427c62fb555e398d09a0e7e8b8d95155a7a6e8b1851d571a1ef8aed565b784dcaaac4e
+
+[Alen = 28]
+
+Key = 7d870d7e52d3053c65eefad47764cfeb
+Nonce = 37d888f4aa452d7bf217f5a529
+
+Count = 280
+Adata = 9610949f6d23d5b1f3989b2f4e524fab4f297a5bec8ddad4f16cb616
+Payload = 109317556c21c969eda65a94176d7a11462c9ae18a865b6d
+CT = 4e6b967b1571c6d7b9e118b112b7ac949a4a175650316a242dd579cb0d201d22c86bbc7fbe47bd0d
+
+Count = 281
+Adata = 96118dbfe53434d8aed88769a535eb0c8b5849dca1c81c34626ac9b9
+Payload = 3e6c914a196e175079315b1c92b2b8a844deb472e249e3d3
+CT = 60941064603e18ee2d76193997686e2d98b839c538fed29af0dd7aef4a609f3587652173446ebd82
+
+Count = 282
+Adata = 21fc96f73975298207f818909088295d6d6861677130ca258c2174f6
+Payload = e0014147d5771b4380dc0192d45f36f7d60776d1ba47374d
+CT = bef9c069ac2714fdd49b43b7d185e0720a61fb6660f0060463e4405d45caf4836467edbf35089d87
+
+Count = 283
+Adata = 72a5151abcb55933ff7c9314f3235eba2a400121454144c2670e8359
+Payload = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a
+CT = 51e4ecd194f980c441d8dee31dfa69374576555d7eac44537441c813e90fac775eddb7290df059d9
+
+Count = 284
+Adata = dbbf192914b1ad73666e9f5e9c22c08ca398f7524af62b1046a863bd
+Payload = c1ddd14e380cc91324cf2a381df1da1ccffd90ae436a373a
+CT = 9f255060415cc6ad7088681d182b0c99139b1d1999dd067334d9316f1f1c3142c1c9b26e5c220a32
+
+Count = 285
+Adata = 28e4b88fbf04e9897057ff5bfde7eb04fa480256817a50fa281030b4
+Payload = d4dae9c4cae92afb80f9a5c99383ff16e23a2ec942eed4d2
+CT = 8a2268eab3b92545d4bee7ec965929933e5ca37e9859e59bc0b188e33bfab29b237d6c6920ce3418
+
+Count = 286
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d7
+Payload = 8a188d40a6e6fbb06a9f06304349a7a808b092cc2fc10b9e
+CT = d4e00c6edfb6f40e3ed844154693712dd4d61f7bf5763ad7fdde04d21b876468bd9184101b5f32d0
+
+Count = 287
+Adata = 34ad69f192ae4dcab771aeeacf01bbd32609bcbbea8ff9df31ded719
+Payload = 590c1aac30ab166b1caff748452fc146765c372e226ffc26
+CT = 07f49b8249fb19d548e8b56d40f517c3aa3aba99f8d8cd6f068c65e9d0e5f1b81c86393900e64c19
+
+Count = 288
+Adata = f5e50ce1f99ed5e9f2baa54b96ae7039234b1131e734ec190695d28d
+Payload = 16d0522b2e691e42bd80ce95e00c8a7a1fc738169e904bdb
+CT = 4828d305573911fce9c78cb0e5d65cffc3a1b5a144277a9206ab3b72c56c8df4a12dba89a2f21276
+
+Count = 289
+Adata = 9b1e7e52ea1a12444d884866e11dcf367b70b816460936fdaebba36d
+Payload = 0bddf342121b82f906368b0d7b04df1c682ecd4c2b2b43df
+CT = 5525726c6b4b8d475271c9287ede0999b44840fbf19c72960170ca7b16d23537eeb3034105334699
+
+[Alen = 29]
+
+Key = 8fcac40527c0e7ca8eaff265ca12c053
+Nonce = ae9f012fd9af60a400e20b1690
+
+Count = 290
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154
+Payload = 78d1e96af8cebdcc7e7e2a4ddcfa34f6cf9a24fb85672ad7
+CT = 9adb9a95a9379ad795d8d3ffd4e37a045160d6d727f974a6cb3b5151f327e65447e52c7525562c91
+
+Count = 291
+Adata = e7c78ef4c4b959ee00cb1a09d71221a43892ef8ad705edd27ed85d03a3
+Payload = bc59f18c8473941abc681a92741ab5ee13679829f542b8f4
+CT = 5e538273d58ab30157cee3207c03fb1c8d9d6a0557dce68534e5b08e27d8f5eeef0f064ff620652a
+
+Count = 292
+Adata = f1bce6f2a4bdd3a07ebf5f8d47f931d27e7e63389d70e1059f701216be
+Payload = 5575d950312c14c89ac609dfb0b2fd1af732bb6aae5e8651
+CT = b77faaaf60d533d37160f06db8abb3e869c849460cc0d82044c0a96baae318f4714f0206812516b5
+
+Count = 293
+Adata = 3da3bb091016e54477dae88af1c84c1a51b59c1bb49a05deb6f32064e6
+Payload = df5947d8c6094ccc25816639ec42214b28731bfd7b8312dc
+CT = 3d53342797f06bd7ce279f8be45b6fb9b689e9d1d91d4cad4e7bdce2dc6aae24178aab6984f31028
+
+Count = 294
+Adata = c4cd183071c37a8157c6930a7d4d530cf4b7eb021682327810bd48209e
+Payload = 2fbb6dc235761875411ef59ae06110df8f15f66b721b0fd6
+CT = cdb11e3d648f3f6eaab80c28e8785e2d11ef0447d08551a7f18ece8260bd56ecdee768022d0dd8d1
+
+Count = 295
+Adata = 0e0fece7b6b659b642668e8ba3dca330523e70279155f485f3f6f8041e
+Payload = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e
+CT = 2f1eeee88a5ecb4bebad75e198c85a9be155443c87ae413f6f0fb3b7440b84ddc3cc53819c2e93be
+
+Count = 296
+Adata = a35c6f70f637a9a5e6f215c694fdf65b6fd85f794ed3eaa1bc19abe592
+Payload = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa00
+CT = e109e352e48bd5a6c1ccbde6f5716d9e4f2e977be1b6f47129ca778c51f9320f121dd803ece8d5da
+
+Count = 297
+Adata = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f904398afbec
+Payload = f2d9cf953c8d3a051d9b3eae4307a3cb4fffaa2435b49586
+CT = 10d3bc6a6d741d1ef63dc71c4b1eed39d1055808972acbf79c223a5ad65120bfca4a5992e5ebc6fc
+
+Count = 298
+Adata = c023763a285ea934bc5bc7ddfc2aefe2b3f9eafe7b87c61383dcc07990
+Payload = 4b92e8d2ffaa4af8f3e0ac037a900bd18e195f490a3d71e1
+CT = a9989b2dae536de3184655b17289452310e3ad65a8a32f905c3bc4f618ffb3a159f4e2d0622cea6e
+
+Count = 299
+Adata = 0a39ec0163c7aeb1b4fbe7cb4fa5b0592fade70f430e23730a23ed4160
+Payload = 7c0e6a0d35f8ac854c7245ebc73693731bbbc3e6fab64446
+CT = 9e0419f264018b9ea7d4bc59cf2fdd81854131ca58281a376f099dce6e18435fba4d26c1e93bda0c
+
+[Alen = 30]
+
+Key = ddf9f150cc3f1c15e8e773663c5b061c
+Nonce = 98c5036b7d54da9a1177105600
+
+Count = 300
+Adata = 20c5ab290e6d97f53c74121951f39ba865b3acc465fa3f0fb8a591622277
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d00d29396ffa9e691290d746527777bf96a851f306d4da0b1816df1e0e82bb7bc8105930ad6a2232
+
+Count = 301
+Adata = 0e205a4dc5d5ead0d9ff7f182dc140fc49511c01b0fdbc7e6d6cb5fdf027
+Payload = 88b2572fbe7cf2b46df04db476ffedb41778ae2eb3c3aae4
+CT = 2167fa0c69b415af3383c4e8ae35d41e00b8232e3dbc3cd2df823c8ccd466807f2bd1c4032f0cfeb
+
+Count = 302
+Adata = 48043560d60381e83c11d4bc9d997d3ee2add6b0524b779c62dfaa73ce0a
+Payload = d44bf28b010e076b45db1b053af03db718b60748da51db1f
+CT = 7d9e5fa8d6c6e0701ba89259e23a041d0f768a48542e4d2931f5be8c9965345c760c72cc1b7908d1
+
+Count = 303
+Adata = f0729a8a2fd073699ab87b521cbe0420b43529556a505f5f87874d1a053c
+Payload = eab8cffb512eabe267cd64353552513defe97c2d10f35503
+CT = 436d62d886e64cf939beed69ed986897f829f12d9e8cc335381d94a828a95872ebdfda8a4c6a196b
+
+Count = 304
+Adata = fc2cd69bb61223f713e33a5071d09bf2783640c307c22d836dd94952dd37
+Payload = 001056926546c261fbbdf92b94498e038c2bcfd0b6345497
+CT = a9c5fbb1b28e257aa5ce70774c83b7a99beb42d0384bc2a163931808533f4f70d7a78242ced110eb
+
+Count = 305
+Adata = 8f653c5c003c807d16d17f833eebb97c9c2f0e5aae3780a52ce53a6c33f7
+Payload = 29ffaef9415fd300127ffd26ef324083a9d90e0f60e2ab4f
+CT = 802a03da9697341b4c0c747a37f87929be19830fee9d3d79f34553198f8e40fde6473f9cf04f1de6
+
+Count = 306
+Adata = 8d05e7d3077151c6d9378cb08e049e4d7c28a908f7f7c079c46ff92cd01b
+Payload = 9874dc5ca1b541f7b21c7b3860fa6b0c3ab1b712ab0fca98
+CT = 31a1717f767da6ecec6ff264b83052a62d713a1225705cae0fac20e8d45d2b0771d140b5e4a47c87
+
+Count = 307
+Adata = d4feb3ea76ac2945651f557406f3f38a2d7e9232ed55ff4eaf1201dd8255
+Payload = 1e01c7128c821fb9c971a27fc7c6f9bb902fa735de583b8a
+CT = b7d46a315b4af8a297022b231f0cc01187ef2a355027adbcd3cacfe4281e52d79e60eeb38319bc3a
+
+Count = 308
+Adata = 7cbb4ae995a3367a256cafd11cd6c6cab5bf3252fa97f27a8a1434ca9a27
+Payload = 51cd306fac7d20e3c7043eae3a6dfec046c5c24a666a0723
+CT = f8189d4c7bb5c7f89977b7f2e2a7c76a51054f4ae81591158f0d7646a799b14288bb2f354b5d8847
+
+Count = 309
+Adata = bd40b06a4beded2be3d176266b10772c7fa2949f0a9b20d613af90c2daf5
+Payload = fc5b26befc633a3e8ace011aa7a42bd0258a9f3dc14fc1c8
+CT = 558e8b9d2babdd25d4bd88467f6e127a324a123d4f3057fefd7f95e1d331e700aa9ef83f09b689fd
+
+[Alen = 31]
+
+Key = b1dc81d116d94f5eced526b37c004b95
+Nonce = 97c8f69fb91b17299461fd8d63
+
+Count = 310
+Adata = f8b08aa83bed09ca342249b2cf9e2b45a89dcfb8711a120395e455921af481
+Payload = 54390715b6e7c7bd51a234db059a51ba030cf22ee00b7277
+CT = cb629994c3418a662a8cde1b5f4d99aa7df66e24c53dc6df11297930fd44c63675b7cca70671ef4d
+
+Count = 311
+Adata = 0351c969dd38eeaa4b9b0000e346eeb1a2cd462033c59d9e6e3331822045cd
+Payload = 65b5e856a8cf35dffd42c5ba105cba4c434aa1c2a0390352
+CT = faee76d7dd697804866c2f7a4a8b725c3db03dc8850fb7fa7e77f5566ca2fd9293835bceb461dbaa
+
+Count = 312
+Adata = 5db8b6bc16740680f78fba917733a6899cdba5e4c10a8058963d1265681eaa
+Payload = 9a7685e3daac43ccf22cad0df900ba8acddc5d420846118d
+CT = 052d1b62af0a0e17890247cda3d7729ab326c1482d70a525ec2cf9f5d35521c1c000685e49d2ed42
+
+Count = 313
+Adata = e7d6024611210da0cfb90a9955195aa0a0539280a3a7c792a1540930daae2d
+Payload = c18d9e7971e2ae5fc128777086338fbe194443324e2d2cd1
+CT = 5ed600f80444e384ba069db0dce447ae67bedf386b1b987966f33dfb44ae413283b238616c6b99fb
+
+Count = 314
+Adata = 77a878c9c76f3e6a4ddd330d1d8828949d08e0fedffe0d8e2e557b29e7c78c
+Payload = fcf8982f7342f1b953658453cd5ea413700eff00f1ee7d6f
+CT = 63a306ae06e4bc62284b6e9397896c030ef4630ad4d8c9c731df6fc6b4cf0b6332936ed7cfe9455e
+
+Count = 315
+Adata = aa540554ee80dbffa475f702d862d6b60e0a4090792420a26d02926517723e
+Payload = 0d5690d2a7083ad6daf22b308314b8f5363aca77ca72835e
+CT = 920d0e53d2ae770da1dcc1f0d9c370e548c0567def4437f67c8162a815f2809601ad02595e2e0ff4
+
+Count = 316
+Adata = fae86f95dd06fb7fbae63a646615555aec8153dc328bdf79da5d4cc9677ed6
+Payload = f6e313cc35e8f8812b10a44f8ad00b6893f8084d942effe0
+CT = 69b88d4d404eb55a503e4e8fd007c378ed029447b1184b487fcaa11bdeab86f60f9cd0a2b45cee1a
+
+Count = 317
+Adata = fd525302d2fb246a47cf4e3a27808bda89d8488cf450f1a1c7df6eedd810ee
+Payload = 91e961ea2eb750577c5137c609602dbfcc4c07955ba429ec
+CT = 0eb2ff6b5b111d8c077fdd0653b7e5afb2b69b9f7e929d440a86a810881bd969744ad80f579400f1
+
+Count = 318
+Adata = 767b1bdf9793a512d3a84e99ef77b43011a3bcb8de4cd375dfe47a79293e01
+Payload = 98438c4411bead6f30c89ead762a12bf39391d3652b78b7a
+CT = 071812c56418e0b44be6746d2cfddaaf47c3813c77813fd2250ca00d3231819ecdf501ad39c864f3
+
+Count = 319
+Adata = aac7014f606df6feec415a75e29015891007f07518c955875fbf5619262ff2
+Payload = 540cb00c0eface3d1b2d632d80a642f53c78ff672a1ff6ff
+CT = cb572e8d7b5c83e6600389edda718ae54282636d0f2942571224d1d0294d46981d7dc39114a693d2
+
+[Alen = 32]
+
+Key = 5a33980e71e7d67fd6cf171454dc96e5
+Nonce = 33ae68ebb8010c6b3da6b9cb29
+
+Count = 320
+Adata = eca622a37570df619e10ebb18bebadb2f2b49c4d2b2ff715873bb672e30fc0ff
+Payload = a34dfa24847c365291ce1b54bcf8d9a75d861e5133cc3a74
+CT = 7a60fa7ee8859e283cce378fb6b95522ab8b70efcdb0265f7c4b4fa597666b86dd1353e400f28864
+
+Count = 321
+Adata = 55a62968c222a8501d1ae56a9a815667f8a9554607b7c56e6753f8fa92a4d054
+Payload = 764dbefb42644d18d23e5e4568685d14dbacfa418d36c4ef
+CT = af60bea12e9de5627f3e729e6229d1912da194ff734ad8c4423862a715dda2f63a4197f894515803
+
+Count = 322
+Adata = f8436e35b7a1c810ac6aabe8e2d48a3678d19e1e96337dada514ee5fc075fce4
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 17e3f2110e9ec22c8ebef633023a178021ef45ff5f31cefec200f190bd700f6108f9959f6d12f0f0
+
+Count = 323
+Adata = 548e2152f3a15b8fb81dc01062d99f7b4fc8f074e5cbdc1030c97f8ccc02ec3f
+Payload = 53c164a4990c6e0637267ff2556c1542712fc584f6ff7458
+CT = 8aec64fef5f5c67c9a2653295f2d99c78722ab3a088368733a66ebc4e0777a6fc140a51e04a10f86
+
+Count = 324
+Adata = d100f1d08ef1e3eda4aef22cd970c2b785c4ff9b523c401b4064324aecf7f2d9
+Payload = 15681d2121ac56a63b9d0a38b9c4eccf84fdb746d32c14b4
+CT = cc451d7b4d55fedc969d26e3b385604a72f0d9f82d50089fb810cdc08db0a9966dffeb43ba26446e
+
+Count = 325
+Adata = eece934a807c9f21487cd810f15fd55d7bb4421882333ff2c43b0353de7fc5a6
+Payload = 412a8ef924ca156de860f147575e5731825f0a3759688928
+CT = 98078ea34833bd174560dd9c5d1fdbb474526489a7149503cfc5b397578f8d02a0b936ffac29b99a
+
+Count = 326
+Adata = 86311ff444d9be90459b6ee3652e1705ed0b5cdac3d27293ddea3378fb686ee5
+Payload = 54ba8a020d0876fa369dc32e8627f565ba3dda862ea0bcfe
+CT = 8d978a5861f1de809b9deff58c6679e04c30b438d0dca0d52c3fcd6d618c260d51724126f257534a
+
+Count = 327
+Adata = ab6efbc44a8906d5c067eaed71af467e130aaf170827a58beb03c55069674125
+Payload = 7a15506fd1dae444d77b2a3ae7b57a8d5b4f10e25a9f78e2
+CT = a3385035bd234c3e7a7b06e1edf4f608ad427e5ca4e364c9bf8b2821920640b992b00cd1c9618025
+
+Count = 328
+Adata = ddb640923d083725587aced81ae1d7409983d1f1e3ccc8dcf94376dc1bbcae8b
+Payload = b18a61a89cd698f32e059b7a2a9f62a46be2c248790a9915
+CT = 68a761f2f02f30898305b7a120deee219defacf68776853e4cd52d41a968284af8907ccbb4588cc0
+
+Count = 329
+Adata = d95ec4a6f594be1ba39fa1aa933dc0a5dafff5ce44509577ebb3a3e8084c4401
+Payload = 16ee3bc9ec8b4448e292b8973618e02a99da1c348539d5c7
+CT = cfc33b938072ec324f92944c3c596caf6fd7728a7b45c9ec47449a5cb4943ff2846c589b7c98ef49
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp
new file mode 100644
index 0000000000..1a7a5875fe
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT192.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886
+Nonce = 15b369889699b6de1fa3ee73e5
+
+Count = 0
+Adata = 00
+Payload = 39f08a2af1d8da6212550639b91fb2573e39a8eb5d801de8
+CT = 6342b8700edec97a960eb16e7cb1eb4412fb4e263ddd2206b090155d34a76c8324e5550c3ef426ed
+
+Count = 1
+Adata = 00
+Payload = 296fbda0017351491c2187273fbde2c3a427170e430a703c
+CT = 73dd8ffafe754251987a3070fa13bbd088e5f1c323574fd2167ee33e75d05023a7d63c770cfef2ea
+
+Count = 2
+Adata = 00
+Payload = eb61c284fe009921039ef6a9ce50e702823e44b35357923f
+CT = b1d3f0de01068a3987c541fe0bfebe11aefca27e330aadd170647420f79c0d91cbbd69b806fe96a5
+
+Count = 3
+Adata = 00
+Payload = ffeccc6460d23fdcc387c697e75dbb959b78013a8282eaa4
+CT = a55efe3e9fd42cc447dc71c022f3e286b7bae7f7e2dfd54a8a3ef2324754539ac774872282534386
+
+Count = 4
+Adata = 00
+Payload = 90958d7f458d98c48cbb464c74bf495a49846dd468c514e9
+CT = ca27bf25ba8b8bdc08e0f11bb111104965468b1908982b07e292cd0e32535a848e327bc53cdae94c
+
+Count = 5
+Adata = 00
+Payload = a4fad5205d38206e25097075687ca86032b95b3fe7e82a07
+CT = fe48e77aa23e3376a152c722add2f1731e7bbdf287b515e9bb21701af36936be5f62d02b84df87c3
+
+Count = 6
+Adata = 00
+Payload = b37114c65372b052cbeecf83d05a5da44f7b5bbff7d986b5
+CT = e9c3269cac74a34a4fb578d415f404b763b9bd729784b95b7da7f975367be24341e4af51b8bb156a
+
+Count = 7
+Adata = 00
+Payload = 9c0f0426f171ff18b2a4392f61fb4ee4a44c476fe03dc930
+CT = c6bd367c0e77ec0036ff8e78a45517f7888ea1a28060f6de360c6d50a96f316eda0b216cbb6380ef
+
+Count = 8
+Adata = 00
+Payload = 7b6e0a480a40585545b0e940e8d97c9ec987bd3c0e9c16a8
+CT = 21dc3812f5464b4dc1eb5e172d77258de5455bf16ec1294634cd1bd98e8137b578a174e39efe09b8
+
+Count = 9
+Adata = 00
+Payload = 34dac6dbc28be62332a6935efc122e37b26ee100eb4033f8
+CT = 6e68f4813d8df53bb6fd240939bc77249eac07cd8b1d0c16909a895a3b08b63d7a2a1e75d25e7861
+
+[Alen = 1]
+
+Key = 9748798c0f3cc766795c8ce0e4c979c1930dfe7faefea84a
+Nonce = cdf4ba655acfe8e2134fa0542f
+
+Count = 10
+Adata = 67
+Payload = 100fa71462277d76ca81f2cfdb3d39d3894b0ca28074a0f0
+CT = 36e2415b4f888a6072f260d7e786d803be16f8b9cbee112d7ff74e3b05b7d7c13284573bd3e7e481
+
+Count = 11
+Adata = 17
+Payload = 0217eb6778691f8dfe2d0e5241f05fcbcf97b9171f4de3f0
+CT = 24fa0d2855c6e89b465e9c4a7d4bbe1bf8ca4d0c54d7522d3ee7ce845f85dfc770d96dee9ca54ccd
+
+Count = 12
+Adata = dc
+Payload = a78b7bc6c1a7250c5fc236f2a8343725a9a7bd3ca81b53e4
+CT = 81669d89ec08d21ae7b1a4ea948fd6f59efa4927e381e239dc14ddd8ae0aa5d810040a8d1d4da1e9
+
+Count = 13
+Adata = 0c
+Payload = 390c808d998582793bb10ee60568eb8d975c51d68b4e4da9
+CT = 1fe166c2b42a756f83c29cfe39d30a5da001a5cdc0d4fc746b40dec7e647720f1f5e8474bf570c2f
+
+Count = 14
+Adata = 3e
+Payload = bcd9747fb54184b61b2e9e049caa75e22006e250f3722c0e
+CT = 9a34923098ee73a0a35d0c1ca0119432175b164bb8e89dd3c10c4aac45d90119cce490cc8681a49f
+
+Count = 15
+Adata = 7e
+Payload = d0342e3cd2c1142b642da7297ee3b9978cec405e6810f12f
+CT = f6d9c873ff6ee33ddc5e353142585847bbb1b445238a40f2f9a95091d2cab7d3d9fa3e10d3e67ac9
+
+Count = 16
+Adata = e3
+Payload = 7fab91d1aa072947d22f0dc322355a022fe7f0747f4a184b
+CT = 5946779e87a8de516a5c9fdb1e8ebbd218ba046f34d0a996180f7818c373e89f7ff3003f53260060
+
+Count = 17
+Adata = 3e
+Payload = e487143dc4d98dcc6a2dfe6ee0f85d565d1f46bb0fafe62a
+CT = c26af272e9767adad25e6c76dc43bc866a42b2a0443557f71905f581585e59e3c8c038b5bf966559
+
+Count = 18
+Adata = 3b
+Payload = 976b489244ed6789a34251500057d1d4a3229367a42b9066
+CT = b186aedd6942909f1b31c3483cec3004947f677cefb121bbea56569c34f8d9eea23e85fec18cfc51
+
+Count = 19
+Adata = a5
+Payload = 71efa75961dfd60ad533082a8cfe111214eb02573adc4591
+CT = 570241164c70211c6d409a32b045f0c223b6f64c7146f44c212da23548f2ca4e9a8a07962be6422c
+
+[Alen = 2]
+
+Key = 393dcac5a28d77297946d7ab471ae03bd303ba3499e2ce26
+Nonce = fe7329f343f6e726a90b11ae37
+
+Count = 20
+Adata = 1c8b
+Payload = 262f4ac988812500cb437f52f0c182148e85a0bec67a2736
+CT = e6d43f822ad168aa9c2e29c07f4592d7bbeb0203f418f3020ecdbc200be353112faf20e2be711908
+
+Count = 21
+Adata = 9db5
+Payload = d5982c462ad40458660cd7b120ce07fce9afe812caedcebd
+CT = 1563590d888449f231618123af4a173fdcc14aaff88f1a89015e5cd97b7dd3d981321ae0b2d99e1a
+
+Count = 22
+Adata = 69cf
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = da6e85202048347568befac0731db702e687d5ef51d50402bf3e75863c7acd2699caba3cc301f4b2
+
+Count = 23
+Adata = 6c6e
+Payload = 373c157e59b934a1afb57d4c5dd9ca7fb736b206a6210bef
+CT = f7c76035fbe9790bf8d82bded25ddabc825810bb9443dfdb5d6a8f7a9f52a8038aa9dc1bdc9ed876
+
+Count = 24
+Adata = dafa
+Payload = 26e10a2ed8cc883a6552aee162c5542ff8bb8e758a1975f8
+CT = e61a7f657a9cc590323ff873ed4144eccdd52cc8b87ba1cc8a15603f10cbfdb041f8b2b12cc8f037
+
+Count = 25
+Adata = c8b1
+Payload = dd235b05c15479dfe0326ba206ac784eca50038bbeb35d32
+CT = 1dd82e4e63043475b75f3d308928688dff3ea1368cd189061278bf62ba6a4819513d49fdcdb45480
+
+Count = 26
+Adata = af48
+Payload = a0818342a5cae4a90ef281d3d1289d83f273f418a545fcbf
+CT = 607af609079aa903599fd7415eac8d40c71d56a59727288b8b4d00309b50f9ea72f8105c94475b52
+
+Count = 27
+Adata = b1cd
+Payload = 33c0d06b6583bb4d15b4a07364c4be70ac6e72795c3dae0f
+CT = f33ba520c7d3f6e742d9f6e1eb40aeb39900d0c46e5f7a3b220ba58e97936612c4183ba86705b2f9
+
+Count = 28
+Adata = 649a
+Payload = 3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863bde9
+CT = fb5a67c9744faec46fa7e127d646ed5f8be555566a0169dd87d602dc85bb260fb3df1221e2fbd10c
+
+Count = 29
+Adata = 593c
+Payload = a97faefcae36732fcfe47736c2334ea7d411bf7638b0c019
+CT = 6984dbb70c663e85988921a44db75e64e17f1dcb0ad2142deb3835b7eecad6dac9785ad1d370ede4
+
+[Alen = 3]
+
+Key = a74abc4347e4be0acb0a73bb8f7d25c35bae13b77f80233a
+Nonce = 6a850e94940da8781159ba97ef
+
+Count = 30
+Adata = a4490e
+Payload = 6372824bf416cd072a7ad0ae5f9f596c6127520c1b688ab4
+CT = b14a07bdc119d87611342c4c6935c5786ff1f9ae2eb49e6191c88a3cb4fbafcb8a4a157d587d7e39
+
+Count = 31
+Adata = 5cad2e
+Payload = 295f4f3417a77fcf0bbda17b0fd629ad57a6086573c87eb1
+CT = fb67cac222a86abe30f35d99397cb5b95970a3c746146a64235c34d1390bba5b008c3fb29c2df958
+
+Count = 32
+Adata = ebdf4c
+Payload = 86f354a505de941d34cd98e3af3706d56a938ab9a2797182
+CT = 54cbd15330d1816c0f836401999d9ac16445211b97a565575a733bba0a6992d0664dc77d2b5d194c
+
+Count = 33
+Adata = 7c0d70
+Payload = 88c3bfb546abe2f6bfc92a7c56c627e24ab92a8a87a6b43c
+CT = 5afb3a4373a4f7878487d69e606cbbf6446f8128b27aa0e90902a31b15eed99c2dc4ed1bf11cad96
+
+Count = 34
+Adata = 8fa501
+Payload = 75d4216bad77943bfe82be216157843b0da0fd16eeee8471
+CT = a7eca49d9878814ac5cc42c357fd182f037656b4db3290a42f25595ae00103d4eb20288158132e7d
+
+Count = 35
+Adata = b7aca7
+Payload = bf1401e8dcf6f681ed6dd74c7e23b7e54b384608b0e5ec52
+CT = 6d2c841ee9f9e3f0d6232bae48892bf145eeedaa8539f88760e67693b509ea4795b7da32c5c5d17f
+
+Count = 36
+Adata = 1f283f
+Payload = 7e623e7ef7d0a678b5d22a8402d89220f4f1bf759e3084dd
+CT = ac5abb88c2dfb3098e9cd66634720e34fa2714d7abec900880ef8ea380a1a0a38b2c20288e637a9f
+
+Count = 37
+Adata = e93f31
+Payload = 14f80e7a6298d85d31fb80376a394a8f88b0ae47f00450c7
+CT = c6c08b8c5797cd2c0ab57cd55c93d69b866605e5c5d84412d553aafe8536385d34c412c14d3a1563
+
+Count = 38
+Adata = 27e9a5
+Payload = 3330df12249639961f562a74b34f60b0a8bc7c783f6572fd
+CT = e1085ae411992ce72418d69685e5fca4a66ad7da0ab96628f594d366c8fc826ce58309e9053c27f7
+
+Count = 39
+Adata = 72d566
+Payload = 1a1860ac8c11c5d262f8141738cae8ff91ca05906dc98bb4
+CT = c820e55ab91ed0a359b6e8f50e6074eb9f1cae3258159f61cdd6ac6c42cd3d11e0344a9c1001e253
+
+[Alen = 4]
+
+Key = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb0
+Nonce = ba356d392c3f700f4f2706a4ca
+
+Count = 40
+Adata = 8ffc0e3d
+Payload = e8c1a89228d8212f75c136bab7923a89f9fea18e781cb836
+CT = 66b5d782323925e1bd0a8413a9a5a881356453d5df2cbeb199b2e1e803550dcdde55fd66ecb45edd
+
+Count = 41
+Adata = 2b4f9cfc
+Payload = a12c6324e022affd61b7e0d8cccbeb23e2e6c65355c1d586
+CT = 2f581c34fac3ab33a97c5271d2fc792b2e7c3408f2f1d3019e8fbc507244ba234a0581dc69962a66
+
+Count = 42
+Adata = b4de3039
+Payload = 7cccb26f1dd227bc77458b99fd9e00f8e801adaece7bfcd1
+CT = f2b8cd7f07332372bf8e3930e3a992f0249b5ff5694bfa5628a2857099af20a4ae08e687bdb02c75
+
+Count = 43
+Adata = bc59f18c
+Payload = 692b53c1355475c71ceff0b0952a8b3541b2938270247d44
+CT = e75f2cd12fb57109d42442198b1d193d8d2861d9d7147bc3e33a6416e387d9e571a1954471ec9cc7
+
+Count = 44
+Adata = 4fd9fd39
+Payload = 7e3e755e25bbe78d4a7770f9356ab9f4ff1bbfdba46383f5
+CT = f04a0a4e3f5ae34382bcc2502b5d2bfc33814d8003538572180f9735f994c8335e593f30b331a920
+
+Count = 45
+Adata = 296cd04c
+Payload = 997b712cd9295dc43cc19b40679f218c27af3e8c638d2e5d
+CT = 170f0e3cc3c8590af40a29e979a8b384eb35ccd7c4bd28da91990fa537d2657d01f66872ba9af22f
+
+Count = 46
+Adata = 88037d3e
+Payload = 577981ccb6c893dfe6405075fcb41507de7f9bfda860791f
+CT = d90dfedcac2997112e8be2dce283870f12e569a60f507f984915cb93e84028c7aedce1a2dadbb6bb
+
+Count = 47
+Adata = fc4bb852
+Payload = 37ba9f57ec230675ce060ba3d388095adf15907aa0b0673d
+CT = b9cee047f6c202bb06cdb90acdbf9b52138f6221078061ba25baa6385af8d7b807a2d2ab19aa4999
+
+Count = 48
+Adata = f40ec14f
+Payload = 401e0cdc132a9e4a9b5ceeed3c181f67e5203ea69508deff
+CT = ce6a73cc09cb9a8453975c44222f8d6f29baccfd3238d8786adcdb44870e1105b7318d8bad0af957
+
+Count = 49
+Adata = 90e2c63b
+Payload = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+CT = 8c40a5f5a79be2a2af34beb3212d8b12c1e13ceff68c2dfa8b079fb71d45bd985bffd343c3362653
+
+[Alen = 5]
+
+Key = 16d345606a315ad2406abbcb43cd8cabe948107ba6d17a72
+Nonce = d4ef3e9e04f1b7f20ffc5a022e
+
+Count = 50
+Adata = a468f08d07
+Payload = d3bef460223c81e4579c9d1d463ac5e0881685de1420a411
+CT = abb85db49a9b1c8724ecbc734cc8373bd20083cfa4007b1cfe4d3a3bb25f89f692884be230c6035c
+
+Count = 51
+Adata = 4497649a54
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326461ee1
+CT = f9ab96ecd34a5695258f723269aaffc4ddf5c1329666c1ecd05ae56511a230627e02d066c52a919e
+
+Count = 52
+Adata = c30ddd994e
+Payload = 84b88264afec06b370dfcebf5e1d3e2c1f005faf248b3215
+CT = fcbe2bb0174b9bd003afefd154efccf7451659be94abed188ef92fc17dca026f1ac1eaf78a05017c
+
+Count = 53
+Adata = 9573270f7e
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a040
+CT = e64a237d0d2d13c8b62849fcffa6e2dbee2911c810717f4d38eddff1e60e2d9ae74a936364b8df21
+
+Count = 54
+Adata = 40336790fc
+Payload = 260f67122dfbe03365bc9e35e9d4ac4b2eb150eddb30857d
+CT = 5e09cec6955c7d5016ccbf5be3265e9074a756fc6b105a70aa3d464ad89cae59b474d019a5a7605c
+
+Count = 55
+Adata = 0b310c8529
+Payload = 1d55e7352bd895c4ef77389a7225c664f72b38c8de778d57
+CT = 65534ee1937f08a79c0719f478d734bfad3d3ed96e57525abeab0c520e64939c6950c0fa406eafb1
+
+Count = 56
+Adata = 5756b2c681
+Payload = fbd315e1f5bd0f0e60ee6684c88f3543452c62ea0701d11d
+CT = 83d5bc354d1a926d139e47eac27dc7981f3a64fbb7210e10d22d339c382343bf39c239fd64c2a64f
+
+Count = 57
+Adata = 3b919e3665
+Payload = d68d6556c5a5b1f5a123389b3ce966d5837cb8fcf5accfff
+CT = ae8bcc827d022c96d25319f5361b940ed96abeed458c10f2fcd6b562a1b6aa10be92a81f99ed540c
+
+Count = 58
+Adata = 58749b643f
+Payload = 062cb6962fa5b3a6239b95f3a51b478a1f32b081dc538a80
+CT = 7e2a1f4297022ec550ebb49dafe9b5514524b6906c73558d4b853022237d94d253b375bf2150e699
+
+Count = 59
+Adata = a5d50c008b
+Payload = 08c62ff9bd7bcf189f530d5065f8764532d2692f69858483
+CT = 70c0862d05dc527bec232c3e6f0a849e68c46f3ed9a55b8ee7aee0d403b2cf6f8b993eebd6b93615
+
+[Alen = 6]
+
+Key = 1c476cfd7dd300d961fd3f24a6fe0e80742b00851676ca63
+Nonce = e300fc7a5b96806382c35af5b2
+
+Count = 60
+Adata = 28130f938c45
+Payload = 6f3938932b5c1280311e892280d8a822a828a0be7fdb1bcd
+CT = df48662fe134e75a85abc2cece2c3b6236c88a70fa792e9beadc9601adf9fbdf4e3e94b395b0a332
+
+Count = 61
+Adata = f600024a7bf9
+Payload = 0af7345e71f4e8886503395ade0b0296a5856e086638b06a
+CT = ba866ae2bb9c1d52d1b672b690ff91d63b6544c6e39a853c0692a40a6aba8d7c5addae21de90fea9
+
+Count = 62
+Adata = 4eef510d1f48
+Payload = 37f57772f056f45a5ce9f46d27be1858980c8935b9c839b7
+CT = 878429ce3a3e0180e85cbf81694a8b1806eca3fb3c6a0ce122f64becb581070411957e632e19bb8f
+
+Count = 63
+Adata = 4c9c76b6fad5
+Payload = 8bb10c82bcabb7fb2b169252ab443b01df217cf908b8c241
+CT = 3bc0523e76c342219fa3d9bee5b0a84141c156378d1af71708c59f83aa97d069b6d83d9387051f43
+
+Count = 64
+Adata = 5572ecfc7e53
+Payload = d1ccb4654a22b1afe32f3d3035fdccd87e9cbed83c679007
+CT = 61bdead9804a4475579a76dc7b095f98e07c9416b9c5a551f04686ee1d7b985d903f1de6cf78f8f4
+
+Count = 65
+Adata = bffdf9d20d74
+Payload = f990a8f6ba14065d48665db36eb470c49f38e2b6376a9bde
+CT = 49e1f64a707cf387fcd3165f2040e38401d8c878b2c8ae88f8118f1b9f39b51965ae9ef1bdb40111
+
+Count = 66
+Adata = 3f27e678c580
+Payload = f8c7d89639ab742a8bcfffe776e868d671e1fbdd55807a8a
+CT = 48b6862af3c381f03f7ab40b381cfb96ef01d113d0224fdca3236d02f33f49759f281315e449bfef
+
+Count = 67
+Adata = 1294cb9db5f5
+Payload = 8601cfd7d935e8a8487b9c39d55ca27096255f2eb9e009e3
+CT = 3670916b135d1d72fcced7d59ba8313008c575e03c423cb5e74770a07c242c3854ceb242dadc1976
+
+Count = 68
+Adata = cec271332b75
+Payload = 77c85b8022f58337b364142a2474fe5cfddb31cfca48af46
+CT = c7b9053ce89d76ed07d15fc66a806d1c633b1b014fea9a10d6c65f19175cfa49898655ccdddb864a
+
+Count = 69
+Adata = da06bd140502
+Payload = b0f2db802475fa70af02057373844f637a3244cda4b4f93d
+CT = 0083853cee1d0faa1bb74e9f3d70dc23e4d26e032116cc6b458822e49e69031431b3eea872a72eb7
+
+[Alen = 7]
+
+Key = 79d1e38a70df1cf239be168833dcd0570bc8f37b3aa26c37
+Nonce = 8229d6d7e9e21fdc789bff5dcf
+
+Count = 70
+Adata = 076887d2abe900
+Payload = 83c24f3a77b83b4ef45277ba90225f3ba1722312f52b1a07
+CT = 19d880f1d959a68f162de243d4a45747ace704613359b27218d1531a066de60a95d2924a6910e990
+
+Count = 71
+Adata = 7535bcc6fbd1a0
+Payload = 24f85ef683cc521387f484bc0b2ad9172f61884c09a9718c
+CT = bee2913d2d2dcfd2658b11454facd16b22f4af3fcfdbd9f96dbf58406020e6df7b312b6825127f9a
+
+Count = 72
+Adata = f4f96d7b4384a3
+Payload = 212bedfa06b5e1a2c3a2f31f6f791dd9df8ef26077821c0a
+CT = bb312231a8547c6321dd66e62bff15a5d21bd513b1f0b47f64dd755177efc87f8b1daf1fd88e51a6
+
+Count = 73
+Adata = 3b7e3d9c1a7fa2
+Payload = 8b9036914bb0f440c8dbcfde9b9547be5e5ef1f56492c75e
+CT = 118af95ae55169812aa45a27df134fc253cbd686a2e06f2b0be31cab31f1a20805d5c07dc516d707
+
+Count = 74
+Adata = a8c35fae8912d6
+Payload = 50f3f3a91bf6fd9573d5ef54b9bb5805205b2f9865d81fd7
+CT = cae93c62b517605491aa7aadfd3d50792dce08eba3aab7a2399df9a45ad153c0dfb3fec3b9d6f7c5
+
+Count = 75
+Adata = db636541f2429d
+Payload = 6fbda8d435555e735443f1e6bc09e96065092efd89edd64a
+CT = f5a7671f9bb4c3b2b63c641ff88fe11c689c098e4f9f7e3fe20b7da94eac8c7ef8478671165e0d82
+
+Count = 76
+Adata = a8de55170c6dc0
+Payload = 640ef4c246a2c6e16ddc49072a5aeef70319149ffba071ef
+CT = fe143b09e8435b208fa3dcfe6edce68b0e8c33ec3dd2d99a4979c35bdbf9538666b6fa57f0f915d8
+
+Count = 77
+Adata = f8d64ce2aa66e6
+Payload = a14e3910766f31594a28ad2c3678c31d0c3aee88484ca6d6
+CT = 3b54f6dbd88eac98a85738d572fecb6101afc9fb8e3e0ea3752824a691da2e99374ae6c031d74ffb
+
+Count = 78
+Adata = b3c340afdc53a8
+Payload = 1b8e0a09e6364020b4cac704dc19bfa79455295604cf9c9a
+CT = 8194c5c248d7dde156b552fd989fb7db99c00e25c2bd34ef04159a68706faa2e8c3376b4dbeb423a
+
+Count = 79
+Adata = 73824034001519
+Payload = 52c84a0735eea6c5c230644075ebfc5db0c3128056e7a8f4
+CT = c8d285cc9b0f3b04204ff1b9316df421bd5635f390950081e5adc7564721ead2af75cb98e61148b4
+
+[Alen = 8]
+
+Key = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+Nonce = 3820db475c7cb04a0f74d8e449
+
+Count = 80
+Adata = f427c47e10c45bb3
+Payload = 54bc7e3c227df4e83252a5848fea12dfdb2d14b9e67c1629
+CT = 91e7baff2b42af63e26c87ce6991af22422c1f82906858b1721961de5c768f4d19bd3034f44f08d2
+
+Count = 81
+Adata = ca25504f3f5559aa
+Payload = ff4493fea916f49fbb3cae2838bc84e293531092cc0904ab
+CT = 3a1f573da029af146b028c62dec7391f0a521ba9ba1d4a3342968c638ecb8a2b358e8eaefd931efb
+
+Count = 82
+Adata = 8215753d9efc5132
+Payload = af16ab8558269a93d8e8c9e38f12a8768947d8b69be0e259
+CT = 6a4d6f465119c11808d6eba96969158b1046d38dedf4acc1f8ac11752fe51e354f3f8a68815539aa
+
+Count = 83
+Adata = 9e7cdbc6202e6492
+Payload = 744a167ae31a8ca20df82290766429de9ef0b7dfe199a78d
+CT = b111d2b9ea25d729ddc600da901f942307f1bce4978de915489de8e241dcab16bdcbf1a1ff4d8d10
+
+Count = 84
+Adata = b8d511d0ab86a07f
+Payload = eeb39de1fe21b5aba654da45fe1481decb22365fa4cbe49d
+CT = 2be85922f71eee20766af80f186f3c2352233d64d2dfaa053fab212a1b6dc7b953e2bc211be194ae
+
+Count = 85
+Adata = c74a5d4265f9f3d5
+Payload = e95c20e80153bae3fde3c3d82b6b33b35fc1959fa31a5d11
+CT = 2c07e42b086ce1682ddde192cd108e4ec6c09ea4d50e138973918ab70fe048d6c5b63a01725eddfb
+
+Count = 86
+Adata = fd849d3ada03181a
+Payload = 6d00606c72cea3deaea5b51ae09e61924355e167058ef42c
+CT = a85ba4af7bf1f8557e9b975006e5dc6fda54ea5c739abab487089bc20867f474c1127aa1320f0000
+
+Count = 87
+Adata = 56825a68681f498c
+Payload = c47705d897a6c7e7aed710b96e2d8532c23b82090e21b114
+CT = 012cc11b9e999c6c7ee932f3885638cf5b3a89327835ff8c34a23b0b6ac4d297dd7832a5e2102272
+
+Count = 88
+Adata = 72e4da839913a26e
+Payload = c822a1ee581cf85b0482c821473385bd3f28528e5e5760d9
+CT = 0d79652d5123a3d0d4bcea6ba1483840a62959b528432e41dd665766c7af21ff890bd40178f1c660
+
+Count = 89
+Adata = 138457571ee8dafd
+Payload = 3ffb82a83308da66e95ac63ae92931b09ffe0e42afbb4979
+CT = faa0466b3a3781ed3964e4700f528c4d06ff0579d9af07e16a6a58bb772c79481dc26861ffbd68c6
+
+[Alen = 9]
+
+Key = 39c03a0c8634047b1635348f284d3dc1e752ab40548eb337
+Nonce = 9e2ea8eb7f56087ee506925648
+
+Count = 90
+Adata = 28d157f09a71da80dd
+Payload = 0662e63c88e963d3e0cf2c4653515ae4474a2c78ab0394c0
+CT = 01dcd4dd3b8c1369518136ce45e8bb9df565b0ad231a887b02ada34addf0aa2f4744ed2e07995491
+
+Count = 91
+Adata = c17d311362c41d442b
+Payload = d6df8b60c697093987b3d89a3667b36504b6ddddf12b0900
+CT = d161b98175f2798336fdc21220de521cb6994108793215bb38a27466b8741bffce44ef04b23af321
+
+Count = 92
+Adata = 006669ef1a11b65b1d
+Payload = 49ad29ef5e82b08752ac5a50dd982e4bcb700005454ade6c
+CT = 4e131b0eede7c03de3e240d8cb21cf32795f9cd0cd53c2d77d11372fb0dab1c99b159e5fe9f91118
+
+Count = 93
+Adata = 8eafce9ba466fd53eb
+Payload = 385f9fb139dbf88561b7a500b0c7b835fe57e2698c6d9f76
+CT = 3fe1ad508abe883fd0f9bf88a67e594c4c787ebc047483cd09e4898a4046f6ec9f40e412915007e4
+
+Count = 94
+Adata = 796e55fbe7bed46d02
+Payload = 4ebb149b01cbacba32d11168ca61928ea149dcf2ee2c1001
+CT = 4905267ab2aedc00839f0be0dcd873f71366402766350cba5d40a9902481bfac7ff33d08fb4b3d31
+
+Count = 95
+Adata = 8f958d796be0566512
+Payload = 0d974e5621caa1d86eaaee689ccbca57843373fcf20db407
+CT = 0a297cb792afd162dfe4f4e08a722b2e361cef297a14a8bcd972d09a17172161eb68a30b593b1bd6
+
+Count = 96
+Adata = cc879ff2d583a7288c
+Payload = f8e0dac6a691dfb231411b5c5f70a0daff83cc637b0c7bb3
+CT = ff5ee82715f4af08800f01d449c941a34dac50b6f3156708119cc26a80c152c253fbc36cb886e0fc
+
+Count = 97
+Adata = 4765d696d19dec58bc
+Payload = 096a36396ccfa260f28fb0919157a5076b53506c51a2a4ef
+CT = 0ed404d8dfaad2da43c1aa1987ee447ed97cccb9d9bbb8549de06cc5c3bc4ad75076c774576843fb
+
+Count = 98
+Adata = a004f283afc3309c31
+Payload = 5b943269be41e2758a4ea6a3cc621b711a8ba6002783aa72
+CT = 5c2a00880d2492cf3b00bc2bdadbfa08a8a43ad5af9ab6c9135493b44f79a5774df6b2943b0bec67
+
+Count = 99
+Adata = cdd5d8aefe49a315ad
+Payload = 5f27867109e74862ce0dbc9ba73c420b93067bdede17ae51
+CT = 5899b490ba8238d87f43a613b185a3722129e70b560eb2ea7a5da4a29a9012d78b6de6f1b3e8c9ed
+
+[Alen = 10]
+
+Key = e2a92ffbb0b5eb68cb82687f12449fae5167d375131b0b10
+Nonce = 441ad5e1382e083a95224f395d
+
+Count = 100
+Adata = 2352648299b0413cb2ce
+Payload = 048c9ba4597c3bb595bfd5048e5e9a1296f30e5c0118b177
+CT = 25247a258e4ac0a988d8def60cc174a9d4578cd5346fb5150c96e8ab8774baa421f39c64a386c418
+
+Count = 101
+Adata = ce003c836a6f5f066053
+Payload = 02ea8e7e488c863584f828df13dfeb68433294d11d9ca9d7
+CT = 23426fff9fba7d29999f232d914005d30196165828ebadb5d453036cdc6bad0c5e770a6249a52e74
+
+Count = 102
+Adata = d11be73a104ccc6346d5
+Payload = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024
+CT = 4cfd9248f0ae6ccbcc072678175fa50e889b2fa48bfea4464627ad75bbfe17f3f5ddfd3dbc1045f3
+
+Count = 103
+Adata = 6a7b80b6738ff0a23ad5
+Payload = 97a813e75d95d25c2edb1c705c4ffe4d7c08c756761fbc0b
+CT = b600f2668aa3294033bc1782ded010f63eac45df4368b869af8943f74706cc3394a170fd49f7011a
+
+Count = 104
+Adata = a391acdb3a06dae4a671
+Payload = a78981ac244307451e4d3fd7f654b70cc4e6518aa47a3c18
+CT = 8621602df375fc59032a342574cb59b78642d303910d387af22597f63074ca3533bb5e107860481f
+
+Count = 105
+Adata = 0b9f28f2d3215785f569
+Payload = 5d649d79ff0e304e164a383c74f13d7ffab145d00cb0ec2c
+CT = 7ccc7cf82838cb520b2d33cef66ed3c4b815c75939c7e84e905b5609f593c6ea9281f66cd2e646dd
+
+Count = 106
+Adata = 7928b1091cbfb2eef0fe
+Payload = 83a273687dced7b94d569f81d75508595cde668f06406183
+CT = a20a92e9aaf82ca55031947355cae6e21e7ae406333765e1428195355618ea0cf87260ad20b6d7b9
+
+Count = 107
+Adata = 3b74afb81f54a93c79d5
+Payload = b4dc3c059cf7b47dd0bb7f165a63fc80b5c6b5f3ca7eeb73
+CT = 9574dd844bc14f61cddc74e4d8fc123bf762377aff09ef1155019659f41a5f0430695b4ada9d8b8d
+
+Count = 108
+Adata = a46ae4c71d4c9eb72fab
+Payload = 7e919581c5105d98717d0613e1ca869c6516506ea482d5c2
+CT = 5f3974001226a6846c1a0de16355682727b2d2e791f5d1a01514b252f33dc870c42260e48c4fa9fd
+
+Count = 109
+Adata = a1ace61711f0a09ac17d
+Payload = 3a4558b55214f21cbd2ae2eda5a2321cfc2f102e059b744a
+CT = 1bedb93485220900a04de91f273ddca7be8b92a730ec7028c263c667d7ed58907452c092905d0b31
+
+[Alen = 11]
+
+Key = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Nonce = 8e7d8a44244daa7df2b340993e
+
+Count = 110
+Adata = 521583c25eb4a3b2e46120
+Payload = 9f580cc6c62a05ce125c6bec109a48ca527ee26a64b14b68
+CT = ff0ff95bcb0bccd5e4aadd77ac6770f5013654eb3c6386fded2c87135861b43a99f258b6938f66e3
+
+Count = 111
+Adata = 31adb39e947f8883fa4b69
+Payload = f16bba081bddda83546eabc9a55c81a439720dd8562ce964
+CT = 913c4f9516fc1398a2981d5219a1b99b6a3abb590efe24f132b87476d66a1bd405f484ef9ac8ab7e
+
+Count = 112
+Adata = f05f39eb0a3d6460076aa8
+Payload = 6baf784f63cf45a1836fa8f3609fff7870ce8cbd1e91268c
+CT = 0bf88dd26eee8cba75991e68dc62c74723863a3c4643eb19a120b455b366cb104fd8b6dc2c80471e
+
+Count = 113
+Adata = 74c7a633ff73ff507009c5
+Payload = d8176a6de1c15a14c8b8b58725c179dc84c9308268d718d5
+CT = b8409ff0ece0930f3e4e031c993c41e3d78186033005d5400c8ca09f4bf06b1c27e75abf15112e49
+
+Count = 114
+Adata = ab322a88cf44b9ca774415
+Payload = 3706e4d8ff748574f382e5f9b0a3b6258f1f360fd87001b0
+CT = 57511145f2554c6f057453620c5e8e1adc57808e80a2cc25b3159274a7de3550baf759f7fae53dbc
+
+Count = 115
+Adata = d6fe6e17221d4e06ed3ab9
+Payload = e02217394772deffe218c405e40f2a3a56ca01d55d6d3330
+CT = 8075e2a44a5317e414ee729e58f212050582b75405bffea516fba8d193e133e6f78daa39681cb262
+
+Count = 116
+Adata = 2739d2cdfcbe7d5cd7d28c
+Payload = bb713f74a884bd1a994adba87561d637853c6181290ef5e8
+CT = db26cae9a5a574016fbc6d33c99cee08d674d70071dc387d65f92db3b3d1c2de04c69c5d06b0e001
+
+Count = 117
+Adata = 5841571299cd064a6262b7
+Payload = 9641dedd50d80ac0abf7591436065fa2e23e4687abbb86e4
+CT = f6162b405df9c3db5d01ef8f8afb679db176f006f3694b716e4d20ab5ffad6f71155f6839dfdbb25
+
+Count = 118
+Adata = dc5d7fd97bb3243ba585fa
+Payload = aefda8501193edacb8abb94fff875529a537a462c4b9b69c
+CT = ceaa5dcd1cb224b74e5d0fd4437a6d16f67f12e39c6b7b090ebc3af2de52b8bee3d130fa973f716b
+
+Count = 119
+Adata = 8789e0b3e0dc13d9725b37
+Payload = 65e53f549b62aca03f21ab2a494b93805e02cfecf4f12aa4
+CT = 05b2cac9964365bbc9d71db1f5b6abbf0d4a796dac23e731b5cd5a004a0ef28e30383bdaed8f93c7
+
+[Alen = 12]
+
+Key = 44cba20b7204ed85327c9c71c6fea00b47ce7bdde9dea490
+Nonce = f3329154d8908f4e4a5b079992
+
+Count = 120
+Adata = f1e0af185180d2eb63e50e37
+Payload = 6333bde218b784ccd8370492f7c8c722f8ef143af66d71d7
+CT = b9401a4927b34dc15e9193db00212f85f0c319781ec90e3b4484d93cb422cb564acc63d3d18e169c
+
+Count = 121
+Adata = ea74231e49e667ca1c21d46d
+Payload = 3c0e2815d37d844f7ac240ba9d6e3a0b2a86f706e885959e
+CT = e67d8fbeec794d42fc64d7f36a87d2ac22aafa440021ea72c4c151d9927e6a9f19d47ff7d79ca6f6
+
+Count = 122
+Adata = 7f5871a8300471dc325f8289
+Payload = c642c9722d84d708682350dc70bdaa9a1181a415a9e72b93
+CT = 1c316ed912801e05ee85c7958754423d19ada9574143547f959eee29be1415ab03444de0fa42707d
+
+Count = 123
+Adata = ee7e6075ba52846de5d62549
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = f8f50646e284ba77f4ea3e08d69777a53aab062ec784ad70ce97c1c8aea70de04580d7b37f8c014d
+
+Count = 124
+Adata = a30f2fd445820cdf80014554
+Payload = 92577d5db20391110309d490f52acecdfc18382f368bbe42
+CT = 4824daf68d07581c85af43d902c3266af434356dde2fc1ae23b536f993381e525a14599dd5c02e80
+
+Count = 125
+Adata = 0cfec933831644b468724e80
+Payload = 6803dc3f7c06568ca78ee5aa2e9b1b354a4f1e067ff6a25b
+CT = b2707b9443029f81212872e3d972f392426313449752ddb7d6ea722fdd82ede2c7b8832dde3cbe80
+
+Count = 126
+Adata = 6bd14e3bf91dc7fd6be07647
+Payload = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adba
+CT = 8ff3c0856dae0290f7eca38aebda1485163fe5bbe0edd2565c2994b2b469ad977564d83db1ebfe38
+
+Count = 127
+Adata = 6c6ad35e97d023217018162f
+Payload = 1bd1bcc6766d251144376d91ff93ef83033d0e0ee546266f
+CT = c1a21b6d4969ec1cc291fad8087a07240b11034c0de25983ac31ebf9e255eecf3c69ddf198760556
+
+Count = 128
+Adata = 52c35db85cc34b6efed180ee
+Payload = 28f71a2fe498f89203a5d23e8f8fa64b124aea6459fe721d
+CT = f284bd84db9c319f8503457778664eec1a66e726b15a0df13424079e3de87fa59c3d10fd62380a90
+
+Count = 129
+Adata = a96e4776270683ee7d0c9b6e
+Payload = 5be078ead1926074afca81f9a97dc93dcb954c955e4343e4
+CT = 8193df41ee96a979296c16b05e94219ac3b941d7b6e73c082258e1f3fc3eb7e976c86c8a21bd6569
+
+[Alen = 13]
+
+Key = b5f43f3ae38a6165f0f990abe9ee50cd9ad7e847a0a51731
+Nonce = 13501aebda19a9bf1b5ffaa42a
+
+Count = 130
+Adata = ead4c45ff9db54f9902a6de181
+Payload = 3726c1aaf85ee8099a7ebd3268700e07d4b3f292c65bba34
+CT = fd80e88f07dad09eed5569a4f9bb65c42ef426dda40450119503d811701642143013f28ce384d912
+
+Count = 131
+Adata = e63b89e95df8338ecdcc885c3b
+Payload = 37f86aa62b1e31e9ded3e1a38a7e1a8a638d619ac109694f
+CT = fd5e4383d49a097ea9f835351bb5714999cab5d5a356836ac6d3f9c7b9f25e09ce164a11370b8b05
+
+Count = 132
+Adata = a2161536e263459e0b0a29a225
+Payload = 1749f5977197359a5d318d5fea38aba95b3603f1d7011e66
+CT = ddefdcb28e130d0d2a1a59c97bf3c06aa171d7beb55ef443e02b848b006c28803303fd97bdc35476
+
+Count = 133
+Adata = 8ac95a6ae0bce0fb07f85368ab
+Payload = 0842bfb8b38283257c2ea58b29c8350775f1dbf15f73c905
+CT = c2e4969d4c06bbb20b05711db8035ec48fb60fbe3d2c2320431de2bc45b2b726bfda92939a11f68b
+
+Count = 134
+Adata = 44cc9b2510680c4d73f1938c77
+Payload = 68d09fce5e89e4ef6d453b8ee326090cedb97b75b886c7b3
+CT = a276b6eba10ddc781a6eef1872ed62cf17feaf3adad92d96786add8c2619f0782ca12312a1d64266
+
+Count = 135
+Adata = d8a662ab8449bd037da0346a24
+Payload = 45245de4ac6a6196a0b15b77c622a21bb50627379ddb4256
+CT = 8f8274c153ee5901d79a8fe157e9c9d84f41f378ff84a873b6bd4a09f9b4aa2864d39ff1a03e0ff7
+
+Count = 136
+Adata = 8ed39da1d9179e77156eb909f3
+Payload = e928e37dbe8389a53c650edc86f83cd3589a53dc8e45adfd
+CT = 238eca584107b1324b4eda4a17335710a2dd8793ec1a47d819b6935778ffbc0953974de0a9d87a31
+
+Count = 137
+Adata = 423515f7bd592d6a7a2408661a
+Payload = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b1
+CT = 869df54479ad40017e50e6012b5bd71d829b5ed19c64329400a3da0d3ce34a272b51582a998f461e
+
+Count = 138
+Adata = 5a6bc2cd6890a473d478a582b4
+Payload = 1c5ebaeb7b926a39b8aaf65a4c484b113d6f2caafadc33ea
+CT = d6f893ce841652aecf8122ccdd8320d2c728f8e59883d9cf4ef28c338f497a40f550f2945734ad1a
+
+Count = 139
+Adata = 7bdc26b5b4df58af539d91eb2e
+Payload = be5c9fee6babf569c66e6a0d0f3c4dc314f40c0aeca493f7
+CT = 74fab6cb942fcdfeb145be9b9ef72600eeb3d8458efb79d2e07f1998e57ba9b611568632dc5cb9fe
+
+[Alen = 14]
+
+Key = 13f179aa2a23bc90a85660306394940e9bb226ce3885ec01
+Nonce = aaa52c63ca1f74a203d08c2078
+
+Count = 140
+Adata = 5cc924222692979a8e28ab1e0018
+Payload = d3b36c6289ad6ae7c5d885fe83d62a76270689ce05fa3b48
+CT = bc4fcef401c2e1d1c335734ff23ea52c3474d2e6f31648a7f58649400ac9e825b038d67f0c2a6f1c
+
+Count = 141
+Adata = 21fb9cdd9b110bbbc6832275dfa7
+Payload = a7742dd9c3e8bbad08157fbd01ebfb94e1639117c4b4eb5d
+CT = c8888f4f4b87309b0ef8890c700374cef211ca3f325898b23fa5ad4142e0b4650fa5cc8f7ef70d62
+
+Count = 142
+Adata = 9919ddb6ee6c330646cd15953d39
+Payload = 297b4498bf5427e6341aa9275c1f62e3b0c9b150a195ae72
+CT = 4687e60e373bacd032f75f962df7edb9a3bbea785779dd9dfec551d11b8647432cc4320173939600
+
+Count = 143
+Adata = f94cfd1f8c7902a57784c10b9a5a
+Payload = 2218868033e17220655f0196dab6193c58293ca105d467d9
+CT = 4de42416bb8ef91663b2f727ab5e96664b5b6789f3381436a79a075ec2cacee1482b8328b697a3b2
+
+Count = 144
+Adata = 63f3fe58c348dc6bcbb44c3c370f
+Payload = 4a9bc26fb10000a57b9e73a8a3d30f66ef9de8782201ffa8
+CT = 256760f9396f8b937d738519d23b803cfcefb350d4ed8c4739cbe17b4edd64a3dcd2b8ae3352c04a
+
+Count = 145
+Adata = dec0ce763833305aa9c9efdc2c65
+Payload = 1b61b3ff3e4847a17f55f7565826b0e2ccc1368f4de32022
+CT = 749d1169b627cc9779b801e729ce3fb8dfb36da7bb0f53cdf54665c476d0741164685b0d81caca31
+
+Count = 146
+Adata = 592ef6784ee839a049e0d96257fa
+Payload = 32e5998b37987a38800f5bfe3132979ca1447314570aaef7
+CT = 5d193b1dbff7f10e86e2ad4f40da18c6b236283ca1e6dd18500d93b11fecc8b4560320878ba53550
+
+Count = 147
+Adata = 4a47a82b999a2a739959f153a091
+Payload = 84acfb6cf10b301558e5acbf41bbbe0b145dc66dc600f4df
+CT = eb5059fa7964bb235e085a0e30533151072f9d4530ec87303c2a41443578adaf31483bbb6b9f10b0
+
+Count = 148
+Adata = 4ceba98cc0ff5de1a7d580cf23d2
+Payload = d7c73d77a286df38aad116843620911c92e11486be5fcb0c
+CT = b83b9fe12ae9540eac3ce03547c81e4681934fae48b3b8e32232a856c07999e99a4701988b486ef2
+
+Count = 149
+Adata = 15e3b3c5794fececd703ac58ccb2
+Payload = 140882c5d3534bb0861e7ba9423e67439a02ee6f0b0b00f3
+CT = 7bf420535b3cc08680f38d1833d6e8198970b547fde7731cb3a6d50a92f3183c0c5090edc3c7f822
+
+[Alen = 15]
+
+Key = c1dfc48273d406a3a7b9176f80b2dc4e9a7f68134bab66d2
+Nonce = 1ac53ba965cdaeeef7326a37e4
+
+Count = 150
+Adata = 39ba54a410a58a5d11615a2163cc3b
+Payload = 67d9728a88f1fac3af43ed6d634ba902896bd226858697d9
+CT = 360f0fc714994e3b59448b50cdd61d511b4f09e0e5fb5ac826a51fe5b9b598a17eb3da10f936813b
+
+Count = 151
+Adata = 38b0cca09d69320105d24ee3f96684
+Payload = a8365ba9fcfff060b28895f7a2d786c5991a8f7758962caa
+CT = f9e026e460974498448ff3ca0c4a32960b3e54b138ebe1bbba673a94f4280e84724f4a2510165e9a
+
+Count = 152
+Adata = 76718dfb9c68acdd82592d96def39a
+Payload = 497be597dd695cb159d8a64f44049c3b549ac927837b1b90
+CT = 18ad98da4101e849afdfc072ea992868c6be12e1e306d68118865ab37be6f015316e0d177b6c2e91
+
+Count = 153
+Adata = dd719ba1710916a546233c1494a7a7
+Payload = ca452c21383ebc3fb584f0d59a227374854983f243a3f460
+CT = 9b93516ca45608c7438396e834bfc727176d583423de39713d903f67ad0d72fb8ffea2035216b769
+
+Count = 154
+Adata = d893fa2bd7c70e21a5934dc2e99037
+Payload = 3dd118ed65453d3d7844d8de78d7a43587ac5e9305b11464
+CT = 6c0765a0f92d89c58e43bee3d64a10661588855565ccd9750b885e3e054f519d0355db1bd589bb35
+
+Count = 155
+Adata = 97c60265a3a6993b97ac1b375a79b8
+Payload = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117
+CT = f6e126eebe391bf9cebaf9e55248de2fd18ff76fc781cc064a950e4bed4137e38787839e39924821
+
+Count = 156
+Adata = acfdf302ed116ac4755069d1704423
+Payload = d39d188f28521e4fb0a0c5e48e6d6efe4383c95b2535ea8d
+CT = 824b65c2b43aaab746a7a3d920f0daadd1a7129d4548279cca94dd97fd2a5d50eb7dd6234b40c525
+
+Count = 157
+Adata = d449f97164aae9a3046624e98810bc
+Payload = 758102470e221e30d87d2807b5f8b793a7a56c83eecf32a4
+CT = 24577f0a924aaac82e7a4e3a1b6503c03581b7458eb2ffb596f11450d5d2ba55ffb4a6cf7eab847a
+
+Count = 158
+Adata = 3e6c914a196e175079315b1c92b2b8
+Payload = 1db875c4b4f9dd4926dfb5604d6c4d21aba7d905aed9d1b0
+CT = 4c6e0889289169b1d0d8d35de3f1f972398302c3cea41ca164894e9218ecacd143fb62df69a13d33
+
+Count = 159
+Adata = e2b7b00d0cfbdfcc24f1819ae1869f
+Payload = d7a75bc621addccbbe162b86d536d69c887c278384af54e7
+CT = 8671268bbdc5683348114dbb7bab62cf1a58fc45e4d299f685a7c19bc9c2f8e36ed95015ebb679ae
+
+[Alen = 16]
+
+Key = d8a662ab8449bd037da0346a24565683a3bbbbd1800e3c1c
+Nonce = 166fb8d0e110124c09013e0568
+
+Count = 160
+Adata = 1c1c082eeb5b8548283d50cc2ace1c35
+Payload = 61fdd10938557080191d13dd6c3002dd445d9af988029199
+CT = 23c05927502a4ee6e61e4e10552d49b020643eab476eeacc867601fe79a122a7817819655183283e
+
+Count = 161
+Adata = cae884fa25adedd883ef4e7c855def19
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = ce476aedad7cd761d26d59297533ece2b6703002fa0bda63160bb976ab072aec8fcea8eab3dc5aff
+
+Count = 162
+Adata = a350ed58c04473e113b9088b1fb9dad9
+Payload = 863f9a26182f131c594972398b52b3a01a9d314fd9390bf4
+CT = c402120870502d7aa64a2ff4b24ff8cd7ea4951d165570a1291b2c13a3f5e49ce35b9047ee1e8627
+
+Count = 163
+Adata = cb7090f7a465782f680fd44cbc558107
+Payload = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402
+CT = ffa941830a2cfc3b3b14a5b6574fab5b45f550e17099cf57fdd9fd1d469a9042b80e6458d25292b4
+
+Count = 164
+Adata = 914cf55a3fc739b5f87ac7518cc4171b
+Payload = c313bd213dc29c00691e25ce028884192e21a820003aece4
+CT = 812e350f55bda266961d78033b95cf744a180c72cf5697b1a8b8e82175ff30c69ea71d2cfb814ada
+
+Count = 165
+Adata = adc8b69d84ef7ae62f9ca9f371d3488e
+Payload = 85e4e053b976e06a64dfa8523130cdd802d3e7c3d6d797c2
+CT = c7d9687dd109de0c9bdcf59f082d86b566ea439119bbec9776fa36db27b2f84d1b8ab55e2fc89ab8
+
+Count = 166
+Adata = 29ed477994dd231d3a71157eb56d219d
+Payload = c77aae5fd09dc9bceee7428e0734d4b0556528396a58f909
+CT = 85472671b8e2f7da11e41f433e299fdd315c8c6ba534825c0e32058ea939036805a735198934a072
+
+Count = 167
+Adata = 494c8f931029a4919e2dcbc16512a8bf
+Payload = 1f47273103f265f963e498878361c06c01a5ffcfb630a161
+CT = 5d7aaf1f6b8d5b9f9ce7c54aba7c8b01659c5b9d795cda3437098c81475f8a1d8f3b0e63d499d387
+
+Count = 168
+Adata = 53200bc5d1f1fb0eeff02d2bc42f7d54
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = e1bfb9812822f9d1f38ee14181532085c4e58ac732b057bd9d7317973878957e8fc1fa57a025a3e9
+
+Count = 169
+Adata = 61e0e28bf344a9a1b04b15156e06498e
+Payload = a0d3a94ba6bb3bedf38220d1cba7e91273ad19f9a1c436c0
+CT = e2ee2165cec4058b0c817d1cf2baa27f1794bdab6ea84d95b0aa1befae96e71b9d221673844b1cb7
+
+[Alen = 17]
+
+Key = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5
+Nonce = 924322a3ef0c64412f460a91b2
+
+Count = 170
+Adata = 03c2d22a3bb08bbb96b2811ce4b1110a83
+Payload = 1bd3b5db392402790be16e8d0a715453928f17f3384c13a7
+CT = ad736402626df0f9393fe4491eb812725ad39d6facf20b5b2f9340b0d48a17ae1cc71d7515e61ee9
+
+Count = 171
+Adata = f390387610741d560325b5d2010d8cd4a0
+Payload = c93aaa04279e451b6880ed7b7fdb3ca9e80ab76180434937
+CT = 7f9a7bdd7cd7b79b5a5e67bf6b127a8820563dfd14fd51cb717bae4c040561bcfcf80fd842ae8dd8
+
+Count = 172
+Adata = 891d7988a56415a7b433f463b1e80eaa62
+Payload = 2611612ccb5ffefaa73195509bb52c641472bca0dfd09d49
+CT = 90b1b0f590160c7a95ef1f948f7c6a45dc2e363c4b6e85b5bc9fb15d874feccb6b5f581fa470734f
+
+Count = 173
+Adata = 831c0fed5e600dd82d7d55669262a9a17d
+Payload = 08136e946e306cde0544ddc2f3f4a529c89c7b77a5e635c1
+CT = beb3bf4d35799e5e379a5706e73de30800c0f1eb31582d3da72589ee50d23f925f7998ab3ccac37f
+
+Count = 174
+Adata = 32ca9d412d4ef0e89928496e96c9de7f2e
+Payload = 695aaac402942de7d899cc3f741c7fb2b2d8247a7676cf29
+CT = dffa7b1d59dddf67ea4746fb60d539937a84aee6e2c8d7d555c0b608f331dca47c65f5c879f2d532
+
+Count = 175
+Adata = 0746b2e6149c7f55854e9ca3e6861bf0e9
+Payload = 8f958d796be0566512f0512dcebd2e12f3160b05b72ae955
+CT = 39355ca030a9a4e5202edbe9da7468333b4a81992394f1a9b039bd916e923e2fc1f7c60eb59916fd
+
+Count = 176
+Adata = 0e4cbd1c574d656112bf6e70a8f23347f0
+Payload = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364
+CT = 80de1cc22a964beab63cbc5b3cb91bdb23ac4da247e34b98ac07f2c0847069fe5be26e623033f532
+
+Count = 177
+Adata = 1a05ff12412bf728497536534c234901ce
+Payload = a9ccee975feb10f635d548a8502f7c8b6adbd2be74117257
+CT = 1f6c3f4e04a2e276070bc26c44e63aaaa2875822e0af6aabf4e66a2b210e5a03bb10ff2926ed8a48
+
+Count = 178
+Adata = 3bd063a51c71fab5aeb47e7f8f958d796b
+Payload = 7df6220599d6235eb450989b6f0cd6c96db62b0d13afc4f4
+CT = cb56f3dcc29fd1de868e125f7bc590e8a5eaa1918711dc08ec90169d0c5c11fff8f255fedb13a99a
+
+Count = 179
+Adata = f0d334e0a27c3d00d56b15c2ee426e6347
+Payload = 6f65a24344c32debaf9f8c3fa426fe0b139e8ad1c8b1fbbb
+CT = d9c5739a1f8adf6b9d4106fbb0efb82adbc2004d5c0fe347170141cf3f207c4f0fc1b0238477cfad
+
+[Alen = 18]
+
+Key = e67f3ba11282d61fe36e38cab7b559c2fd9cbe8bf7eb5863
+Nonce = a727ed373886dd872859b92ccd
+
+Count = 180
+Adata = 68d199e8fced02b7aeba31aa94068a25d27a
+Payload = d7a954dae563b93385c02c82e0143b6c17ce3067d8b54120
+CT = c6cfaa1f54d041089bd81f89197e57a53b2880cefc3f9d877e30b2bcc3f1ea9ec2b8f28bf0af4ecf
+
+Count = 181
+Adata = fc4bbe329a86089ebe2a2f3320dad55a9bda
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd2
+CT = b3605f2ec11a2a70abff1c3ab717fd172ba9e9ac72d961753a6e6844102d6bb86986c030765d3393
+
+Count = 182
+Adata = d8741e540330692d83cc806a8ac1c4742be6
+Payload = 56ef76dbec6b8b46f5b7b4e311c0baaa6fcf54c69c0b9c3b
+CT = 4789881e5dd8737debaf87e8e8aad6634329e46fb881409c3f92a80b1d82f8c1dc32bfe64adca12a
+
+Count = 183
+Adata = c8b1992dfba55b4ab86b480546c861655e1a
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 364f9da4a34153d9d97696eed355ec79d464405a927d14a12fb48ad162b0c0678674d79d26a6b5ef
+
+Count = 184
+Adata = 347e12eec56e95aafcc7d25bf10fc756b4e4
+Payload = dd433eb7422c7c4dccee57a1679633ced3b5f08df763d457
+CT = cc25c072f39f8476d2f664aa9efc5f07ff534024d3e908f081c7cd81c974d985bf24b7fe9542141a
+
+Count = 185
+Adata = 45b35a04d6e2645e9a5aef206ed4e36199c9
+Payload = 70523bc397417e09d791a4976960e02636ca7144a5681cf7
+CT = 6134c50626f28632c989979c900a8cef1a2cc1ed81e2c050a7f6a5c04e59896074e1594706ab27e9
+
+Count = 186
+Adata = 378b48531fe34f55125b2f14f59715dd6ef0
+Payload = 514cb462dd4b117f26cac22062fcbeb353650c71649a7b3d
+CT = 402a4aa76cf8e94438d2f12b9b96d27a7f83bcd84010a79aa9d16c3ab79276cff345444511940a9d
+
+Count = 187
+Adata = 73ed686d6fecdc031cd97653137f269d6537
+Payload = 7f0c2b261db3f3de0ce3a733f4b8c446c374567d96d00379
+CT = 6e6ad5e3ac000be512fb94380dd2a88fef92e6d4b25adfdef92bf8aa6facbe6f9607ea02b54a1bf0
+
+Count = 188
+Adata = 5b0441107e5560be94f030a41cedbdb116d9
+Payload = ebb3e2ad7803508ba46e81e220b1cff33ea8381504110e9f
+CT = fad51c68c9b0a8b0ba76b2e9d9dba33a124e88bc209bd238e4936ee93b5c7a302913292df33c1700
+
+Count = 189
+Adata = feedcc5f8524fe7d49bcd178415b9f4c450a
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = 237022260902363567fc3cf433ad446235fc1a5a3d53ad7493426b6193afe765a76b3dec00266e69
+
+[Alen = 19]
+
+Key = e0a29a2c7840cf9b41de49780b9ee92d646a4bfc5b9da74a
+Nonce = fc9fd876b1edded09f70b18824
+
+Count = 190
+Adata = 36e15baafa0002efbb4bb26503b7e3b79f6c68
+Payload = 344dc8b6bd66a1fbbe330a95af5dd2a8783dc264d6a9267d
+CT = 43b3b96aa5a54378f3bb573ffda3e154aa7f425fc3008175b60a77b9d38740356b544b1c0f259086
+
+Count = 191
+Adata = 712b788f0276e2b5a58be80f9114a12ab2a268
+Payload = 6d0546d4e95d1cfcb37a8f88a62064f5d95791311511535b
+CT = 1afb3708f19efe7ffef2d222f4de57090b15110a00b8f4535f750bb4cd42db3038e2c1622b72cea8
+
+Count = 192
+Adata = 07f77f114d7264a122a7e9db4fc8d091334a03
+Payload = 05024ce13b9057dd2c509db7dbcbd5585e4e64a1e2e380ff
+CT = 72fc3d3d2353b55e61d8c01d8935e6a48c0ce49af74a27f761e77b59ef7eeeae35bb53bb9543b64a
+
+Count = 193
+Adata = 899b036138cee77cd28382ba27984d858a6351
+Payload = 77b8e735b13b10e45e411ab94c6fe1a9eb89f0a7af40ff1a
+CT = 004696e9a9f8f26713c947131e91d25539cb709cbae9581244a60fdb473098a11b2176d37b2c4643
+
+Count = 194
+Adata = 4b000440a8484a5201cd54aec058919769772e
+Payload = 6b21800ae599a15254bb33f0bb080788fb6e9fa054bfd8b2
+CT = 1cdff1d6fd5a43d119336e5ae9f63474292c1f9b41167fba58d4afc30a7f672ea34e05ec1843d848
+
+Count = 195
+Adata = 73a222e681ed1ca47d92a6dd90625d895fbf29
+Payload = bfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028
+CT = c857a87376dcd0352fe24172c9e201ade919d09a987317204ef270e0f3b5e3ca0b8440af65c76e85
+
+Count = 196
+Adata = 7109a3a36b286059bc1a1abb2767c92f884e3f
+Payload = c68b1bc0050e19780ab53efbea175634f70a7245d966966e
+CT = b1756a1c1dcdfbfb473d6351b8e965c82548f27ecccf3166ffb66991b38a0345fbbff5f2362f87de
+
+Count = 197
+Adata = cd15973753b94b77bb4b778de8b3b0cabbde85
+Payload = 4256f1c9b64390fe2120df9fd38e497c2903c2ca5679ab75
+CT = 35a88015ae80727d6ca8823581707a80fb4142f143d00c7dd033a087c44c2e44adbeb333aa9ded10
+
+Count = 198
+Adata = 6e5e0793855f7145e13a5872f563e5ec61cfd2
+Payload = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192e
+CT = ccfe476f53cfc28a00bb072626088022766c6cf454ecbe26ff9c8713422fe38d5bbf2dedccbffe10
+
+Count = 199
+Adata = f844684f5404e7d8eedfa20394b40b4f5d910a
+Payload = 86afa9cdd743916563ebfd3adbdd56e015ea3a4ebc61cfe2
+CT = f151d811cf8073e62e63a0908923651cc7a8ba75a9c868eae75de56eabcf8e02c1a27705adef2732
+
+[Alen = 20]
+
+Key = 26d0a3a8509d97f81379d21981fe1a02c579121ab7356ca0
+Nonce = 8015c0f07a7acd4b1cbdd21b54
+
+Count = 200
+Adata = 093ed26ada5628cfb8cfc1391526b3bcc4af97d9
+Payload = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711
+CT = a3a60b422eb070b499cf6da0a404b13a05cedda549c6b93e6ca0e07e04674f21a46df2659a5905fb
+
+Count = 201
+Adata = 7df13c9d2247aa40af7bbe2da98bd366d8b47b43
+Payload = 93925579b6367ff592ecbd59495fdeccb50f31ea4fa390bc
+CT = 079f7430e3ef9b6373c1c0cb11d884507d02a31d83cd9e93836597806f5da1d176c745d95c4fa46a
+
+Count = 202
+Adata = 7f369bbc99b6f08049eeb43566269a174829d4dd
+Payload = 8363aef9c7c34e1f8149de46c97d5ac79d38c6ed31ab1d12
+CT = 176e8fb0921aaa896064a3d491fa005b5535541afdc5133df826dda99111691993027628c70ff6ae
+
+Count = 203
+Adata = 04aa8442179f62babad0c006e36af0c21105f27a
+Payload = 17281acb525b13653000ab45d86e70106c10a93c99b18f76
+CT = 83253b820782f7f3d12dd6d780e92a8ca41d3bcb55df8159d074b018143a7ea1b5369b7f80eae20d
+
+Count = 204
+Adata = 997e646014f19a53beab8877ca6022bef23016f1
+Payload = 5d48a71557608736eded309027a80349a18e9ce5dee2bc6a
+CT = c945865c02b963a00cc04d027f2f59d569830e12128cb2455db17d3f75214c3cf39858617cfee57a
+
+Count = 205
+Adata = 60ffcb23d6b88e485b920af81d1083f6291d06ac
+Payload = 6c9d11cfb64d96bfab61c04a25d9e19294fb7330fb4847c8
+CT = f8903086e39472294a4cbdd87d5ebb0e5cf6e1c7372649e79550998376e61e11a5a69e9f8fe1c329
+
+Count = 206
+Adata = d574632658bf456dfbb11c2653602ed0f4dae777
+Payload = 7d41688c86d5e3bc53966810f2299fdd732e3471fb0a88f9
+CT = e94c49c5d30c072ab2bb1582aaaec541bb23a686376486d6a1b0d05a7ebc657c3235479893bf7e5d
+
+Count = 207
+Adata = d896ed60128f4bb0277d3af94c5138cf91697aa9
+Payload = 8c7ae2c3c503e9072d6e04e44c2ea78fd24994503567a136
+CT = 1877c38a90da0d91cc43797614a9fd131a4406a7f909af1980c98c8959c158ce209aebcbd554f250
+
+Count = 208
+Adata = a350ed58c04473e113b9088b1fb9dad92807f6b6
+Payload = 49bc9d3bcf3c22daa8cf55c1b59d4bffddc2412d60518e98
+CT = ddb1bc729ae5c64c49e22853ed1a116315cfd3daac3f80b7573175f9105cd16ee384465ebb232200
+
+Count = 209
+Adata = 1db5887001204194e8b5dcee92c8af8fa5f7321f
+Payload = 25f3788e0d3dd8f5821faa4e45a9d6b3995fd881f927135c
+CT = b1fe59c758e43c636332d7dc1d2e8c2f51524a7635491d732b67e993384f2e7229d1838efd040d99
+
+[Alen = 21]
+
+Key = aac60835c309d837aacc635931af95702a4784c214283ebb
+Nonce = 0e20602d4dc38baa1ebf94ded5
+
+Count = 210
+Adata = 796e55fbe7bed46d025599c258964a99574c523f6a
+Payload = e8610756528f75607b83926597ef515f4b32a8386437e6d4
+CT = e0a3d5f43e688ce104f4ae1a4fcd85500aa6b8fdbcd1b8d3003c0c3b7369e79339433e1754c0937f
+
+Count = 211
+Adata = 5170836711fcb1a350b087907d8a17c7637aa1595b
+Payload = c61b0c1845fa9b2e0013b3fa9a8cb4f4fbbc6846f63ed180
+CT = ced9deba291d62af7f648f8542ae60fbba2878832ed88f87120a7f18d021833b167bf330c4858239
+
+Count = 212
+Adata = 2a68e3fe746f593c1b97cb637079c3e5ee352c107a
+Payload = 10c654c78a9e3c0628f004b061e28c39a3c23e7250f53615
+CT = 18048665e679c587578738cfb9c05836e2562eb788136812ca9698d9a88e892c364e57dd35c2f17a
+
+Count = 213
+Adata = bf38ca0e89b8f5ccd29387f7f193ab5a967caa715b
+Payload = fa3a959fdff853c39f76da626094a1ea6dbc78bd2f091a79
+CT = f2f8473db31faa42e001e61db8b675e52c286878f7ef447ef3839d6f7e20a2e343f4c4da9eb9be13
+
+Count = 214
+Adata = bee00f2f75a4415ce993d2d14a6d8e01d1d59a48f6
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f6d
+CT = 7e13fc9e20ba608a8a14fa757cbb4a5dd81998ba4fa1216a6630bfb7a2a2441e020efdf36274b72f
+
+Count = 215
+Adata = d5b614e4e8f72a5d8b1ec2b375da5dac64c2cc30b1
+Payload = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b634
+CT = 61fd7cd894ad5a168fc586d10191139a7ee1f78794afe833866bcee343ec5aae61f9effa19b99d3b
+
+Count = 216
+Adata = 33f11aa36d8ab0fc53486839a576b31ee915dbd769
+Payload = 56ce9a09f38127b14dbbdcaa59f363c92a3b9843ad20e2b7
+CT = 5e0c48ab9f66de3032cce0d581d1b7c66baf888675c6bcb00331b60eb252f744a06b4a95aa9f4e7c
+
+Count = 217
+Adata = f40bce1a6817b29b9e8b56f214fcca7dfde17e7ee6
+Payload = 5cd8986e974d09ede34ba68fd81d6109a64092e7fbbaf87d
+CT = 541a4accfbaaf06c9c3c9af0003fb506e7d48222235ca67a4153778a644cb2469cef3ad125e257bc
+
+Count = 218
+Adata = 53c457d8d4d4ab95ba116c28b82c16743cb09de9fe
+Payload = 9c3c610f204d98702dd91ea28e0cc14830b26bb5e2ee0349
+CT = 94feb3ad4caa61f152ae22dd562e154771267b703a085d4e7013e1c34dbc5efc7bcd4f8e52797644
+
+Count = 219
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c
+Payload = 90c5dd9db0316dac89db18f70491bdf0a06a6a7f72b77d9a
+CT = 98070f3fdcd6942df6ac2488dcb369ffe1fe7abaaa51239d66aed667c761b7dea44822e30cff671f
+
+[Alen = 22]
+
+Key = 671544bf2988056f7f9ccd526861391a27233793a23f811f
+Nonce = 0a259148a1d081e0df381ecd0c
+
+Count = 220
+Adata = 61dafc237cb52f83ab773ba8a885462b6f77d4924611
+Payload = 576b069ae2713f53d2924c1fd68f786cb2eec68892f9e1be
+CT = ce06b3d09b02921f290544032a081a7766612940048867281bb089af0245792c16e6320cf5ffa19e
+
+Count = 221
+Adata = 87e49b8164e7052becfa0c966991637b38df833fc5f7
+Payload = d7eb0d7dd737805cd3b8dbf451aeea2fa1f6a96eb58cb428
+CT = 4e86b837ae442d10282fd3e8ad298834757946a623fd32be3cec29bd5df92363d6bb75456f5cd32b
+
+Count = 222
+Adata = d302a518d7c625756d3e4c8cc2b1d973a19107c945fc
+Payload = 77d8c9e6321314524afd05b7ad599c29f4eedda9e9f0763f
+CT = eeb57cac4b60b91eb16a0dab51defe32206132617f81f0a901ca82cddb78a2fe3904d1d8bf6fe5b2
+
+Count = 223
+Adata = 6566bb616a94bb03df5c26b722bcd38d516285c5f6c1
+Payload = abbf28b3ae164051648293d0b94e11f5af8468450005c7c0
+CT = 32d29df9d765ed1d9f159bcc45c973ee7b0b878d96744156d095ad121f0f76f07b715cad996def52
+
+Count = 224
+Adata = 141be3601e38185a9fa1596d2ee406415c9673af32f5
+Payload = b67d50110f844b36a00d352123012a1123c7c3cba959dc48
+CT = 2f10e55b76f7e67a5b9a3d3ddf86480af7482c033f285ade8529ec8f477462dc2409482c3479756d
+
+Count = 225
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732b
+Payload = 2a63f7b09b43fee65738e8115bd8419b3ef3e8f86eca707f
+CT = b30e42fae23053aaacafe00da75f2380ea7c0730f8bbf6e9b14fe8dbb3c361ea61d7b44e689a1c48
+
+Count = 226
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc
+Payload = 59dad755af92c29522da4348ab9b3037fe87004f5fa1394a
+CT = c0b7621fd6e16fd9d94d4b54571c522c2a08ef87c9d0bfdc54f0659fae291f943f2f3b33688602cb
+
+Count = 227
+Adata = 5d895fb949344e603ce5de029842b20d2bb614ecbbb8
+Payload = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f
+CT = fdb508761d1cdb90977f95f3288015e5c3be88e1745a2f993af4e3a7a20390a8da264299712a34e3
+
+Count = 228
+Adata = 74cc8da150b0bacdefa8943900b4ea047611d96be70a
+Payload = 0c3c9a634a000f00be003846eac7482e303a5bef3a70fe75
+CT = 95512f293373a24c4597305a16402a35e4b5b427ac0178e3a7f79d2b5a9bde5bd453bc8a03e971d8
+
+Count = 229
+Adata = 65f6adbaaa803dbad5ba9cb6d231314d55147cc61399
+Payload = 712c788928c8a1562bc1f3f0eb1286e15c3405f6a6fa0443
+CT = e841cdc351bb0c1ad056fbec1795e4fa88bbea3e308b82d5ffccebfb8c833833db40e98a1950fb70
+
+[Alen = 23]
+
+Key = 90e2c63b6e5394b1aeec03f95a9d13a01a7d4e9d58610786
+Nonce = dada5465eb9b7229807a39e557
+
+Count = 230
+Adata = f5629ca0eea589f6cf963d875a7d2efb656983f2dd2231
+Payload = 44dd098b1f869d670a8a841900c4bef023a1946a0c278354
+CT = 6b38ca85450e05e7b9362ed7e6e291a130ff233b5a561cdef7ec84dd992fdf98514f845dac8f656e
+
+Count = 231
+Adata = d43d7753530a7280b76221906dca85d396b6cf05125018
+Payload = cea19562328bd1fea889f575db6a28a14b7d06fb9f9c98bb
+CT = e144566c6803497e1b355fbb3d4c07f05823b1aac9ed07313613ed15d527d9dc58ab6893e723db58
+
+Count = 232
+Adata = 75650ce366757618af20205b69af7e5d4e82c398c00101
+Payload = f0641f595b791edd860977fcf699688587a354e053e9c7fe
+CT = df81dc5701f1865d35b5dd3210bf47d494fde3b105985874ef8728d1bf3a2d93db3266bafadb7c26
+
+Count = 233
+Adata = c00f1b8066677c63e898fddfb8a1b482b536963da0628d
+Payload = c7486a084f8475e6f5138e8d6e9f42a1de90f05aa88a362d
+CT = e8ada906150ced6646af244388b96df0cdce470bfefba9a7a5bce94d7564d297fe87730f1a36acf4
+
+Count = 234
+Adata = 5a89ab6b26b2ca78f98a8f8409fe8008b97ba9ef185d41
+Payload = 091ef698e16dc43a11d3ea005d5a5cdb7f1bdb5665a6c81e
+CT = 26fb3596bbe55cbaa26f40cebb7c738a6c456c0733d75794cd971b07fc14c512b8df6dd964b129d0
+
+Count = 235
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d3
+Payload = 62f204394b367c4410746001e02dfd171858396568fdd43b
+CT = 4d17c73711bee4c4a3c8cacf060bd2460b068e343e8c4bb1a192b781dc94448d4a0f6a439a716339
+
+Count = 236
+Adata = 4a47a82b999a2a739959f153a091a65c4d7387646da66b
+Payload = ac1cd5ba4997af91dbd74aee7730f9ee92cf8a360ca96a8a
+CT = 83f916b4131f3711686be0209116d6bf81913d675ad8f500cade9533b272e0a3edeba68362b057b4
+
+Count = 237
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab
+Payload = d0a249a97b5f1486721a50d4c4ab3f5d674a0e29925d5bf2
+CT = ff478aa721d78c06c1a6fa1a228d100c7414b978c42cc4785d68df8ff28345be4d83541a72071059
+
+Count = 238
+Adata = 720a9dc3e33ac080775a06f67f4a6591c37d0e101944a0
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664caa7ec8892be6a18458c663665495035
+
+Count = 239
+Adata = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903
+Payload = 77fb98f24172f5d5edadbf466ee910855a71d46090b789ee
+CT = 581e5bfc1bfa6d555e11158888cf3fd4492f6331c6c61664862fda880e45e891a3a50da7e14344c8
+
+[Alen = 24]
+
+Key = 13cdaaa4f5721c6d7e709cc048063cfb8b9d92e6425903e6
+Nonce = f97b532259babac5322e9d9a79
+
+Count = 240
+Adata = ad6622279832502839a82348486d42e9b38626e8f06317c4
+Payload = d7c837971b973f5f651102bf8d032e7dcd10e306739a0d6c
+CT = 4709600418f2839841e6d126359f6982bdb53acc7ff209635623d15b24184481eadc63bb8c878fc4
+
+Count = 241
+Adata = ad4833aa53218949cfd724814a43889a74a2114bbef4cf37
+Payload = 7d672bccd0fb01ce79320ed61779146aa432038daa13cb41
+CT = eda67c5fd39ebd095dc5dd4fafe55395d497da47a67bcf4e614c3e546273f0aeef207bd3f4d32fca
+
+Count = 242
+Adata = 54a723826086c7175e8fdc854b62d780de6ac1f90b57dd3a
+Payload = 0e1b73df74982f535a5fb08bc13d22515ee10969efe033bb
+CT = 9eda244c77fd93947ea8631279a165ae2e44d0a3e38837b413c6395ce9aee2e22ac0606beb140185
+
+Count = 243
+Adata = bec02d7df4cc3deefdd7e7d3ea82d381c870ad46bc06d64f
+Payload = 9a55aff269b180118ff0ea99e851c7474d19d23e641f16a9
+CT = 0a94f8616ad43cd6ab07390050cd80b83dbc0bf4687712a661e4f02150bedd86dfa49f52b214239d
+
+Count = 244
+Adata = 1b8090d712e0ec95a01bc3aeb6f5230c67c355e0ed68043a
+Payload = ff19294e8faed8353dbcab0b146e2ef928dd2680833424bd
+CT = 6fd87edd8ccb64f2194b7892acf269065878ff4a8f5c20b2f0e82b9f04bfc0cc0ba432b5135450c2
+
+Count = 245
+Adata = 5ed0b9f25d07b26717cdcb2507bef9d681ecd9389831ac15
+Payload = db1eba6ac4a79aa1d97838d263c7c4ffa7d354770e762805
+CT = 4bdfedf9c7c22666fd8feb4bdb5b8300d7768dbd021e2c0a2e64c82b60880c5c7506321a1060a481
+
+Count = 246
+Adata = 55f16fefaf2168aebc61b5e01d9e1f7bfe215eaaef118974
+Payload = 012d45168505ca9fde5aed123875639a207d473b993dc7b8
+CT = 91ec128586607658faad3e8b80e9246550d89ef19555c3b77152f64dc993b36ad9d5d12bb52b1ad5
+
+Count = 247
+Adata = 9893bf14fd3a86c418a35c5667e642d5998507e396596c50
+Payload = b205f26d6c8a8d6085ab28d595703cae046f96d82093082b
+CT = 22c4a5fe6fef31a7a15cfb4c2dec7b5174ca4f122cfb0c243e5c69256b6326ebb7ee6e677d396765
+
+Count = 248
+Adata = 244b840085bda9576c8424bb05a925a6b09cad2d0528ab8d
+Payload = 549ba26a299391538b56ce4bd71dbbfd96995836f8915ca5
+CT = c45af5f92af62d94afa11dd26f81fc02e63c81fcf4f958aa2083dac565c7a63908f0022e2867bb68
+
+Count = 249
+Adata = 9e8d492c304cf6ad59102bca0e0b23620338c15fc9ecd1e9
+Payload = 9e9dbd78a1066800ae33253be6104015158a0187e4f38116
+CT = 0e5ceaeba263d4c78ac4f6a25e8c07ea652fd84de89b851968242fe32958ea32e670ae1b3543974f
+
+[Alen = 25]
+
+Key = 90851933d4d3257137984cdb9cba2ca737322dac4dbd64bc
+Nonce = be02df3a840322df8d448c600c
+
+Count = 250
+Adata = 69a9dd9ac8be489c3a3f7f070bdaca10699171f66ab3da9351
+Payload = ba1785a149cb8b69a4e011c11a3ff06f6d7218f525ac81b5
+CT = 89ab2efefa8406336d9e2245199fbc9454f0ef650b9ed0f446c7246bd3130803bf8d703ef5bdf15c
+
+Count = 251
+Adata = 0c39a72f0f38d2713c164b0f870646fc65b9838a322ecfddd0
+Payload = 263dc4fb5cd8798ce0f183a816e51fafba167533dde1bf96
+CT = 15816fa4ef97f4d6298fb02c15455354839482a3f3d3eed7096a6a4422e582c5d02973952ac80e5f
+
+Count = 252
+Adata = 911d9f5c4c34c2f4b69be1e253d43fe729e2ab2622130394b1
+Payload = 7b5da2c283116713f3d80c7907114270964541e03ab80d50
+CT = 48e1099d305eea493aa63ffd04b10e8bafc7b670148a5c115965f6df4332fe7a2cdc4d1b80e28a34
+
+Count = 253
+Adata = 8a961df9c23f6d5ecdafa94c61164a22f460a1bf7415258d39
+Payload = 541a2b3ee25022c92fdc6783a6cbde90680ad3dc41868e5f
+CT = 67a68061511faf93e6a25407a56b926b5188244c6fb4df1e18bed174081b2170ffc6ab53b54c9ddb
+
+Count = 254
+Adata = cac7a248a4d4e96a9733627e247234995d6aa57e491498118a
+Payload = ebb2e893da9f32c363f98bc76fd14eda59e7cc620070f6d3
+CT = d80e43cc69d0bf99aa87b8436c71022160653bf22e42a792bac3d3a2b9ef6d4c8715f9a5c6fe8245
+
+Count = 255
+Adata = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eebd9
+Payload = 199cca0d0e1c70ec405d6816cbddc69f8ada624f2c168891
+CT = 2a206152bd53fdb689235b92c87d8a64b35895df0224d9d07f9610c82fe9a7c78e8f1980e886b446
+
+Count = 256
+Adata = 78b6ed20ed85337c969618bd41917cd85c37e7c35c3a12e25f
+Payload = ca481f557306f9ce386edd0cfde375a550cb5b574be524f7
+CT = f9f4b40ac0497494f110ee88fe43395e6949acc765d775b6aab366637ec41d0bf557f578be424a8b
+
+Count = 257
+Adata = 87faef55c54250c30232ccaf5efa1ff41b6243b2a5bc93e7cf
+Payload = 6f1b4ff66d3aec7b0c0d9e202acc52722e15bca0983291e0
+CT = 5ca7e4a9de756121c573ada4296c1e8917974b30b600c0a1e57a5b3ae26469d229425f887ad5a2a1
+
+Count = 258
+Adata = 7f19ac3e53a629a2df1cb56d68fde0c80a46be40a996830e2a
+Payload = 7533c88ce55c2243b64b6c5bd01aed4dd6ac8bb9fd333e06
+CT = 468f63d35613af197f355fdfd3baa1b6ef2e7c29d3016f476ce4fe492062f74bff4c3c0e9ea849a4
+
+Count = 259
+Adata = 0516a69bfd8785ad001367b51e5410b75c11b761be08b9eea5
+Payload = 19ea09a9bfd10db2a74e398859d8f4831fa5749767773acf
+CT = 2a56a2f60c9e80e86e300a0c5a78b8782627830749456b8ead47ffc17b871f530f62b9f9aec98509
+
+[Alen = 26]
+
+Key = 5c5d02c93faa74a848e5046fc52f236049e28cd8096dcac6
+Nonce = 54cbf2889437673b8875a0f567
+
+Count = 260
+Adata = 09fc21ac4a1f43de29621cacf3ad84e055c6b220721af7ce33bb
+Payload = b4da43ebfe9396b68f4689fba8837c68d0064841c6ddd4a7
+CT = d40725397229021a18f3481e3a85f70445557bb2a85e4ae8101a34c777e918e16186fda05a386572
+
+Count = 261
+Adata = 10f0c45d06a138a964fb11b2d450620a2977bcd2952afe371cad
+Payload = 7b628930d44e22907277db057395601b82b65479fbd59613
+CT = 1bbfefe258f4b63ce5c21ae0e193eb7717e5678a9556085cc1e79234882846d916dabae40b1bd055
+
+Count = 262
+Adata = 64dbb170a037b36beed28a2637c87830e2b23f8eea6cd9a7331c
+Payload = 9db30b669fc5d25f05e0dc708d597da6ddce2dacc85ae99c
+CT = fd6e6db4137f46f392551d951f5ff6ca489d1e5fa6d977d3e35499e3c09dc384eb41344ee8be3769
+
+Count = 263
+Adata = c47de6608546a02c6eebd6628c9123f6936c0154d3df52a367e5
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 02de0a6c5fdcf929f5f8fc2c53f2bc29dec98633526340ddd605189608ce40b237dde7bed6fde487
+
+Count = 264
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb7
+Payload = 5c9bc739f6b6fe4214f3c6aad307d1f208892d79de010e37
+CT = 3c46a1eb7a0c6aee8346074f41015a9e9dda1e8ab0829078c31f69c847440be20bd08cfef330002f
+
+Count = 265
+Adata = 8a9716135fa38c250e249f6712f7cb3ad9210d7278b53d599df9
+Payload = 0df109298083d3896214b84ff6edb11e9cfdbd88f5702839
+CT = 6d2c6ffb0c394725f5a179aa64eb3a7209ae8e7b9bf3b676ca83622b127fa50fc9637998c0ddd44d
+
+Count = 266
+Adata = 2d52447d1244d2ebc28650e7b05654bad35b3a68eedc7f851530
+Payload = 518f651f6d82f670b63767ad8476ed8fc24df12a45110611
+CT = 315203cde13862dc2182a648167066e3571ec2d92b92985e81e738b9e4b0dc7b7a39eb7d03adc64a
+
+Count = 267
+Adata = 3cba0fd2bb16ae1d997cbe659a2dd101885c97f2322b0172b5d6
+Payload = e91a694bea2d351928b6098660d49f382c087f6777de159c
+CT = 89c70f996697a1b5bf03c863f2d21454b95b4c94195d8bd3d298c05b1d2e597f44f8621ecd11ed16
+
+Count = 268
+Adata = c7f93152016bba584dadc6002ec493a46305726068886d2340da
+Payload = 2d14792ed349a878b2b879e7fa5f438a50e36947ce827e73
+CT = 4dc91ffc5ff33cd4250db8026859c8e6c5b05ab4a001e03c5fd5221fceecbf0dc7211a1aec06793a
+
+Count = 269
+Adata = 799cac048eaccded37ca6a70dd89595e1ee04606212da5572679
+Payload = 315b8d95938d304015bbc94ea03c21f6dc25c90f991ba680
+CT = 5186eb471f37a4ec820e08ab323aaa9a4976fafcf79838cf5c25f00b862b49fcfe8447949f39787c
+
+[Alen = 27]
+
+Key = 0234dae5bd7ae66c67ff0c1a3f1a191a0d7bceb451bc2b7d
+Nonce = 16d345606a315ad2406abbcb43
+
+Count = 270
+Adata = c37fdf7449fd7e943595d75e977089c623be0a3926e63fdbbfdf4a
+Payload = 0f960a89a7e806f8709047cb7a2e7c4211ad724692c88a05
+CT = 3907880d25f910eab12dd14e704d1b33ea7c453634d54da2a461f44dac1112ae3f9c65671a931d3e
+
+Count = 271
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb99
+Payload = ab40a4baa39b0e568bf2193fecbc36b84c76bb50523b2912
+CT = 9dd1263e218a18444a4f8fbae6df51c9b7a78c20f426eeb5ed15db6e142ee07b59eb5b0ad3a59194
+
+Count = 272
+Adata = 79ae14843b2e7ccf0fd85218184f7844fbb35e934476841b056b3a
+Payload = b74c06d9077c568762796d5be14f3563e7205a6e9bc65bcb
+CT = 81dd845d856d4095a3c4fbdeeb2c52121cf16d1e3ddb9c6c203f11f66b74366caeca8dbded2bf17a
+
+Count = 273
+Adata = 542d86fd7ff591f97e6926a090553538bc3b8a6bcd45f2e29c7d9f
+Payload = f2179beb5635a6d8a8340acea0ffcf4428e5de1306a8c12b
+CT = c486196fd424b0ca69899c4baa9ca835d334e963a0b5068ced925fb9a4cf6b6bf17f72ab044653d1
+
+Count = 274
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a4
+Payload = d1a9e4593bc3d02c407e84a1736e587c1819c72195a07d57
+CT = e73866ddb9d2c63e81c31224790d3f0de3c8f05133bdbaf0d1f677deca1bfda83c1b9223aaaedbfc
+
+Count = 275
+Adata = 966954582e78e99ba68d6ffaf794b55a82325834ec4f373b2bd227
+Payload = 15b94910853a8f23dfb8b31c0262b8461f777075cc0937e9
+CT = 2328cb94072b99311e0525990801df37e4a647056a14f04e12937871932a7ca3e1e27a90a7f73694
+
+Count = 276
+Adata = b7aca715dcc402565cb711b001f21e8e95ec54c4afab2e2dcc8a2f
+Payload = fd1681cc306518bf77766f55226afac3eb21e31ed897075c
+CT = cb870348b2740eadb6cbf9d028099db210f0d46e7e8ac0fba0464ff4ddeccbd523a5ed3b32337f7c
+
+Count = 277
+Adata = 290a36f7daeeeafca4431446b396dbec0bea0a1f6f081418811656
+Payload = 0804fa48fc76f98bb021e3501bef8875b64a3b508adf8594
+CT = 3e9578cc7e67ef99719c75d5118cef044d9b0c202cc242332f68ed5e44a71c5ba8bade07b7bf5495
+
+Count = 278
+Adata = f0739a855422310a21ed863376bce9d75dc7c687b9b535cb7a05cc
+Payload = 4f5c6d80a3955f12f4d2594e02a045c42fabb11d90817fff
+CT = 79cdef0421844900356fcfcb08c322b5d47a866d369cb8583b5dc1fbe32743e257b7c1c9d624adc8
+
+Count = 279
+Adata = ffac0edb0b62977bb5040e4128a48deaf711f5e6a84d8f677341f3
+Payload = 5c29c458212d010a0d9c5a547aba1138eb4ce94742fef01e
+CT = 6ab846dca33c1718cc21ccd170d97649109dde37e4e337b9e53b654de1976294897cae0476ac6248
+
+[Alen = 28]
+
+Key = 6351a67fd6daabd2fd49ee944dd41dd37301f958dd17fcc3
+Nonce = b8d517b033754058128d13d11a
+
+Count = 280
+Adata = 511c6924fa96db716f6b053b7a48aebdc1504145a56cd02d6be2590d
+Payload = 0c0663dd69ccbffbbd0c8c2e9473d0354451ae7a20fa3695
+CT = 19f2745df5007619c79c84d174e4521b942776478a0601d982c560fede4741e2fd3b54b3a48f3e38
+
+Count = 281
+Adata = d9ccd93317441e9d6ccc358f31e7e2ccef8c921b23d742993eff9d53
+Payload = 34a882834172924d39d2df5d637d9d273a99a9222971701c
+CT = 215c9503ddbe5baf4342d7a283ea1f09eaef711f838d4750ee82d927a2aa678e792acdeb615409f8
+
+Count = 282
+Adata = c268d65f7a7b30d3d198b2045fc8d1db7adda56604fa567d8855d1a5
+Payload = 5b7450b73d68de079e92bba56c7860f11126b8fdedd3334d
+CT = 4e804737a1a417e5e402b35a8cefe2dfc15060c0472f04017a48226389d24ed3ec3da2da1a9bdf7c
+
+Count = 283
+Adata = 4c2b6815156f0643b4573825e28b9f2a668a4976e3342884f48bc310
+Payload = 140c6933248f052e05bd4a36aec185ee86730108cc2989b6
+CT = 01f87eb3b843cccc7f2d42c94e5607c05605d93566d5befa16fe6bd83993ccbdd50e1ca061f4845f
+
+Count = 284
+Adata = f11c873354b3c0cff2c8f8010e9e364582b9c05c62efdefbdcc2e1c0
+Payload = 2a083de317380d94dd991349a7b8761c7c98013b1b0227e0
+CT = 3ffc2a638bf4c476a7091bb6472ff432aceed906b1fe10ac577c5893cb3896400012e48f5b190b73
+
+Count = 285
+Adata = d0a056754098d7f7ef2f639d61ea3d2b9cc936c48a1b2c5a9e96d169
+Payload = 02769283d5a06c363c2cc66c09b1ac954134e3ec7df773f2
+CT = 17828503496ca5d446bcce93e9262ebb91423bd1d70b44be80c80101fdfe6dc4cfce080bf921582e
+
+Count = 286
+Adata = 56de0e55653b9a04a3ded71c31f8807c3c8dd96bc82892e4acccef30
+Payload = 4890404bc5b24822b4cf7a2fe28abc52fbefb919ae0629ec
+CT = 5d6457cb597e81c0ce5f72d0021d3e7c2b99612404fa1ea0122dfc20e3088dcd33b6706a0c1fdfa8
+
+Count = 287
+Adata = 794a86f5b20d344ad86fd5523d08f1864737be57731440c29aa6b425
+Payload = 161f8501f59338f72026815c77cad6d8d581859192cd5644
+CT = 03eb9281695ff1155ab689a3975d54f605f75dac3831610828f0a78ce798448529afe26eec875aa6
+
+Count = 288
+Adata = b1eafc03ea2fa3e9e3842a09a225e83055de8a1f412badd6fc9ead12
+Payload = b3f38aedbf08dd7ead9d402c5aaa1ec9279c7e4bfd4a2967
+CT = a6079d6d23c4149cd70d48d3ba3d9ce7f7eaa67657b61e2ba48856a266c0d404474316f418f8f4e4
+
+Count = 289
+Adata = 8fec99f1be0e69267620c0b934bf984d60c1437f74c6ac19610fe188
+Payload = 5c09e2a6a055fe9c21e06e5519cf56b8e2e7fb44094e79f9
+CT = 49fdf5263c99377e5b7066aaf958d49632912379a3b24eb56412292d8015285efaa6f1154580eb57
+
+[Alen = 29]
+
+Key = 9a5a9560baed3b8e0e90b92655d4e5f33889e5d7253d9f6c
+Nonce = c0049382cdd8646756d4e6bff5
+
+Count = 290
+Adata = c95a86d52088a8b0107cc5b437a8938b2c9e74e46e2e03bb9bceecdbe3
+Payload = 5bbe9c1fb2563e3e82999fe097b28da4dc6ff2e020f3b4f3
+CT = 6d5401db42b5c48b79203b6ad82806d7460ac4c82ad0809b811020480e834f6fe55900a162a4e61a
+
+Count = 291
+Adata = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193dfa755a5943
+Payload = 8a85a9b32a323c6af156a3fa2f1448b6387cc3660aa8a0f4
+CT = bc6f3477dad1c6df0aef0770608ec3c5a219f54e008b949cba9827513c7f1de970d316b6f81c109d
+
+Count = 292
+Adata = c834096e059ea73ddc90b0c982f9a3a31bfc6b1b81a03f9d41c9c741e7
+Payload = 1e02c13104937fe084b18eba1ea8951dcc5e75b692937dea
+CT = 28e85cf5f47085557f082a3051321e6e563b439e98b04982c9d79dd3255a8323f8229ac1c6d76ae4
+
+Count = 293
+Adata = 9249022bdead3d86ef5bd03acf053132d08663ba1f2426e19c126b22e9
+Payload = 3225570fb15ae13a13c71e364ae9a9fef03d1c9a7fa5dfa0
+CT = 04cfcacb41b91b8fe87ebabc0573228d6a582ab27586ebc8425dc81f93257ae8399fc2d48b4a7685
+
+Count = 294
+Adata = 3c3a92c4ece49fb9f84243d7c1bc91f595fce118305a758c83985c34b4
+Payload = fa0a458174537ddba25708b8d0c22d5517d57b122517b0c9
+CT = cce0d84584b0876e59eeac329f58a6268db04d3a2f3484a1b595003c58e69600c2a3b9ec45c0e15a
+
+Count = 295
+Adata = b49b845ccf76acf508f9db8543c73375d530d91f3b0e4ed70decfd2c2d
+Payload = b7fbdaeaa3ee1d0bbf5ec47898b069ec4ba6a140a3e83996
+CT = 8111472e530de7be44e760f2d72ae29fd1c39768a9cb0dfe0da009261c43c6640303696655e2981f
+
+Count = 296
+Adata = 3aabdf589eeb1709bb3d60b08bc71eaa3ffeba4e2903a5dbd8339aae85
+Payload = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7e
+CT = ac001b7d0b3a47f0ff578aaf4ad3c9c0a759edf04836ef16dfdcdbd4ad711c493d3176f032a02af0
+
+Count = 297
+Adata = 6a79879cd62bd1dbf9609897d2ebf2dc4dda43cc15fcb241aaa0deb4b3
+Payload = 3a861638ccd6591e51e2a525be59447e4a28bab32e36a5f3
+CT = 0c6c8bfc3c35a3abaa5b01aff1c3cf0dd04d8c9b2415919bfd59b45c05873c670f5f8bb47732d59f
+
+Count = 298
+Adata = c5b6ca474eb251817ae4d2f47c0632c381e222aae3b6f585a0dcae120a
+Payload = c7da4e9ba6e5758be726e6e227d7bddb0332228f7e3ecb6b
+CT = f130d35f56068f3e1c9f4268684d36a8995714a7741dff031572a24bc00b40a6b4b172b3648142e7
+
+Count = 299
+Adata = 64a96d191f1d5f95f5fed6259e33e7206adc07b0279e16cb453a9c6438
+Payload = 2b9347d3e195152dce22afdb92acd179eb484872285704c3
+CT = 1d79da171176ef98359b0b51dd365a0a712d7e5a227430ab828bc33396179ac39ce0027a1d62e0fe
+
+[Alen = 30]
+
+Key = 3e61094c80df0053e86d43fccf4e1d3ee2cdb862d3237b0a
+Nonce = 63f00b2488809fdc49ca5f05d5
+
+Count = 300
+Adata = a08763ca936abdeece06467bef8c3c47c3a473636a039d4db540c867d3e3
+Payload = 1fada8f4c7daea0d1c370184c169485b80a278708ed41451
+CT = 680dd22f16a1290bde42c9792dfa997aed24d5bd2265b6e095aa6b99d3f894d3790c2aa2dae1ba2c
+
+Count = 301
+Adata = 19508a6c83b992c660a1a28597e07c729ea2ed39401aadbf9d7586b5720d
+Payload = e9f1f2cf0b8d563e2d20f39f9f464a808b136dba364a6446
+CT = 9e518814daf69538ef553b6273d59ba1e695c0779afbc6f72d9d77109f4597e9c4c8cf7023dc5f3b
+
+Count = 302
+Adata = e5929c3b5d68a4c9fcf1168ea35bf8c0bf3043cb1ed54ff301578b3b7266
+Payload = 07a74c3b874849ecbf013713b80a84337c90b690cea0b837
+CT = 700736e056338aea7d74ffee5499551211161b5d62111a86b2544ecc3c7d5accd22ac075e7b44d5a
+
+Count = 303
+Adata = caa5cc5d0d87680eafc29429bac55c9e33167d485789c7c124b5c57a1ba8
+Payload = 4255f2cf90f0d15e9bead4be799165c57f7225980713d609
+CT = 35f58814418b1258599f1c439502b4e412f48855aba274b8f1a8a1db25de0fab7cabb11a18497584
+
+Count = 304
+Adata = f61cf7ae23a66777bd3fabc3d542feed2b00c6d4f46a772fda11b5214551
+Payload = 70b1e2e4cf260b108f5a52d0d8234838ffd6ffe7b4acd78d
+CT = 0711983f1e5dc8164d2f9a2d34b099199250522a181d753c5a9718ed0257a50e38de86154054fc3a
+
+Count = 305
+Adata = 85f647d940a6d1acb6b7851912f807063515631eaabaa019dcfb993e86f4
+Payload = af4be10b3a59ea99dadc75fbe5651f6f7630852bb556aa39
+CT = d8eb9bd0eb22299f18a9bd0609f6ce4e1bb628e619e70888550d1acca34c28ba8a3b890bb0542b23
+
+Count = 306
+Adata = 296cd04c4d9ab493def7aeb6841a45309e777028868efe45166235c56b2d
+Payload = 72d5663727592f1bfc9c65be83f4d3508126fecc4e34ae72
+CT = 05751cecf622ec1d3ee9ad436f670271eca05301e2850cc3a268dc1596a7855639c63fa76ad8479b
+
+Count = 307
+Adata = f380ca0a26a94adcf2c1ce26d226d3bf520268c72412e58a71acd9a66d00
+Payload = 3e2ccce03c10ce1527ef8e002adb265edba5779fbd4fcaf6
+CT = 498cb63bed6b0d13e59a46fdc648f77fb623da5211fe6847e3416c75fc28924a21cc123e62a7894c
+
+Count = 308
+Adata = 8825532a31680cb3b5bdb027802d2d8718755e135367e0c8c88e21288311
+Payload = a18dfe7f2d7bbaf316366f67445170afcbe18e2a1de1e947
+CT = d62d84a4fc0079f5d443a79aa8c2a18ea66723e7b1504bf6ff1a47f23d08485951aab18b393584ef
+
+Count = 309
+Adata = f768375589b687fb17c56673af4263626da69eb991007d94d4f5a163fd05
+Payload = 17ca72a440c944fefd6c08ecc3a8ecb54d96b9cad9d2aa4c
+CT = 606a087f91b287f83f19c0112f3b3d9420101407756308fd7d024456bcb69a4f77008773a3f48805
+
+[Alen = 31]
+
+Key = b5664dd6ed435df006052f6ded74bb7ce9482ca9229886f7
+Nonce = 7a1649896f3e030c18f0205599
+
+Count = 310
+Adata = c5f1a26351e53e6509c8bbbed03c42c23ad81c65fccec7ffa1cb494c7f1fc4
+Payload = 0b6de49b530703affc94010c2b793ddc6de0c44d48037ff2
+CT = 56b02fea595cc24e798691ae905be3d466ca68ca744005dba260b5ea3b047020b73b5bafa17e5084
+
+Count = 311
+Adata = 89899be18b4c389afa769b11ecd22e9fad8f38fd614ea5f8eb7a066c0ed8d8
+Payload = 2f1821aa57e5278ffd33c17d46615b77363149dbc9847041
+CT = 72c5eadb5dbee66e782151dffd43857f3d1be55cf5c70a685e4bd97b9dc83134867c00c2acea0aaf
+
+Count = 312
+Adata = d43b841f174335f1347834590b0984a2cb35f7a00a0ee993157d2d4f848748
+Payload = c7da4e95cb38342c6d5bf0c381d5a192adc3bfc1cda3a1d7
+CT = 9a0785e4c163f5cde84960613af77f9aa6e91346f1e0dbfe55202ba34bb9918fe915776de65947c0
+
+Count = 313
+Adata = c1093518efd80245e3c42371f220b21f2034e6738fe02ef43e828190f01aef
+Payload = 414a70aba5a219dbd41cdc46b84812b28cc4f7399218004d
+CT = 1c97bbdaaff9d83a510e4ce4036accba87ee5bbeae5b7a642fdf807b5a6880f2d4c36d558b40eb90
+
+Count = 314
+Adata = 90f627d5b939625bc76fe1bd4643b39edc11d3dc7f4bfe16e61bc26c3d49d8
+Payload = 58b260d3f645a35bad7a3842440bc03608248bd46e725e60
+CT = 056faba2fc1e62ba2868a8e0ff291e3e030e2753523124495a9307ca4239380a45bb7f87e41c4cf7
+
+Count = 315
+Adata = 2f360a4715074e942244ab7f9b6db127b0442df9af2efa2e78db1a94312905
+Payload = 5505caa97218957e90247fde60275bdafce4b16bcb36c263
+CT = 08d801d87843549f1536ef7cdb0585d2f7ce1decf775b84af3aeadff9dd60468aef2a8e2c56dda7d
+
+Count = 316
+Adata = 7db564811f14bc5c2098d5635655c3671fbd8288ea14944af925eaec653408
+Payload = b93e40f556a786e39126b8834a6ecacd2dc9f0f528bab135
+CT = e4e38b845cfc470214342821f14c14c526e35c7214f9cb1c8335f2e31a0468b830c5009cd02dbd5f
+
+Count = 317
+Adata = 36be91854d3d02a5d62503bb9047ef4354280510f7576c4272fd757240b621
+Payload = 543a070fdb3a855dd7d83fbc5f983671ad9e905f307148e4
+CT = 09e7cc7ed16144bc52caaf1ee4bae879a6b43cd80c3232cd5d772a599e91504e022b9dbfb124b71a
+
+Count = 318
+Adata = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb8813ccc2f2dd96
+Payload = 86ef67572cb339c6706eb5909b96848aba5246a196972a1e
+CT = db32ac2626e8f827f57c253220b45a82b178ea26aad450379846cd12430f7adc910d1f0c51d80636
+
+Count = 319
+Adata = 3a64414c3588d7c26871d7d054ac6c8420d4917e3baad4a343685916265321
+Payload = cecef24b62676a5623bedae8087b9b05d7e22b41a14dd2d5
+CT = 9313393a683cabb7a6ac4a4ab359450ddcc887c69d0ea8fcd9ee65ac3a8fae1b00a4f1dfe2577293
+
+[Alen = 32]
+
+Key = 50925853a84a33ff392154e4e737efc18dcfc98f4d5235a9
+Nonce = 809343e986f6ff47f54d4cac22
+
+Count = 320
+Adata = d70aef3532bdc5293a3ebb11589ac1f801c9f93ea0d656e1d04068facf9f768b
+Payload = 718f061e8b972a3adcf465d66c5b28e8661f080127f6722f
+CT = bad3b0e6772e9c4c9c631c095e259d99692292932efb72b8966e91a19617bb748f3495aa433585bb
+
+Count = 321
+Adata = 1ee0eb409398bc252175cb460ef9a2da4c9beab2ef6d8206e4fcce74df785246
+Payload = 72e6cebdaf88205c4e74428664bc0d7eb4687a272217b7ca
+CT = b9ba78455331962a0ee33b5956c2b80fbb55e0b52b1ab75dc8f70aa565a12ca3545e68110968040f
+
+Count = 322
+Adata = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698b0ed5c8cb09a8c96
+Payload = d959dd38a458039e2400d21d27b9a2faee8fe23683330cb5
+CT = 12056bc058e1b5e86497abc215c7178be1b278a48a3e0c22daf38076c810e14a7843444a02f010e0
+
+Count = 323
+Adata = f555216840a1f40b411d44128e567617e2694caf16216ea74c604a8d6ec01e72
+Payload = 337f12e8ebc0544b82fcdd3c4a0dab0e5e75c9f433a27d66
+CT = f823a4101779e23dc26ba4e378731e7f514853663aaf7df1594aebf9b8318877bdec2900a22df858
+
+Count = 324
+Adata = 2311a6fe1feeda3a1f16310d635496c0dd662024f0b0f1de79325e030cb850e5
+Payload = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb4
+CT = 8d60d302875518204538f90eccb4ec7651d51698b6ca2c231d9872d1c10a6594b5c349b84f710d64
+
+Count = 325
+Adata = b2c633e3181ae5fe7828707ed5b70e0460088a84465eadeecdbcfa0e9ff19bb1
+Payload = 23c1732959c4bf85bc707e45cc964b6227acd3a8fc73e675
+CT = e89dc5d1a57d09f3fce7079afee8fe132891493af57ee6e2a9db7c4bcaf6087e158c1a5d4eb1c2cc
+
+Count = 326
+Adata = 791f23252094b9b99fafe7fac1d8ff3ba09305c476041e75afb245ac438b4069
+Payload = 02f60f967e7fbcf957313619882407ea8a03fc943062296c
+CT = c9aab96e82c60a8f17a64fc6ba5ab29b853e6606396f29fb5e1c87d9e1c1f3b7d30fdc2f0ccac783
+
+Count = 327
+Adata = 22197f9ad14591e7a6d5f8b18c969a553de9a85309757fa5d319cc505c24f438
+Payload = 6c1aa088d1a6086d0e72636744a6840c80ab8223409c61b7
+CT = a74616702d1fbe1b4ee51ab876d8317d8f9618b1499161201514b449a741e07f9287f7e9090fa54b
+
+Count = 328
+Adata = 0bb18f7280a30767cd769cb5ffd3edd1c18914b92d1b2192e27ac88f57135616
+Payload = 57275bc3b4d63b9b01b0b0760235c9785d45761cace23f1e
+CT = 9c7bed3b486f8ded4127c9a9304b7c095278ec8ea5ef3f892c889b610157e16e9f31558c669298a7
+
+Count = 329
+Adata = 3e5f0f32e27be18ca6f84de11e6e9c25fc0c4cb0cf83633eea1f033aa1373f3c
+Payload = eba27a27f0d4604a5296a41b3fe995c50c66bcba302d0447
+CT = 20feccdf0c6dd63c1201ddc40d9720b4035b2628392004d0fbe19321dc22c748a17aa5eda29d8cf3
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp
new file mode 100644
index 0000000000..af4f5c1df7
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VADT256.rsp
@@ -0,0 +1,1823 @@
+# CAVS 11.0
+# "CCM-VADT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Plen = 24
+Nlen = 13
+Tlen = 16
+
+[Alen = 0]
+
+Key = 26511fb51fcfa75cb4b44da75a6e5a0eb8d9c8f3b906f886df3ba3e6da3a1389
+Nonce = 72a60f345a1978fb40f28a2fa4
+
+Count = 0
+Adata = 00
+Payload = 30d56ff2a25b83fee791110fcaea48e41db7c7f098a81000
+CT = 55f068c0bbba8b598013dd1841fd740fda2902322148ab5e935753e601b79db4ae730b6ae3500731
+
+Count = 1
+Adata = 00
+Payload = e44b4307234281209bd41f89dbe2cc3fbf68e14df2f7fce4
+CT = 816e44353aa38987fc56d39e50f5f0d478f6248f4b1747ba003abc6a4b020625adc8b6cd7bafbd42
+
+Count = 2
+Adata = 00
+Payload = 8db7a73856bcb4007346bb3e00096f69e75e97c0bb960f3b
+CT = e892a00a4f5dbca714c477298b1e538220c052020276b465e7cfa7a208a8b3e6b6377236045df17d
+
+Count = 3
+Adata = 00
+Payload = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e676d44
+CT = 2dd6c9e8563298008cba3be237c67ffb68f59f97c787d61a81b39a0c55822e32042b4f8981021090
+
+Count = 4
+Adata = 00
+Payload = 7cdb2c9b167b3ae811289acf7dc1814bbe241f553447699f
+CT = 19fe2ba90f9a324f76aa56d8f6d6bda079bada978da7d2c1091117e2ad77db510d902038743b5a98
+
+Count = 5
+Adata = 00
+Payload = 41eacf70d05a6d0cdbdd38f197a52987def8fde37f332eeb
+CT = 24cfc842c9bb65abbc5ff4e61cb2156c19663821c6d395b5ac7379b8e51592b98e4874f4592278a8
+
+Count = 6
+Adata = 00
+Payload = bde9e3eb9f0c57302c9185b1cb912ef76d88f2f9c3b51e9a
+CT = d8cce4d986ed5f974b1349a64086121caa16373b7a55a5c4d08c1c902c4c2f078452dd6943b85028
+
+Count = 7
+Adata = 00
+Payload = 6f9ccc033c6bfbdfad4719ad033c927e2175727a9a021dc6
+CT = 0ab9cb31258af378cac5d5ba882bae95e6ebb7b823e2a69832fefb87445f1ca42811899acc0cdf68
+
+Count = 8
+Adata = 00
+Payload = cc67bc3b7afd625b2610226d3b30e111e6aa47a3254f711a
+CT = a942bb09631c6afc4192ee7ab027ddfa213482619cafca4481d605a1019c8e9778b8928b4636053e
+
+Count = 9
+Adata = 00
+Payload = a10c81725f49ab9075fbf4d96be030a2d881d8501b115d61
+CT = c429864046a8a337127938cee0f70c491f1f1d92a2f1e63f96a82e8411e5b04426dc608298c6408d
+
+[Alen = 1]
+
+Key = a4490ed6ab51dbfccd6f3702a857575dad44da3a27eaf31178abc97da60d1e4b
+Nonce = 26ceaf6e3b28190a17c4f0c378
+
+Count = 10
+Adata = 9e
+Payload = 1b5cc6b1651dec4bbbf5130343852e971c7ff1774100d9be
+CT = 789bce069a725a96c484e64a9e54dcb7a7c268c85df47815a462ff2dd8ba44a381e1f6edab12b5a9
+
+Count = 11
+Adata = 4e
+Payload = e7ab98901c0cb1d7d76e125d8ac8e86edf6f469fa937bc10
+CT = 846c9027e363070aa81fe71457191a4e64d2df20b5c31dbb6b0789c5866b7e3312ad992e228d6d20
+
+Count = 12
+Adata = cc
+Payload = 53bc7e3648d0b389b887b065e9e8f79685beb2eb36e2eb95
+CT = 307b7681b7bf0554c7f6452c343905b63e032b542a164a3e39b1b1a480fdd268c1c75b131cde798b
+
+Count = 13
+Adata = 45
+Payload = 6d7262476da95db63b322c5193ea05030923c3cbf0f8e8b1
+CT = 0eb56af092c6eb6b4443d9184e3bf723b29e5a74ec0c491a32060fea35c3e9528fd18994fae9fce8
+
+Count = 14
+Adata = 2c
+Payload = 8246bf7b81b287411777df7ecb53a1795e54b150ff3dd584
+CT = e181b7cc7edd319c68062a3716825359e5e928efe3c9742fb4e0a604ab30a764e8c98a9cafbca8d4
+
+Count = 15
+Adata = a9
+Payload = 2596ca8772bc69b50bcbf33088c6efbab614b691ed836f92
+CT = 4651c2308dd3df6874ba067955171d9a0da92f2ef177ce397ca72f1acf6dfd078b6f4eb82fa01e9b
+
+Count = 16
+Adata = 85
+Payload = 703065d701f4fcadee20d64300b3082c0c76490eb2dc4ba7
+CT = 13f76d60fe9b4a709151230add62fa0cb7cbd0b1ae28ea0c2a85c9252ee62612dc29cffa7289b2ca
+
+Count = 17
+Adata = dc
+Payload = a1aeda4b4cb8dd2943675181561bac48ba07e8de5b327837
+CT = c269d2fcb3d76bf43c16a4c88bca5e6801ba716147c6d99c9fbdac729413152c089d3939e30b8602
+
+Count = 18
+Adata = ce
+Payload = aa17341f4cead054d41c171dd34c459f7052da225c6c365d
+CT = c9d03ca8b3856689ab6de2540e9db7bfcbef439d409897f6f86266c273f8184e901b50c04845b8ab
+
+Count = 19
+Adata = a6
+Payload = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f
+CT = 274bd52b4497d536191e2f7f65f40159339a43830fbdc0b4ddd02d5c9ae2bbac47a7a076edb1d207
+
+[Alen = 2]
+
+Key = df594db94ef8eca56a417afe946085eaed444c7cc648d07d58132e6cb5bc2bc3
+Nonce = c1ad812bf2bbb2cdaee4636ee7
+
+Count = 20
+Adata = c0c3
+Payload = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259
+CT = bea778540a90033b2c0d087e3cc447711ea25f7eea96855506ec97f23bd6ea97834f92f7263c3195
+
+Count = 21
+Adata = 34b9
+Payload = f6c043c70136585d012ae0df6f42b25584e374649d0116c5
+CT = bcb0ac1ca69079500eeb5d1a4b21c21820cb45216b0581c9f3230df0b52b5cb7ac907dcadcb662ca
+
+Count = 22
+Adata = d4ab
+Payload = dec0c896b04490816409da1783478ef2510231d0a28c5b39
+CT = 94b0274d17e2b18c6bc867d2a724febff52a00955488cc35a99c3165ce83102891ef3885088ed6eb
+
+Count = 23
+Adata = 2a3a
+Payload = cbfd94fc31785d30214271dab2264134805fee6e52aa0b5c
+CT = 818d7b2796de7c3d2e83cc1f964531792477df2ba4ae9c50c9d8078607994ae5dff0de6526fb53d1
+
+Count = 24
+Adata = 4eb1
+Payload = 134d2d9726400d09dd3521326f96fbef993ddc0c40887700
+CT = 593dc24c81e62c04d2f49cf74bf58ba23d15ed49b68ce00c7e84da7d2564533e7ad55390ec3a6ff9
+
+Count = 25
+Adata = 0a79
+Payload = 1ccdcf789d42caba80d7893feaf26d3853fbcaf7d964df0b
+CT = 56bd20a33ae4ebb78f1634face911d75f7d3fbb22f604807520849295a56191367a696999ffef8e9
+
+Count = 26
+Adata = 865f
+Payload = 4042dbe148db3e6dc542b25d57a5787af535d38e8c34c71b
+CT = 0a32343aef7d1f60ca830f9873c60837511de2cb7a305017bc4aceed1a10309b6402b9e9420b33a3
+
+Count = 27
+Adata = f4ae
+Payload = 85b6894fec36294aa934cdc3523fd95c90ad56cbd18545dd
+CT = cfc666944b900847a6f57006765ca9113485678e2781d2d176c180d2e299ccf0b8781ba6de8a72ce
+
+Count = 28
+Adata = 10bf
+Payload = 0f27f4fc8538a676a763b3e5db845a1bfb20d5fab340dee3
+CT = 45571b27229e877ba8a20e20ffe72a565f08e4bf454449ef98d91c68d94873a5d6557611a5402a0a
+
+Count = 29
+Adata = b92e
+Payload = 1b5ec0cb03810a12fc6a0a1ff565afb001405d2a45a1f18a
+CT = 512e2f10a4272b1ff3abb7dad106dffda5686c6fb3a566865321cedf1122354636e130acbd69718b
+
+[Alen = 3]
+
+Key = d98193ab2a465e3fcd85651aaeca18b8e91489b73b7c7e93b518c4b5b81fc6ac
+Nonce = 2247dc7e2674e9e0a63fe70613
+
+Count = 30
+Adata = 4dc2f4
+Payload = edba7d6312144e90ec9eaace7576045a46e553dcb8ee5a98
+CT = 44b9ea727c847336fd739ad11f4b906b292edb810462f06ef59626ad5cdac2e4d4cb07b538a1fd8f
+
+Count = 31
+Adata = 2f3bf0
+Payload = 52a9626f5279c11e17e96f5dc5e1c1f58c1e913020d8499b
+CT = fbaaf57e3ce9fcb806045f42afdc55c4e3d5196d9c54e36ded0d53402253453e494ad350994ca77a
+
+Count = 32
+Adata = 95d2cf
+Payload = 87b6447d97a74d0b315031078aa06fffc7b9f246bfa5f147
+CT = 2eb5d36cf93770ad20bd0118e09dfbcea8727a1b03295bb196dbc3bff865a1d94b164df23d708e8e
+
+Count = 33
+Adata = 0caba9
+Payload = 1852848046706f2e274ba381a2bee1422df4f61d93219af7
+CT = b151139128e0528836a6939ec8837573423f7e402fad3001791b4469fe50d45f8efb81217cd68580
+
+Count = 34
+Adata = f8d459
+Payload = 99aac82fa66a15e4f76b76cf4590150999d5cf8468df7f42
+CT = 30a95f3ec8fa2842e68646d02fad8138f61e47d9d453d5b4587106da25012f92f01cc2db8d11ac29
+
+Count = 35
+Adata = e883dd
+Payload = 4e2f0f91990b855a00d27fbb2e8db7184cd82909de361b52
+CT = e72c9880f79bb8fc113f4fa444b023292313a15462bab1a464148536847290e4fdda7966fe6d5e3b
+
+Count = 36
+Adata = e45da4
+Payload = e558be3fd246170b294d18ffa708842242681890baf8bed9
+CT = 4c5b292ebcd62aad38a028e0cd3510132da390cd0674142fcc4cb33472825363940e2b26424b7802
+
+Count = 37
+Adata = 3b6fc8
+Payload = f8b284c2d851289275973fcd807fac5d8e5e3b6a75ba2ace
+CT = 51b113d3b6c11534647a0fd2ea42386ce195b337c9368038a99dd8dbe89b3ecf663eda1b0f92be7f
+
+Count = 38
+Adata = 043d68
+Payload = 8edf1eb90f0ad33be8a7c6446899e06addc10b3badc4ea25
+CT = 27dc89a8619aee9df94af65b02a4745bb20a8366114840d3dc4894c8fa0a1e1aa760acf9360042f5
+
+Count = 39
+Adata = e89257
+Payload = 8fe9a6bd82462c97f436d382d1ff971c95406b1a6c847d81
+CT = 26ea31acecd61131e5dbe39dbbc2032dfa8be347d008d777cdad1590fd8bf2d7ea919e60d0316566
+
+[Alen = 4]
+
+Key = 45c8afd7373cb0f6b092af3a633d9fd97c4ca378e19d75f9b74d089429726c29
+Nonce = fdb1fa230ae0b172ff98fc7496
+
+Count = 40
+Adata = 270981af
+Payload = 0b92adbb251dc29a67f0bb97f8e7160862b6c4e843d07fd9
+CT = 274e2faea3271ea6fa0494c1951f115b5491a893056c3ee4c76fc350e585277e373e9119bf9595cb
+
+Count = 41
+Adata = 633f3efa
+Payload = 1f88dfd4f5c52c22b1db47f9f4fb6e2f8bcd78d593061369
+CT = 33545dc173fff01e2c2f68af9903697cbdea14aed5ba52540fa7e55dc54e80488a05ee7f1fc96e9d
+
+Count = 42
+Adata = aad86fb5
+Payload = b2b4cb5e90ebf4bd265093b7f5efd4d62dc60e29737aa496
+CT = 9e68494b16d12881bba4bce19817d3851be1625235c6e5ab18151c17d9e3f97244000a3b2d3c2f95
+
+Count = 43
+Adata = ed42941a
+Payload = f312b47d05f8eb5a29943b41347cb1983c75cb7a458a3868
+CT = dfce366883c23766b46014175984b6cb0a52a7010336795562d521c4b5c7a6f2c5ac65f2fd15b066
+
+Count = 44
+Adata = e5b085d8
+Payload = e9fb86938ea7f04cc230296859e7c96fcc352f968c9473e4
+CT = c5270486089d2c705fc4063e341fce3cfa1243edca2832d9e491a31218f688744098851672a09a64
+
+Count = 45
+Adata = 3776f37f
+Payload = 8af6b7540f997954812e38dbd99ccfaedd5c69963c353a4e
+CT = a62a354189a3a5681cda178db464c8fdeb7b05ed7a897b730ece28347d7ebf8291d7eb66b7651b4e
+
+Count = 46
+Adata = 4eb08c9e
+Payload = b90cfd9dd58e320d98510483b1d939bdb5f3b81666ecee59
+CT = 95d07f8853b4ee3105a52bd5dc213eee83d4d46d2050af64cbd25fb40480d15c039878b5d2f25afb
+
+Count = 47
+Adata = c7f93152
+Payload = 02caabc6ed0641681e7148c10cf3159fe35e44013252071e
+CT = 2e1629d36b3c9d5483856797610b12ccd579287a74ee4623fbfd98c8567b78d4b9c3a49a4641908e
+
+Count = 48
+Adata = 57957630
+Payload = 2f29882fdf1418d04f0b9d44272995a56973c4369c687a99
+CT = 03f50a3a592ec4ecd2ffb2124ad192f65f54a84ddad43ba4655c1abcb3ed1a175f12721a407c5d00
+
+Count = 49
+Adata = 19da955d
+Payload = 4e427130be9e94639320529ec135715e65da1117b5ba3c76
+CT = 629ef32538a4485f0ed47dc8accd760d53fd7d6cf3067d4b90621a5e5683df421a0dc52341485d1b
+
+[Alen = 5]
+
+Key = a2e6bf39efd1ceddc92b4333ed92d65efeea6c031ca345adb93a7770a8039bcd
+Nonce = 693cbb46bc8366086ec7cd7776
+
+Count = 50
+Adata = 3ba11282d6
+Payload = d822f84b023f12ea9e3ce16b904278e4aaab5e11c2c23f3f
+CT = 9f91fd2f6472e33b02b1eabb9d6655729d44c44dad6b3883fe0667bcc5806b225224b04ade8b21c1
+
+Count = 51
+Adata = 3f3a4718ea
+Payload = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12
+CT = e834b623d3d3c675b88d41d09d59e6595dbad43bed00b9aea6750fffa5a487540ce65770cd836e99
+
+Count = 52
+Adata = ff79ca8965
+Payload = 82b7cd168b6a82cb2d837f41ceda0c27adc5f5b28030454b
+CT = c504c872ed27731ab10e7491c3fe21b19a2a6feeef9942f7e7cfafe32bd71ea9813607c5df446c9d
+
+Count = 53
+Adata = 0021be18ed
+Payload = 1c1a0f144df76781e7c85ab178ed9b1ce8c6dc3f15c59149
+CT = 5ba90a702bba96507b45516175c9b68adf2946637a6c96f576716fe674c33ad3b9d3e54cc86bfccf
+
+Count = 54
+Adata = 9ae7996547
+Payload = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841
+CT = 9e0874c9f658dc8d867e53185d3b85088aa48de3205d3ffdab55dbee34f1bab555bbb196095fb5fd
+
+Count = 55
+Adata = fa292d1958
+Payload = fc7d028a1aa05c74b7ffe333ba6f676913b0f9f1ffa050b8
+CT = bbce07ee7cedada52b72e8e3b74b4aff245f63ad9009570476a4e9e759d5bb79c187a157099e3d12
+
+Count = 56
+Adata = 88800df7b6
+Payload = c9ea772e61742a6706da3ab3e81df14b31506ae58b063ece
+CT = 8e59724a0739dbb69a573163e539dcdd06bff0b9e4af39729f0f3699c9743ad6c9f09dc00ea10487
+
+Count = 57
+Adata = 715041afd4
+Payload = 70d2b8d64121ceccf1961444e8d33b7b7f998aeb58d3d270
+CT = 3761bdb2276c3f1d6d1b1f94e5f716ed487610b7377ad5cc560d78cba6d9f50e9c2677a710f92155
+
+Count = 58
+Adata = 14682301a9
+Payload = 1013946815001a2c08acca4196e0d6668ffbb3883cf111e7
+CT = 57a0910c734debfd9421c1919bc4fbf0b81429d45358165b95ffb6e29172a283d47e4478e2e1f7c4
+
+Count = 59
+Adata = e44c3c21c1
+Payload = f40dc834067bd163e0004d0ec5dd4b96e2a1ea31ea431c98
+CT = b3becd50603620b27c8d46dec8f96600d54e706d85ea1b24ccf233caf0bad9f68f71d78ee58512ec
+
+[Alen = 6]
+
+Key = c5a850167a5bfdf56636ce9e56e2952855504e35cc4f5d24ee5e168853be82d8
+Nonce = c45b165477e8bfa9ca3a1cd3ca
+
+Count = 60
+Adata = 4759557e9bab
+Payload = e758796d7db73bccb1697c42df691ac57974b40ca9186a43
+CT = 93ad58bd5f4f77ac4f92b0ae16c62489e4074c7f152e2ed8a88179e0d32f4928eff13b4ce2873338
+
+Count = 61
+Adata = 2ea07d393a0a
+Payload = ce60ddbe40b70bd55a9147036ad079dec1558ef4c2c625b3
+CT = ba95fc6e624f47b5a46a8befa37f47925c2676877ef06128b7d812c4d69f1f53ee9158382e56625b
+
+Count = 62
+Adata = aa6667faedc1
+Payload = 89eb3056770a6157f06921bc153834447c4b6d862d10d185
+CT = fd1e118655f22d370e92ed50dc970a08e13895f59126951e26fdbed62b228db008a1b14bd7942e12
+
+Count = 63
+Adata = 9e2127d92311
+Payload = 132f3e19e12f462a7463226b716c41a05a59c76f0e1a2f72
+CT = 67da1fc9c3d70a4a8a98ee87b8c37fecc72a3f1cb22c6be9124e1eb78de01b8af83b684baf3e43ad
+
+Count = 64
+Adata = 2f191bc9cff6
+Payload = b8611cbb9a3667b9458ca57eb636eb1dc580e7dbb5701692
+CT = cc943d6bb8ce2bd9bb7769927f99d55158f31fa809465209cb0f79736d1a810d06a776094f9fb67f
+
+Count = 65
+Adata = ad739d5f4736
+Payload = 112f89ccbdadc2433008d3ede2290f9ce81e5c736abf42a8
+CT = 65daa81c9f558e23cef31f012b8631d0756da400d6890633bfba2348f629471c232c9ff7e5f6f85a
+
+Count = 66
+Adata = 01acc909b7d3
+Payload = d47f2ff745de39a9055ad002de6334971fde480bef268b33
+CT = a08a0e27672675c9fba11cee17cc0adb82adb0785310cfa8c0f694d03ffed043787343827ea2603f
+
+Count = 67
+Adata = ce003c836a6f
+Payload = 13be365884b8a91a284ca24f70011e48794b51be275153b9
+CT = 674b1788a640e57ad6b76ea3b9ae2004e438a9cd9b671722279b553998a6fee0a86e177a448573a4
+
+Count = 68
+Adata = 6a759a4efd00
+Payload = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e
+CT = a13d5db4b781965f9dd065b0790f42dedde61cce68d673f54eeb434cca3ea719827417e94d6ed564
+
+Count = 69
+Adata = 02b84a26c773
+Payload = b7bc1580c68fd5d06c1bf75c31dad7a3e26d636d7eee20b9
+CT = c3493450e47799b092e03bb0f875e9ef7f1e9b1ec2d86422a74b5e4e2edb91fbbe722bfaf1500db4
+
+[Alen = 7]
+
+Key = ae8f93c3efe38e2af07e256961dd33028faa0716e5320a7ab319a10d2f4c5548
+Nonce = 6333bde218b784ccd8370492f7
+
+Count = 70
+Adata = 0b1fabdf2a4107
+Payload = bc9ca92a9c9919e39095d3e53fb148694620ae61227e0069
+CT = 45811b0c8f754bf03950e520cd4afc81c2e3eb8a11f4fd386d5a6e4b1fbee15d35939c721004502e
+
+Count = 71
+Adata = 2fc7f5c0ce052f
+Payload = f25a4ca20bbf4969bed6b93c1c77e3d7415f60fe3784216b
+CT = 0b47fe8418531b7a17138ff9ee8c573fc59c2515040edc3a24a68f98716190fb55f743a8bf62a085
+
+Count = 72
+Adata = 8a74412da3034b
+Payload = 3237bf953989d17c65a0fafd2bb1e32c237f98f55389e8f8
+CT = cb2a0db32a65836fcc65cc38d94a57c4a7bcdd1e600315a923afef7b4955d7d1e8f1abef9933bf9f
+
+Count = 73
+Adata = 7139f3c1d6cc36
+Payload = 55d86dc0423cfc2616ef996a3316e776707f8d25c985884a
+CT = acc5dfe651d0ae35bf2aafafc1ed539ef4bcc8cefa0f751b8e824c62632dff5cbc103d3060fbd174
+
+Count = 74
+Adata = af7a380f079aa1
+Payload = ac48398adb10292314973946f261ec39397442ca09b98dd8
+CT = 55558bacc8fc7b30bd520f83009a58d1bdb707213a33708980202d518ca871c9544f4a8c55fd8d20
+
+Count = 75
+Adata = e602abe8f72964
+Payload = 2fb78654e4395df8c37f260d74def234a3a4e3d2b1fe8614
+CT = d6aa3472f7d50feb6aba10c8862546dc2767a63982747b454b33ea6e4344033f74f513d1e41b82ae
+
+Count = 76
+Adata = 82741c5fd6e1df
+Payload = d488bdda400932de56a9f105f0e74ee79c2ed869faaadc31
+CT = 2d950ffc53e560cdff6cc7c0021cfa0f18ed9d82c920216073ccf18c7ea7dce79d0be1204c593234
+
+Count = 77
+Adata = 78f0cc22535402
+Payload = b22aba8d3e9f4b4bf006e26062de15daf94597731a600912
+CT = 4b3708ab2d73195859c3d4a59025a1327d86d29829eaf443b81b8af57b85093778690266e20e2fbb
+
+Count = 78
+Adata = 18e468139dd16f
+Payload = bd864f7b8efd6ed2b068f425482d449bf53a203ea88e1ca1
+CT = 449bfd5d9d113cc119adc2e0bad6f07371f965d59b04e1f09b94a857e7a0423ef6c9cbebde1f9c40
+
+Count = 79
+Adata = a6dab47c0fbfe1
+Payload = 47d9d18b6addc5f88986f0457b666faae59aba4fa3a02abb
+CT = bec463ad793197eb2043c680899ddb426159ffa4902ad7ea64718820065a739fbd3ba560a416895c
+
+[Alen = 8]
+
+Key = 548c2d1eb7d91e003633d4d9ff199e4a8447180edd89ac7867d25a1db288b5ce
+Nonce = 23b205bd6ff8ed0bab0c98999c
+
+Count = 80
+Adata = a6601111cd92c943
+Payload = 49fd5cbe4aff89dc3b8718f9ce545d612cbbebb289ecbf42
+CT = 3cfc6211e359ae322802fc9566f377b0dfe17d1dfe0878ebf2a9047e37cc0be1fab0006af8db8dc4
+
+Count = 81
+Adata = 96f0b7cd7439721d
+Payload = 94a95e945f660d1571b4d7d22709b000b45ff98b2129a4ae
+CT = e1a8603bf6c02afb623133be8fae9ad147056f2456cd6307106a430b04938e97f2e4cda81108ad3e
+
+Count = 82
+Adata = 2ee135dc2ddd9501
+Payload = aeed3aea01755c912213c8c276a2b75dad24f888a611efa3
+CT = dbec0445a8d37b7f31962caede059d8c5e7e6e27d1f5280ab2ab219c6c4952d52505cd9f904b0e04
+
+Count = 83
+Adata = 10c361934fd6ff77
+Payload = be1fcebea4c22a1d71e08047b028d7f4ccab0a6b8085d344
+CT = cb1ef0110d640df36265642b188ffd253ff19cc4f76114edfc1f7b2fe314faea28ab0dae349feb9c
+
+Count = 84
+Adata = 3f6c8a69917f7776
+Payload = 87680ac26fe1511e0f1f745aa4c2a5b9f6c0117dcf08feaa
+CT = f269346dc64776f01c9a90360c658f68059a87d2b8ec390308e529d64e786a29661cccddc0366f3b
+
+Count = 85
+Adata = 0f7a1426ff3b5ee1
+Payload = 9e004b072a27b085e59ca201c157c7d3c906a2c3b455c56e
+CT = eb0175a88381976bf619466d69f0ed023a5c346cc3b102c797c6510b85dfd097f3eac276aff00ba2
+
+Count = 86
+Adata = faa5bed84dcf168e
+Payload = a1bf47b15cd66e43daff420edf014a14b11994b97ada4030
+CT = d4be791ef57049adc97aa66277a660c5424302160d3e87998e522b6f13f99ecb553b6de845940907
+
+Count = 87
+Adata = 2851dae3cb3fcb1c
+Payload = 2d15734871adc63ff32d7002ab40c4a235a4d5fad223953f
+CT = 58144de7d80be1d1e0a8946e03e7ee73c6fe4355a5c752967a9ca39566189ee96c86462bfea78af5
+
+Count = 88
+Adata = 35a29c1bcbe2182f
+Payload = 5a84c4fdd47510fb7aebc0f79d7b625ccd0a96575740b8e6
+CT = 2f85fa527dd33715696e249b35dc488d3e5000f820a47f4fa613b5fbbe73a2df6c630a00ff4b1b92
+
+Count = 89
+Adata = 45820ae66c3e8e77
+Payload = 2052a94e1392dc1db0e89be19ea8f7379ee4cb607a914c89
+CT = 555397e1ba34fbf3a36d7f8d360fdde66dbe5dcf0d758b20d19feb067e9f6225376da21b4899d296
+
+[Alen = 9]
+
+Key = aab793e377a12484dbdd74c9b3a85c74c286e1cc498663fbd7c718b5633bb91a
+Nonce = 10022cddb323e88b3c08f95a0f
+
+Count = 90
+Adata = 82b8c736037ce2f2e8
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1044250f58857c69f72b5d3454d43949e5c02b3822970b280de1a3f7fc5d06cc30f06075f5504ed7
+
+Count = 91
+Adata = 8f2777ec4930f7e349
+Payload = bd845561f099500a6ff3fd09964dc3820f7ab48ba4ed04d5
+CT = d1c8f9ebee44ff231485207e684b0e65a033db29b082ac45835840df6fa96f5c972ac09d94148cbc
+
+Count = 92
+Adata = 5cab3b846870709569
+Payload = a6e09404fe60badfc63dc228057485e6f563ba82acdabd7c
+CT = caac388ee0bd15f6bd4b1f5ffb7248015a2ad520b8b515ec2f83ef84b299cfdb61d2b5039d536c3f
+
+Count = 93
+Adata = 0938f2e2ebb64f8af8
+Payload = 33404d7e0e620c1030b91020e33619c5f53d8b210fa86489
+CT = 5f0ce1f410bfa3394bcfcd571d30d4225a74e4831bc7cc19db04e655cbe22b9ea508d2a03757b97c
+
+Count = 94
+Adata = 82f78ca0e0da2b2d3a
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb9f087a50bf50
+CT = 0d34c4248f2aaaefcef5688a80188d610ef2f0aa6e3f17c04bd88dc6985f819004c2b634c5303ed8
+
+Count = 95
+Adata = 401191aa3fd34abe87
+Payload = 949cdd7c2973d7519e7bca98b2c5947e6d8e91c90e632319
+CT = f8d071f637ae7878e50d17ef4cc35999c2c7fe6b1a0c8b894ff3572e4ebf78473760d8cb4b0366b4
+
+Count = 96
+Adata = 4df4377596d8987671
+Payload = f6720a0bd8705c70e0f923338965e810b3ea939bad652327
+CT = 9a3ea681c6adf3599b8ffe44776325f71ca3fc39b90a8bb7de95ec3eee17753e60fb3c0661bdd098
+
+Count = 97
+Adata = 6593194b9970545c5a
+Payload = de9b0556661e726f3e6e34515ff7196420fe61b4f38419f2
+CT = b2d7a9dc78c3dd464518e926a1f1d4838fb70e16e7ebb162b8590ff04f967e51fbd1be84f01b4dcb
+
+Count = 98
+Adata = ab2d432058b540ac72
+Payload = 6cad7f3b9f196839bbc5a7f755c09aa8e17c83d9cb8b3954
+CT = 00e1d3b181c4c710c0b37a80abc6574f4e35ec7bdfe491c471d67b75b2da855a12ffb24ddd64a048
+
+Count = 99
+Adata = 5dc631eeeacb5a0b0b
+Payload = 70a55aec1144357377612fd0bbc2c817f33465a656219957
+CT = 1ce9f6660f999a5a0c17f2a745c405f05c7d0a04424e31c71fc798dd16c1fadef607a9297cbfbfef
+
+[Alen = 10]
+
+Key = 06ac39896073a44283611a66ccab067e2dd2faa8da82ff9a45bb29e54d2e6e77
+Nonce = 6c7942c9819cf69b817bfcdb0a
+
+Count = 100
+Adata = 215e2a6c24325340fdec
+Payload = 3216dce3b8b1ce0e79e40fffcac728ab191aaaf319d971d3
+CT = c5b3b50ed8a7b7b96b02ba9464b6a2ff80e90548605699a63d70e6dffb31a376a1eb7f94526dca48
+
+Count = 101
+Adata = e0a29a2c7840cf9b41de
+Payload = 7e5e5710a693ebfa36335cf7965574740880acdddd13fb1a
+CT = 89fb3efdc685924d24d5e99c3824fe2091730366a49c136fcbf516608fe20e06bbff931e84683545
+
+Count = 102
+Adata = b8026fbada6339d84802
+Payload = 08c342a50aa23362622934dfab55d9b22c22c249ad08138c
+CT = ff662b486ab44ad570cf81b4052453e6b5d16df2d487fbf9d70eb14f3fa0229906b9e0360be3d3f9
+
+Count = 103
+Adata = 65f4b3a00c1c1ef39445
+Payload = e085aba85882c75d5e41559167731496cf17d3907894352a
+CT = 1720c2453894beea4ca7e0fac9029ec256e47c2b011bdd5f4184771199a427861bf17cd8401e794e
+
+Count = 104
+Adata = 96118dbfe53434d8aed8
+Payload = 710f890be2b8da77c1eff429ede9cc931d50f059748cbcb6
+CT = 86aae0e682aea3c0d3094142439846c784a35fe20d0354c34e20b2db52fde68f88bfb886fdcb2c47
+
+Count = 105
+Adata = cdf4b485d2e04709cf8f
+Payload = cda96efee4e188ab3048bc1904ac2c36ab018f2ab7602682
+CT = 3a0c071384f7f11c22ae0972aadda66232f22091ceefcef782ee3df38ddea8e269eb47e39900345e
+
+Count = 106
+Adata = 50e57e57cf8e49e3a4e6
+Payload = 3dc596d52e520779a50bcba3049388b340dbf6d0f2eb94cf
+CT = ca60ff384e447eceb7ed7ec8aae202e7d928596b8b647cba44aaac4ed86f687cfc031f22827725f1
+
+Count = 107
+Adata = 48c670f11ff7f74e7003
+Payload = a33105c0dccf8e3b687212a870af9f710462756705fe09b3
+CT = 54946c2dbcd9f78c7a94a7c3dede15259d91dadc7c71e1c6d75255006ac037d6a4d048f1fc338012
+
+Count = 108
+Adata = 465e3be6113a2fb2ee20
+Payload = 573ac2436158eb7dd9be981e3cfbe75d3a188ea9cf2b1ee2
+CT = a09fabae014e92cacb582d75928a6d09a3eb2112b6a4f6976c1da33a80bc8157cece1acf9400b2bb
+
+Count = 109
+Adata = ee4e10574faeae85e9b6
+Payload = ca35bdb54e73eac5a5200a296b3aba5f37c87349746102d4
+CT = 3d90d4582e659372b7c6bf42c54b300bae3bdcf20deeeaa165c1cb98da4a1a920ca1ed9a7b6ec514
+
+[Alen = 11]
+
+Key = 50412c6444bcf9829506ab019e98234af1541061557412740bc120b456052763
+Nonce = 85684f94c3702c5d870310166d
+
+Count = 110
+Adata = f706a3e09df95d3e21d2e0
+Payload = 6cdbd63f6d591f59776f828533b28e2453a214d1d0dd8a39
+CT = 8c8b4ae854a5d5c265b25e3b54bded9444cc454b3e0e6a24d6c05eaf406a5ebd578e19edd5227380
+
+Count = 111
+Adata = e46b25b9a41a858e87900a
+Payload = 100132c315bfc9c4fb93023f5d3500d7208a68acb4d2c630
+CT = f051ae142c43035fe94ede813a3a636737e439365a01262d5088446e42591c0ede68e82334d97cfa
+
+Count = 112
+Adata = 28d34b29afe6586fd9bf0e
+Payload = d5460c1db0d24dedc63c4c78ce6d1f0b2d46f3b01934525c
+CT = 351690ca892e8776d4e190c6a9627cbb3a28a22af7e7b2413eaaef2823f5ac3f313f560bd774d10e
+
+Count = 113
+Adata = 2852d4fd68a3e9e47d44a7
+Payload = d2d73b62e3b1c9ab75f3544ff8616741e0adbae84b8cf9d0
+CT = 3287a7b5da4d0330672e88f19f6e04f1f7c3eb72a55f19cd62d30d99bb7dadec34e2891c156a1f5d
+
+Count = 114
+Adata = ec1c17b2ab13d7c8ac874f
+Payload = 74796d78d6ad03634ed80800af530212baa7e5093651cedf
+CT = 9429f1afef51c9f85c05d4bec85c61a2adc9b493d8822ec241c9a05ebf9ed27792bbced83b5dc582
+
+Count = 115
+Adata = 4f1ab5ddb1c199e9a5daab
+Payload = fb432488b5d08d576a90f085181ad883407a6ce9ea29950a
+CT = 1b13b85f8c2c47cc784d2c3b7f15bb3357143d7304fa75171ffc24020e86b1314724104e6b57b3ce
+
+Count = 116
+Adata = 864e0e728aea856fae6c6d
+Payload = 2b82d96ed1778412378abe4e09c633acf3359b9709ae3dcb
+CT = cbd245b9e88b4e89255762f06ec9501ce45bca0de77dddd6539bbb0af8ecf77b4508533247b3501a
+
+Count = 117
+Adata = 21ee21a5ed0d75d0380a28
+Payload = 85143071241bb65261fe7afcc102416e59b9e46ee0c90073
+CT = 6544aca61de77cc97323a642a60d22de4ed7b5f40e1ae06ef8981ec6ce7c4687b178f2103fa8c8be
+
+Count = 118
+Adata = 2b63f7b676f13f45d103dd
+Payload = 185577b48237acbdaa3590b8057fe374f875ce829b62c98f
+CT = f805eb63bbcb6626b8e84c06627080c4ef1b9f1875b1299265d9d899c6b71c0ab3049ea1dbfaf6a9
+
+Count = 119
+Adata = a33e86d813c2c4ff3bab20
+Payload = f051beb936e60fd4f3bca31964f1ad3e6fa16dd27b65a6db
+CT = 1001226e0f1ac54fe1617fa703fece8e78cf3c4895b646c6b246474c4e79822f5fd55f2fb0067a40
+
+[Alen = 12]
+
+Key = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0cb00b1abade1b5ce0ed
+Nonce = d80210b9f9776ea36dc0e0a787
+
+Count = 120
+Adata = e4296d1c8cf4ffc4b2635135
+Payload = c825952293e434ea866db558aaf486ef09a92bf366988f71
+CT = b8b3b15fdf6a4a0b5abc313afc769e4e8413bd887552583ede3ed995d1b70561c8e28a7b1a7e3dc8
+
+Count = 121
+Adata = d18bfcc1584eeb8695388ebe
+Payload = a1e0248355bfd1d881fb1a4798cda2f6f6ad513c69c5f9b4
+CT = d17600fe1931af395d2a9e25ce4fba577b17c7477a0f2efb561575f6743c5759494be59afa0c3e11
+
+Count = 122
+Adata = 14682301a99bf680805d1ffe
+Payload = ded135fcbf62219bfba2cba40c2d2cbe4815ddaac1342231
+CT = ae471181f3ec5f7a27734fc65aaf341fc5af4bd1d2fef57e34f689367228cbaf3cd76fb407109cf6
+
+Count = 123
+Adata = 8853aa2dfea9c4d370678bb6
+Payload = 12d3900c6c01968b8344762e0e883e5e219f42b052dc6215
+CT = 6245b471208fe86a5f95f24c580a26ffac25d4cb4116b55a2cacb7fc3856abcf759feb8dc0998ab1
+
+Count = 124
+Adata = c5d3b9c593c3185fe4b6d1bc
+Payload = 8c3c1193fe1a1ebad7e01a1eed1a32c08a0091b1c948e184
+CT = fcaa35eeb294605b0b319e7cbb982a6107ba07cada8236cb42a740cd3262424a2c3d77849ead6149
+
+Count = 125
+Adata = dfb9e8149b51f89b1ec00a8e
+Payload = 8219618b7728ac89237705ecf84012cc7c80293c4cf171d8
+CT = f28f45f63ba6d268ffa6818eaec20a6df13abf475f3ba69747d4dbe0f9415d40843070e1e93059eb
+
+Count = 126
+Adata = 08a4590d262e4dbcb7e23ffc
+Payload = b344b7dc239617fa51b9ea10a349e940c3163779f5284c9c
+CT = c3d293a16f18691b8d686e72f5cbf1e14eaca102e6e29bd31215b3dccba4ca5de64be7fab8a7a22c
+
+Count = 127
+Adata = 74aab7b5b96238710637c6e5
+Payload = 740d4b25ca7221d0826057701a6bfd66c50a82f010a57be8
+CT = 049b6f5886fc5f315eb1d3124ce9e5c748b0148b036faca734e09945ee44c95c7923d8b9249ade7b
+
+Count = 128
+Adata = 420aac47a3f212fffca40549
+Payload = 5d9000489186abdf4f0a2794f0222fcaa156fe6309c10f79
+CT = 2d062435dd08d53e93dba3f6a6a0376b2cec68181a0bd8360a568dd779526a0058d522af1dafde30
+
+Count = 129
+Adata = 6e80dd7f1badf3a1c9ab25c7
+Payload = ac2c44263363810bec3a309aa618b303e05099dfdbeb5c16
+CT = dcba605b7fedffea30ebb4f8f09aaba26dea0fa4c8218b59279442c88d612ed1a39ae0005f88155d
+
+[Alen = 13]
+
+Key = a4cc7e1c90f8684e6a5f95e6898ab4e3c194cb46e196d8228062b9f3fa744930
+Nonce = cdc2712e51c7f333d6bad78eee
+
+Count = 130
+Adata = 569c56b27268d3db54e728aac0
+Payload = 10d4cff95ef490923c9e0906880729d4d05412e7675cce76
+CT = be3ce3e9dc72499839a98ae52abb17415e8547687e8a3c7b8aaaac20d4c9276f2851cbba2b04d185
+
+Count = 131
+Adata = d75635b6450e43285fba966835
+Payload = c9db03e2efbab713b0b640421018d3971ffe2abd70fe8fa1
+CT = 67332ff26d3c6e19b581c3a1b2a4ed02912f7f3269287dacc121ff83891335dd1214ea6fc25f6a68
+
+Count = 132
+Adata = 70750acea6a05f8b7b425d262b
+Payload = add631ce5846ce71434aad4998f8e429aed430e7d38bdbb2
+CT = 033e1ddedac0177b467d2eaa3a44dabc20056568ca5d29bf549e71ec517cd65150f42b3cb53f936e
+
+Count = 133
+Adata = 2a567c7ec7edaa5a438ae3bb35
+Payload = a514d170422feb1d87bb7725a9e77cc6fc8afb45c2af6d90
+CT = 0bfcfd60c0a93217828cf4c60b5b4253725baecadb799f9d0e432ec394ddbb65205dc40a5a8e90a4
+
+Count = 134
+Adata = 0f8795385b805246a0a2573afc
+Payload = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d
+CT = d730a80a3ab4a07849d4ddf9280170800fb9897c917dbe30926b0d977107a3918717f79b63f36b0a
+
+Count = 135
+Adata = 111d224c102b136159fbeb44a7
+Payload = 2edd498e54b23aab6f4fd7b3f22c4c787e3a4f1fb06c9ec7
+CT = 8035659ed634e3a16a785450509072edf0eb1a90a9ba6ccac2cd61599bb93db3dd3dabc12aa90932
+
+Count = 136
+Adata = df0821c9ea6ab329c626d11b4b
+Payload = 6e3e25db29da2c787bb37755ee770e2402fb8208da23389d
+CT = c0d609cbab5cf5727e84f4b64ccb30b18c2ad787c3f5ca90bd027ecd00cc6dc5ffd5d746d92281e9
+
+Count = 137
+Adata = aacaf4839c35338d6e2b47ac45
+Payload = d4ed4584678e982ace8664e77d0e55be356be558cead3755
+CT = 7a056994e5084120cbb1e704dfb26b2bbbbab0d7d77bc5583c01354a450eda2588be7578530e38c0
+
+Count = 138
+Adata = dc6eed3f8bd1b5563c1eeb9afa
+Payload = 4ebf00eadaf70711f630f5badf0214d8518a200afb0e5765
+CT = e0572cfa5871de1bf30776597dbe2a4ddf5b7585e2d8a5688d7a1d546e25ba026cd46556eb2c4b7e
+
+Count = 139
+Adata = fbfe7e910f242a78dd6e69a2ec
+Payload = 2729636112f2abe2c76ea5e52a3f80b0f882f0f3b6f7c806
+CT = 89c14f71907472e8c25926068883be257653a57caf213a0b0e951aee790239e7067ef37f497b4bf4
+
+[Alen = 14]
+
+Key = 347e12eec56e95aafcc7d25bf10fc756b4e42bc2e43da7f97df24331f27f1f5c
+Nonce = b8d517b033754058128d13d11a
+
+Count = 140
+Adata = 511c6924fa96db716f6b053b7a48
+Payload = ca88dddfc876a12f45f19562bc9ca250f43267ab251a7f34
+CT = eeedcfa8f5b5b48c1d7e277526eecb7294213b9f5785167ae949b93003dfe63c95c1d49edfb4de3f
+
+Count = 141
+Adata = 10c26d5939618189a9503623f55f
+Payload = de0c0d17c3950e7f8985b56d60623cbd010cd765da4df5ab
+CT = fa691f60fe561bdcd10a077afa10559f611f8b51a8d29ce585c32a90d77fed97eb0ac164ed616e1c
+
+Count = 142
+Adata = bc09c59d20e55a9e184d70af2c7c
+Payload = 2f35102d78a32fcde1cfb563ea8d310ecb83c146ab8de362
+CT = 0b50025a45603a6eb940077470ff582cab909d72d9128a2c180fdf5f63045f326057cf74fd4cee6b
+
+Count = 143
+Adata = b75887f13d6e8c4b35b27b965693
+Payload = a3fcce3420effdd6edb37271735a0d30c10c65233aee173f
+CT = 8799dc431d2ce875b53cc066e9286412a11f391748717e7134959a180fc2cf2ba99af21cc1bc8e5c
+
+Count = 144
+Adata = 603401a9b8ecde4d5c86b6107363
+Payload = 4ac918727e41b8c536484e3781c403e260c278712853508d
+CT = 6eac0a054382ad666ec7fc201bb66ac000d124455acc39c32ca2e5195dbd44f0a119538c95788510
+
+Count = 145
+Adata = 7206b06f306124ca3a302e84c5a6
+Payload = 97d770cbb2c42a552e450cc4e35e5668b2ff89cec735cc91
+CT = b3b262bc8f073ff676cabed3792c3f4ad2ecd5fab5aaa5df74a4e1198878a76291594b9826d4b563
+
+Count = 146
+Adata = b15efed90a5d1d62f545ac22af6e
+Payload = 86bb2ae50e36c72936240a74502172625cbca210cf285077
+CT = a2de389233f5d28a6eabb863ca531b403caffe24bdb73939ff5f993dcfbd048274da7439c0f9ef5a
+
+Count = 147
+Adata = c9eb714ed9858a8dc11a26ee3f00
+Payload = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17
+CT = 29a28be439bcc3447e851e5a1e0db26f765b631cc3a436590e87710559a375ece6ef2953b6aa2542
+
+Count = 148
+Adata = 07ca22271e95cb48a872046822b7
+Payload = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a1
+CT = dd35fb1a58664b58636c174a35892b389ac289562cab29ef998035c81716e2d1ed4b4d56ff18af5d
+
+Count = 149
+Adata = b65f6773516124317cfb4b1fcdf5
+Payload = e160e28e601a49d16db18f25410756b330b036c42e615fd6
+CT = c505f0f95dd95c72353e3d32db753f9150a36af05cfe36981ae73a9b6896d8fc1b8c0d772d632983
+
+[Alen = 15]
+
+Key = 520902aa27c16dee112812b2e685aa203aeb8b8633bd1bfc99728a482d96c1fe
+Nonce = ddf50502f414c1bf24888f1328
+
+Count = 150
+Adata = 22b4f8f1aac02a9b2ef785d0ff6f93
+Payload = 533fee7d2c7740db55770e48cb1b541d990ea3f8f08ed1a6
+CT = fc867b319e0e4ab45ec518a1b5dcec4f29982173f3abfd4d8a8f8d14d2bdac84c3737cfbd75b7c0b
+
+Count = 151
+Adata = d0a43de391d492746ecf322acd6e5b
+Payload = cced20b59a6b2c3c45ea6c87802440c9c47b1015e83d86c3
+CT = 6354b5f9281226534e587a6efee3f89b74ed929eeb18aa28fce59f5e6e3cee284b4cc747ff5ee13f
+
+Count = 152
+Adata = 3a789c06f87f05933c34a1cf9834a8
+Payload = 90939a4530181ad6900664f66bfc2ce0289432a0afe9babe
+CT = 3f2a0f09826110b99bb4721f153b94b29802b02baccc9655ddaef56d8255125f7c316c6c59ce779f
+
+Count = 153
+Adata = 785260973f112c56d9f891160c4c11
+Payload = 86cd926b9565b76a88fde73c31e9ac908ffd1e6ca30b59ce
+CT = 29740727271cbd05834ff1d54f2e14c23f6b9ce7a02e752555810cbcdf48f05d0a7808673c82d08d
+
+Count = 154
+Adata = bf6a144591c0ea7b10274fbd3345a1
+Payload = 6ecd1c1acc6290672f9cf639ed0cebcb21ed0c56f35a5ce3
+CT = c17489567e1b9a08242ee0d093cb5399917b8eddf07f700849e41e5d34a698ae1d96f16bc68da944
+
+Count = 155
+Adata = 7d9488b500d89a27f367f34a448a87
+Payload = b01e3f4fb5ee7501e8c2f4ccefb542ae20d7fd61a2c41c8b
+CT = 1fa7aa0307977f6ee370e2259172fafc90417feaa1e130601bc54e546d1a6fcf6187169feb1ea533
+
+Count = 156
+Adata = 060fc718e994edc7bac9962ca7f28d
+Payload = 22ab6a0daf953165dda864cceeeb782e275c0b072aedd284
+CT = 8d12ff411dec3b0ad61a7225902cc07c97ca898c29c8fe6ff2eb6c0ab42acf42985c721bfd576e71
+
+Count = 157
+Adata = cb6f96dd06015967279ade310a7401
+Payload = f96ed20b23c784015ff58f5f040798ca75e3b98045deca8e
+CT = 56d7474791be8e6e544799b67ac02098c5753b0b46fbe665ac502b8e65cc1329b6895afdd354f5db
+
+Count = 158
+Adata = 9aa6d501455019b4ef4c7fb789d22f
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = cb3311cd8ed070804105f7aa90ee14ebf6ae04ebf2ab9a9a87e5f8a8148f21adf721477c36bd99ca
+
+Count = 159
+Adata = ebd1d12bbd14176a0d4080aa1edb89
+Payload = 32d71e59634126ac6c6156a80a0dfa0175b29e9f40a31696
+CT = 9d6e8b15d1382cc367d3404174ca4253c5241c1443863a7dda9ea0427522dbeaa509a11755434760
+
+[Alen = 16]
+
+Key = 57da1c2704219ed59abfdf04743a9a93c87a63d471818de0f1564b2db6421562
+Nonce = 4b60a47b7e90f622fa0bf803e1
+
+Count = 160
+Adata = 0ae8c012ff39753510df3ee80707e4e2
+Payload = ddc3c1aa73fb6de92bb4db138e26f3c2e0543ab4f5924871
+CT = daa8256d4753fdf9cfef876295badaba89b45cc497f54d220ec2c6fb687753bca4580adc6aa2f296
+
+Count = 161
+Adata = d5b22e7697ba70e00c7ef32709563f01
+Payload = 34270576724083e9989764d08a0d5c1b4738f34927a1e436
+CT = 334ce1b146e813f97ccc38a1919175632ed8953945c6e1658f30b9c8e380c98bb939a4e8a85af758
+
+Count = 162
+Adata = 6b4edef415763aabcef01863e8197aec
+Payload = 904fe88e7a8e76447a64b488ef84184d0f1ab1b67f0c5a7d
+CT = 97240c494e26e6549e3fe8f9f418313566fad7c61d6b5f2e53e80d8ccc687fd303f4cdef44b6e8b9
+
+Count = 163
+Adata = 4c099809061024c010a77e9621fc2bcf
+Payload = 51fe7bac8f3255f17f64fb9322210fb7d8da8e762498b233
+CT = 56959f6bbb9ac5e19b3fa7e239bd26cfb13ae80646ffb7600c635dac5b70338dac3f33ce16a99145
+
+Count = 164
+Adata = 9d329439588164d5a96675a85c07a039
+Payload = eab6dbc13bb92df36b1882df2b8f34c3cefa41f95717fbd7
+CT = eddd3f060f11bde38f43deae30131dbba71a27893570fe84f996e8163affb1494bb3c12eeadf16b6
+
+Count = 165
+Adata = b768fc3daf29ff9e8bd575072d986e99
+Payload = c44c9c287d3eac7c30570d9c4adf2e4857c598f7c54cd126
+CT = c32778ef49963c6cd40c51ed514307303e25fe87a72bd47598b4206a9622d5631751a497dfb1f662
+
+Count = 166
+Adata = 3efc7cc2d16bf82d2bcfbc559a09b2c9
+Payload = c11b9c9d7607f387359c0038d3e8ec4d527562ce63c3384c
+CT = c670785a42af6397d1c75c49c874c5353b9504be01a43d1f7dd300167d267ad700dea37fb475ecdd
+
+Count = 167
+Adata = 0ff89eff92a530b66684cd75a39481e7
+Payload = cc17904b166f28df82f57889f391159a4a308e752d714ee5
+CT = cb7c748c22c7b8cf66ae24f8e80d3ce223d0e8054f164bb6303e9c9bd0d8e4aac42894ca03d6ab06
+
+Count = 168
+Adata = fbd11bc75759f0461e796f6917aeb42b
+Payload = 6f97e595ea2f40612ea84a2097b974d235055fe1dae59403
+CT = 68fc0152de87d071caf316518c255daa5ce53991b88291500953f46e0e9cf1369e9eb018a4df3c09
+
+Count = 169
+Adata = b79940952f42537484aa2907c72dffa9
+Payload = a48cbf933b88c0ec5ddcdd8fcad186391c2cbef308607de5
+CT = a3e75b540f2050fcb98781fed14daf4175ccd8836a0778b68a1702dfa0cd9c290c5ff9c35cc83705
+
+[Alen = 17]
+
+Key = 9267ebc99ccf648b146cba3c251187e24a9947d806ceb0ced6894211641a1e0d
+Nonce = 9b7298950280e8762ecdc9bbe4
+
+Count = 170
+Adata = 5824689453bc406bf891b85e4576e38fe8
+Payload = 967daf12f16f166b7b5038f83a1cf0b980f5abf4c7746f2a
+CT = 7cfe2a7a54306eb8d8a63d3d1ae86794f9a2c22198b2cb4f10ca926f1a430c08c12e23db3d913e93
+
+Count = 171
+Adata = cd15973753b94b77bb4b778de8b3b0cabb
+Payload = c4a756f6024a9dceabf6e264fffff9c719217fb418141ac5
+CT = 2e24d39ea715e51d0800e7a1df0b6eea6076166147d2bea05d5b674fd15410cc235dba6d8c8d82a8
+
+Count = 172
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3f
+Payload = e0d5de7d1eace211c0e70859ff315ff485d1200c6dd13f93
+CT = 0a565b15bbf39ac263110d9cdfc5c8d9fc8649d932179bf688750b5f36c86e7eda9015e960a7471a
+
+Count = 173
+Adata = cbbecf92551a15f5cf00a5be4a50b0eb17
+Payload = 05a4a4ba28fe8876f9bcfa5ec60651fd3fd4732f22049bd5
+CT = ef2721d28da1f0a55a4aff9be6f2c6d046831afa7dc23fb0d5fa842209dbbc04c87965f78500fec1
+
+Count = 174
+Adata = 873ba7f8b71517ec50297b21cf94cdb7a5
+Payload = 9cdebaeee8690b68751070691f49593668a6de12d3a948b3
+CT = 765d3f864d3673bbd6e675ac3fbdce1b11f1b7c78c6fecd67d147edbe114bfdb3f3b9b37d5719ef5
+
+Count = 175
+Adata = ac087420feb1e1e8c2546c2a8b8a5af0d0
+Payload = 5672e61cf664d73918dc1ca84df1fce82db0e305a61d57b9
+CT = bcf16374533bafeabb2a196d6d056bc554e78ad0f9dbf3dc57b4c2bbc377937d15b3b89543e29d0e
+
+Count = 176
+Adata = a12c690568114fd7a677f49d74e84fc1a6
+Payload = 0f5452e6b51540cf219998590995cd7f8785fa40b4f217fc
+CT = e5d7d78e104a381c826f9d9c29615a52fed29395eb34b3992e6ca774074b47b59adabeaf8835582d
+
+Count = 177
+Adata = 7a78ddfe5afb2dc90ee4a600c2fc014b0f
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae72f7
+CT = 7050bda358442a350db77d357ef4910f0dafd9670168d692bd320f48a7221537e3cbed5ac4154a56
+
+Count = 178
+Adata = 6053e466ed1f647a3cd88c4d2052ec00cb
+Payload = d17b8d556e83190c84d4a812957c64ffa7f336298f4e2c72
+CT = 3bf8083dcbdc61df2722add7b588f3d2dea45ffcd088881740574e201f9a26932a87c8d822505814
+
+Count = 179
+Adata = f7673e3beb526834d6507058fe62e34987
+Payload = 2eaef86b0f602364f86510eabc58bc9ad1e6f0a6f6df0b83
+CT = c42d7d03aa3f5bb75b93152f9cac2bb7a8b19973a919afe6837dfa3fdef2f012b6609de2ac5dd9d6
+
+[Alen = 18]
+
+Key = 7a855e1690ee638de01db43b37401dcd569c1ae03dc73dd0a917d0cadb5abc29
+Nonce = 8f160a873a1166c8b32bccbba7
+
+Count = 180
+Adata = 72674aca7eba2fc0eeafbd143c2c4d8aa6c8
+Payload = 33ae68ebb8010c6b3da6b9cb29fe9f8bd09b59ec39f4ce4b
+CT = b22afdf4f12c43ec23e01ac1215a3f5286059211207e957057e9a9203da74387a9468f8af5e27547
+
+Count = 181
+Adata = f7da3f100b80e2ade812f1700aab6b72f746
+Payload = dbb29817b86cb80e0d008742cedfbf52b236f15ee8cad50e
+CT = 5a360d08f141f78913462448c67b1f8be4a83aa3f1408e35a3985f12a49eac424a35c94645917e91
+
+Count = 182
+Adata = 4b05eaadf98505d0806c233b2cdcaf4254e8
+Payload = 145aa8cfd544a2f46bae1aa83cbdb3d21c3d1350078a3af4
+CT = 95de3dd09c69ed7375e8b9a23419130b4aa3d8ad1e0061cf4ab089a8724b87a1167180963d44ec65
+
+Count = 183
+Adata = 05a3aaa08b9a6aaeb84704431425d0e45a14
+Payload = 6b32e8906dc89194a69410b79cd041b62eb01afb28a3e10a
+CT = eab67d8f24e5de13b8d2b3bd9474e16f782ed1063129ba310a7d1520141892e140448292185c41c7
+
+Count = 184
+Adata = 74db01edc26a2d2044cb8eaad8b907b78863
+Payload = 545ed03588fd85a8bbfeee66d2082ae6f8e2f3c9dbd8725f
+CT = d5da452ac1d0ca2fa5b84d6cdaac8a3fae7c3834c252296472d3eee219d94bd788f62df4add5ec40
+
+Count = 185
+Adata = 5f2c6ddf5a2403e04dac8b2813c060b67e76
+Payload = 66dd5fd8611c551973a3d0c078ec2b4d39ad163d9168de3c
+CT = e759cac728311a9e6de573ca70488b946f33ddc088e28507c600496f4f8b1b7da118ee36d8cd57f8
+
+Count = 186
+Adata = a650a2a5e3c6f7c95614570aaefd0cdd9a42
+Payload = 6f364b3f778376cbf3f4b0b0c5350a8fa278f9d8c25faad6
+CT = eeb2de203eae394cedb213bacd91aa56f4e63225dbd5f1ed4710004d06ce7a7efbd19da4e3ce3cf7
+
+Count = 187
+Adata = 477c2484cf5c56b813313927be8387b1024f
+Payload = 3de4798d8ad84c460b92abc10b7f5e7c9fae46a1dd353687
+CT = bc60ec92c3f503c115d408cb03dbfea5c9308d5cc4bf6dbc304099641c4ec3dc2c54fdf4f48dbef2
+
+Count = 188
+Adata = 564e1df74aa2d7ee33b66cfeda810774e16c
+Payload = 7769b45fea11f530fb9a67f1b5b1964a34cfa32bbb03f4b1
+CT = f6ed2140a33cbab7e5dcc4fbbd153693625168d6a289af8a905c1b05e8945685f8688faea777eb43
+
+Count = 189
+Adata = d5e66502529b0045883d935e05acd242baa8
+Payload = 0c0a502b42f81b51806c7080a8155280f493f2922cdc7df8
+CT = 8d8ec5340bd554d69e2ad38aa0b1f259a20d396f355626c3ea5a3b6a8bafde4006b993cfb3b13557
+
+[Alen = 19]
+
+Key = 0ebdc6ddb4c502725dd6ee8da95d56a0d1044b4694d6ba8475a4434f23a8474f
+Nonce = fb717a8c82114477253acc14f6
+
+Count = 190
+Adata = 41e9d65632f74f449a6842d5e6c4a86ef83791
+Payload = c7360282c85484a5a33ab1c68dd70873ab4e74ffd4a62cd5
+CT = 2e961b3a2fa1609a4e6fd04bff6ac5e306ae2638706f997b42be2e2ba05c54b619850db5c9d684fe
+
+Count = 191
+Adata = 555304659bde926cb2553b8a4605251fcddd92
+Payload = 1332314d1cf783b9f64e0fa2d42d43d225da9fd5165b5f0a
+CT = fa9228f5fb0267861b1b6e2fa6908e42883acd12b292eaa4bbdee2605bc69601b1e83d1e7a0b400d
+
+Count = 192
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9
+Payload = f264da8606ea429e0e25da3f2efafe28beaff05b42097369
+CT = 1bc4c33ee11fa6a1e370bbb25c4733b8134fa29ce6c0c6c7304611baf530932da7954f714514d228
+
+Count = 193
+Adata = d7186a67061319b44eedc0677ebf5d932d5bce
+Payload = c9ee6482144dc61c43041324a2c18ede370011cb4882b0c5
+CT = 204e7d3af3b82223ae5172a9d07c434e9ae0430cec4b056b6d1d44e26404b7324767f0b3f7486f8b
+
+Count = 194
+Adata = 38f37d5e2da017f1953ff3701be0b38809ba80
+Payload = 40524a4d32a711e7d5a59809878c318f42b6e2375b77b8a7
+CT = a9f253f5d552f5d838f0f984f531fc1fef56b0f0ffbe0d095453724d2db19f606c85d00e49b0bb38
+
+Count = 195
+Adata = b3b2d249cd3517555fa692bbe9116f069e7405
+Payload = 961c15bd7dc34cd5409c9e8869988676ec6845ecb0ee85fd
+CT = 7fbc0c059a36a8eaadc9ff051b254be64188172b142730536db1e4112fcd650e8c0f0f6fbf2d07e1
+
+Count = 196
+Adata = f5b5bcc38efaff01f69bd3a106dcfca3cc6414
+Payload = 879568ab9ebdea768a5459ced1d3181d822536c3d1ba38c3
+CT = 6e35711379480e4967013843a36ed58d2fc5640475738d6d1cedb29e68322e47ff9997f859257d98
+
+Count = 197
+Adata = a2098e3e23826e01f31107a208202f710eff00
+Payload = 47cb57599686716c75d7ecef5541d20fb908e6d98c39925a
+CT = ae6b4ee17173955398828d6227fc1f9f14e8b41e28f027f41c12bf2a3571ed672592b27e986e9058
+
+Count = 198
+Adata = 20a3d53e77201599540344c4e746c3ae3a5f84
+Payload = 4a8667b5ee09d3d4a6dca9a95f4ad406f1da94b846dcc6b8
+CT = a3267e0d09fc37eb4b89c8242df719965c3ac67fe2157316f12b2be8f5966d96602111c28f87b104
+
+Count = 199
+Adata = 92c592ead4b3f193cc36687593d4f0f412a5d5
+Payload = 1dc9e32ac4176f64bd78a6edd651ebeea3ba85dfcd8298a8
+CT = f469fa9223e28b5b502dc760a4ec267e0e5ad718694b2d06776df0a0cf048892e65bd8ad77cb2255
+
+[Alen = 20]
+
+Key = 2ff64bbec197a63315c2f328dcb4837d0cdc21a5d6f89ff1d97cb51195330cd8
+Nonce = a235f8ee3de9896b71910ac02c
+
+Count = 200
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112
+Payload = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a
+CT = 1bf122798bd8ee8e73391d589bd046a294d1615794e69cb9e6f3ba30143acbc3a1c1c6ec74333107
+
+Count = 201
+Adata = 0248359f8071143c3cc1d61882a3547a0b3d2175
+Payload = 4a6a7151465c2abd7e7fa1fd13019ad098b6ebcd190e96f7
+CT = 1b8c01056a837081553cb646ef73115a3ddcd3a095074e6436cb510c13a039f4df8cc26a942f9911
+
+Count = 202
+Adata = cca77bc4cf6c0abd3393dac3fbe90fbc8a1154f7
+Payload = a94f5ede43929d48d2c5a58c3262d9127d2ac3cb2fbd5768
+CT = f8a92e8a6f4dc774f986b237ce105298d840fba6a3b48ffb7fe0dedc2899dff81a251cff16bf5897
+
+Count = 203
+Adata = 9c082a84646c070bb11b7d6b92b62f06ee5b5b71
+Payload = 7303bd41cf47289a3111366d08e8e21548baf293052029eb
+CT = 22e5cd15e39872a61a5221d6f49a699fedd0cafe8929f17886c43ac23800de60a1fd2caef0f03261
+
+Count = 204
+Adata = 1c3ede1982a807a410ae1e21947bf430f8db7027
+Payload = fa9743a67978c20316cb91801d7789e350079aae3aadbd43
+CT = ab7133f255a7983f3d88863be1050269f56da2c3b6a465d026f7907e235c09d3322c4092d2e88f88
+
+Count = 205
+Adata = deb05a30a026ff66ce71e98afa62f0255aef84f5
+Payload = 99599b4042dcdb685350cdecfdf24992fd5b165670025d0c
+CT = c8bfeb146e0381547813da570180c21858312e3bfc0b859f6bb44a28c145d49f49f2821d4044e4b6
+
+Count = 206
+Adata = 93dd9b00a3353e5331338dcfcb7ca7e0bb873a4e
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 14f771712219a85a79678ae220e5c0f9c4bf49c59c1507400f7d20aa3d792d6a3ebc5ee0df2fd89c
+
+Count = 207
+Adata = 0855263860043207543c8c34648d53ec51c4f47e
+Payload = b2db87b7787531968d603098cb20ca7c438b4af72623fea9
+CT = e33df7e354aa6baaa6232723375241f6e6e1729aaa2a263a7ca4733f0208668b0a7879305e861d71
+
+Count = 208
+Adata = ee2d3a66deb3ebca867a902bb9202226ed516ded
+Payload = ca18ce38086223e63b4f0b616d110010f9e45eac42f2ba46
+CT = 9bfebe6c24bd79da100c1cda91638b9a5c8e66c1cefb62d5d76b482ff20429da8f60f0f863e1af50
+
+Count = 209
+Adata = 8e531aaea849addab6a83497cbc504f489505952
+Payload = 5717ed5da5b8aa806a18bfe979502bab6632c9428d3a7725
+CT = 06f19d098967f0bc415ba8528522a021c358f12f0133afb6aab66e1ac2346ef97850a4985c64b737
+
+[Alen = 21]
+
+Key = 24e9f08a9a007f9976919e10dc432002e2e078a339677f00105c72ed35633a3f
+Nonce = 15977424eeec0ec7f647e6c798
+
+Count = 210
+Adata = 2d838eb51a4bc69a001a18adf2084a680f02a3c5fc
+Payload = d3416a81b4246eb0bf8119a72a886bbc0ac9449c69f71d2f
+CT = e001a8fae390dc5d672cdd18f86a1f728158ec83a002050def9af5679edbcbb7db20ab6af30698db
+
+Count = 211
+Adata = d83ee7ce22fd1a2882d8d552346e4d7b3efdd67da4
+Payload = 22b6f10b482448626f6c7bebb14f1497896d071738133b4d
+CT = 11f633701f90fa8fb7c1bf5463ad605902fcaf08f1e6236fd435a5a38f84387f63b13407f65ec86c
+
+Count = 212
+Adata = 2d5537b24d0b0f7a45703c1e131656ec9edc12cdf7
+Payload = d60edc830be8207ffd9e9f646d3b4343b10b3d56acb89d44
+CT = e54e1ef85c5c929225335bdbbfd9378d3a9a9549654d85662ede8a705f8c988f55459542bd631b1c
+
+Count = 213
+Adata = 1a750eb326923412d94ccb35f5acd0f87415268178
+Payload = 716d3132f449a9def383978102ae50ed3ccae0cb346ba1df
+CT = 422df349a3fd1b332b2e533ed04c2423b75b48d4fd9eb9fd986de774a612230ce6c71449d26732ce
+
+Count = 214
+Adata = b10fc523bc4562d44edfe5956f93c15c4ab38bba3c
+Payload = 063c2ae2a15f26f979bf90657d20643e3184f1a9f75a3aad
+CT = 357ce899f6eb9414a11254daafc210f0ba1559b63eaf228fe710431005264fa7d3fc04bac50fc1ec
+
+Count = 215
+Adata = fe4f60ce9634e7dbc5e56204c4bf8aa9be577027ec
+Payload = bdc513e56a5bb70c02abc041af04d6e45e735d10cc88357f
+CT = 8e85d19e3def05e1da0604fe7de6a22ad5e2f50f057d2d5d5c13bea6ad0cad724e6cd02c89517ffc
+
+Count = 216
+Adata = 48f3ceda4fd390a7eb38f7f5bcd14310af6b5a557e
+Payload = 7dc5d8cd90ce2faf76bbd0d52e5ae11b310fc2b0051c4377
+CT = 4e851ab6c77a9d42ae16146afcb895d5ba9e6aafcce95b55d2a5531655aae01e249f213e0e04af0d
+
+Count = 217
+Adata = 199ec321d1d24d5408076912d6bb2b6f192d6b347f
+Payload = 66c2696edec26ba3d07bd3f485a0d6ce8a1b0a85b20083e7
+CT = 5582ab158976d94e08d6174b5742a200018aa29a7bf59bc52a127ef341345f9641b26e91265e1482
+
+Count = 218
+Adata = 8b013f5782d5d1af8dbd451a4202866095dac975fc
+Payload = f4da8ac3e8fe5ec6a5b6a2f27b68396e850b46a024d441f0
+CT = c79a48b8bf4aec2b7d1b664da98a4da00e9aeebfed2159d2a005ca13c4bf715c3b7b2782f799b23a
+
+Count = 219
+Adata = e320df32b71cc530e8493b12b9afbeabc255c5eb44
+Payload = 244891cb4af66cc8e99a3784a2e82475e51bd5c7fde67cf5
+CT = 170853b01d42de253137f33b700a50bb6e8a7dd8341364d704642aff9cb9288d49f0e567dd837e05
+
+[Alen = 22]
+
+Key = 0ec1b22b8df05dc92135d2dfbefed8ea81458f5ea1b801e8a218faf6cbdf1a79
+Nonce = 97ebcb8575bb58260208d5c227
+
+Count = 220
+Adata = a2f6337f86dd00d1a58448851e95d8c9bace4a5c8710
+Payload = 2f59d94d4ab8eeb84c2a6fefb7fb0a3ac059c1e1a65ae34a
+CT = 7ca0b1dbe34b0391e524b868b0af08b3e096917664d6aa2cabc1f9d0132394149c9062b74b82f04b
+
+Count = 221
+Adata = abf26b05558252c8e38c52b1ace087bbd1eb3d561239
+Payload = c25381853f73a3dc4195fdcbc45dfa1a40eb8324749adb2e
+CT = 91aae91396804ef5e89b2a4cc309f8936024d3b3b61692486d7df57c6a792f6f6b24cb5f87e92123
+
+Count = 222
+Adata = a13ade56b47803897666e42ef2ef88be0e779ac86c28
+Payload = 8dc5226a2a13088c87f4bf94262e0c0413f06b35d2fda79b
+CT = de3c4afc83e0e5a52efa6813217a0e8d333f3ba21071eefd4ac19b0b74cd9d5e100598b96c9f1f2e
+
+Count = 223
+Adata = 3c5b68b65edf62755b7e064bd26c843816bf6c1cd481
+Payload = ee4b23039cd512cfab8c7a2d0f2c78d66764520bc88759e1
+CT = bdb24b953526ffe60282adaa08787a5f47ab029c0a0b1087a77a27eabfc79f192c0ac491280af8d0
+
+Count = 224
+Adata = 0213fe13c49083d7c00335e1864dc139c9e7123162d1
+Payload = 30b48d4021838090fbd5251069ff8c631452daee5ef899db
+CT = 634de5d688706db952dbf2976eab8eea349d8a799c74d0bd39935f91c1e29fc1e4c5c5427ca9da79
+
+Count = 225
+Adata = a32291746b151be8134e183798aa82bef210343feaf6
+Payload = 2286a1eddd80737a724ca941217e9f0232870b6c2f20d29c
+CT = 717fc97b74739e53db427ec6262a9d8b12485bfbedac9bfaaeaec90ada2a1ffef64c3873af645a40
+
+Count = 226
+Adata = a30f2fd445820cdf800145540602c877da0e4c311272
+Payload = fe703ca0901e4a706ce1393c7d8ce18a03eb2caadbfa7b8e
+CT = ad89543639eda759c5efeebb7ad8e30323247c3d197632e87932952831d0ba25c77c18fe154d8ed8
+
+Count = 227
+Adata = ed438e393e0e37629cb25044ae89de9fd0d42d60c1a3
+Payload = 7043c67726870bb5816da925925bc2722478311c8a606cca
+CT = 23baaee18f74e69c28637ea2950fc0fb04b7618b48ec25ac234fd0241d00f3890a23ccd0bf16dcbf
+
+Count = 228
+Adata = 1013946815001a2c08acca4196e0d6668ffbb3883cf1
+Payload = 695e9712dbbf883e9bf8af9188bd01fc631968928258168d
+CT = 3aa7ff84724c651732f678168fe9037543d6380540d45febaf43498b0c3f70c119f82d5812db940f
+
+Count = 229
+Adata = 44cc9b2510680c4d73f1938c77de21242c8ee790ed7f
+Payload = 67ba90d22c6bb5f649bc0c505c5ed23a299882559a3bf520
+CT = 3443f844859858dfe0b2dbd75b0ad0b30957d2c258b7bc46db66dbb03a4c943ac089ed11eb214bbb
+
+[Alen = 23]
+
+Key = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Nonce = 451101250ec6f26652249d59dc
+
+Count = 230
+Adata = 7cc9c51b69f98a06391ab32742fb6365e15106c811fe8a
+Payload = 065ef9eeafbe077c1c7049f43eb0d8999708e8609f214d5c
+CT = 990065322a438e136860f7b019807e9feff52a642bf3d44a9163fa7a867f04cab6f52dc250070f31
+
+Count = 231
+Adata = 7bb1bc069a783d45d51d8ecd0a53ab7a386fa1f5ef12a1
+Payload = 69b2b056f2265e707d3e31e68bff6a060544c8a737b2a9b9
+CT = f6ec2c8a77dbd71f092e8fa2accfcc007db90aa3836030affd33dd9155619fb040dcd6038c7b7367
+
+Count = 232
+Adata = 0dd220919d0eeee3b7cec36c47e376b778583b38bf61c8
+Payload = b98d79aaa4c04171398c7f1189497acaa7546ef068bc7a3f
+CT = 26d3e576213dc81e4d9cc155ae79dcccdfa9acf4dc6ee3294fcba5a886b1f33cf1cf44618d28f01f
+
+Count = 233
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c112479
+Payload = eeaeb773ade5fb2d27b50bb892916333e0b123c6e3ae5bdb
+CT = 71f02baf2818724253a5b5fcb5a1c535984ce1c2577cc2cdeafe2c670eac203d5e90b9d520e7a618
+
+Count = 234
+Adata = 614b0ac4611b6c6d3b4ed089510dcd2215567bc3789f85
+Payload = f2198e1f91fde2672a1ef60403c0d175f366b6780ee9f1c2
+CT = 6d4712c314006b085e0e484024f077738b9b747cba3b68d4f0388746438e83b731b5588fef53f1f3
+
+Count = 235
+Adata = 866fea4483d4e903566844e31c24283571832dfae32c74
+Payload = ba37617342b4eefd4bdce8fad30c4751b206d47814973b3a
+CT = 2569fdafc74967923fcc56bef43ce157cafb167ca045a22cfca81f8b36d16698a600fd701f2c6424
+
+Count = 236
+Adata = 9d7546f7e8b949c539d21a357f81d0151e278d0bf2c5a5
+Payload = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f6
+CT = f6f3563424142a9d8a8edc1d384bea5d612e770ac247b8e04c15a6d292c7ed2f31cf9512435ec7d2
+
+Count = 237
+Adata = 42b692048c8b3cce1b5e83f4f33232a7d7d0bc20695e7e
+Payload = e0753d4248643642c7a96404de8d76c9d80527b659ec6d31
+CT = 7f2ba19ecd99bf2db3b9da40f9bdd0cfa0f8e5b2ed3ef427a2ad73179d0314b5fe52dd7217518cb8
+
+Count = 238
+Adata = f1dfb6fdb31cb423226f181c0988a52ee4015aef4536f4
+Payload = 79ba959c7221b293e2115f538d9394c64284c756563c04b0
+CT = e6e40940f7dc3bfc9601e117aaa332c03a790552e2ee9da69ccc5ba1caf933b80bfc6f281109688f
+
+Count = 239
+Adata = 8eafce9ba466fd53eb87f499d7c76bd486db0e90a3d281
+Payload = e1590206717a708cad9cca7d23a3b8ee5f7fb7786aa3be47
+CT = 7e079edaf487f9e3d98c743904931ee82782757cde71275173271ec36d92fff34609169f579c8f1d
+
+[Alen = 24]
+
+Key = ef4c1d2314e671f666cc6667660f1438a293208c7cc29b412d81277f0a635c91
+Nonce = 50b23b052922366c25dd40e348
+
+Count = 240
+Adata = cd0522ebe1fed82465277d1c10ae9316a98b4469be63b180
+Payload = c99c3e79125b6fd95e737326a842424eb6c6ecea4c0475c4
+CT = 76df4be4ec8373864399acda11294b220b9f7c3a7d2b3660b25764e40ac6a171e7e6bab4fdee4288
+
+Count = 241
+Adata = ce5bf070678cb07e963263b1562ff79311144addb6e4de4f
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06eb
+CT = 519d742d71422c63c2fe1661c32e7a45cf9f7f2290f4454ffca49758d17f2073066b82667eae6ce3
+
+Count = 242
+Adata = 07175be2475cc735c9a3c1140895277378debf8fb1c87c24
+Payload = 6d5579aaaf8737b01620424f3ddeaf538f10dfad094e5ec4
+CT = d2160c37515f2bef0bca9db384b5a63f32494f7d38611d607c1d64d7e9de47a6ad7878283da9d870
+
+Count = 243
+Adata = c821a8d4bab9d993c20dd206955304a55968e6db5ab6480d
+Payload = d0628b2027f06c246497977d05f211b2c2e302d5b82700b5
+CT = 6f21febdd928707b797d4881bc9918de7fba920589084311adc2bb471862d25cfe25e66fedb8e28c
+
+Count = 244
+Adata = 68439bc9d176feeeb4119d00ed5449dfefb72b5a582bfd97
+Payload = 6cc9749f48c61050e421afa3a10ad3dd3aa02cc3f8586915
+CT = d38a0102b61e0c0ff9cb705f1861dab187f9bc13c9772ab1319a493abc947945f1312395ea98d937
+
+Count = 245
+Adata = adb262c924942e4e1964e9d97c6a8c159fbf9bfedc5ff296
+Payload = 92d50736466e64e6225962e76bd90da824f716a3301a1a90
+CT = 2d9672abb8b678b93fb3bd1bd2b204c499ae86730135593421d0602d29447ba6b24a67509eaee1e8
+
+Count = 246
+Adata = fc7b08707d3c3dac7689ec18088ee6502ef08d3ffbff38ed
+Payload = 87c7ac031fd63e4c83280dce6b68a92dfafb6ea19388fa9f
+CT = 3884d99ee10e22139ec2d232d203a04147a2fe71a2a7b93be52a2eeacb1f023e849161b6306b6cfa
+
+Count = 247
+Adata = fd43dfb66041b117f2ac54c94f7b6e2677860864d9494175
+Payload = 6b53c46266b2f4284d8fe7f0549c98977344d67e178e9a8e
+CT = d410b1ff986ae8775065380cedf791fbce1d46ae26a1d92a0d8c5b1e96b21460e0b5414639abeb0b
+
+Count = 248
+Adata = ef1ad3eb0bde7d4728389da2255d1f8a66ecb72e6f2f1ac4
+Payload = 8e7d8a44244daa7df2b340993e32dac50e05d7b2e103be98
+CT = 313effd9da95b622ef599f658759d3a9b35c4762d02cfd3c1c97260d20797d374c595cbc2ff080bc
+
+Count = 249
+Adata = 9895b24d12b004b215583eac70a95f4fba7442164f35c57b
+Payload = cec07df916ffb7a453d0eb588b7462096f22874bd5abf814
+CT = 71830864e827abfb4e3a34a4321f6b65d27b179be484bbb06cd287afcbdbc5531f11246080b22677
+
+[Alen = 25]
+
+Key = 8544808e8fbf8c3a5e1d4ca751d4b603af9fe119eabc6923205815e0e748b7e7
+Nonce = b44a58724596b4d8dea827c1a0
+
+Count = 250
+Adata = f5b2c88f5232c37273b1e66aa31cfa7201e33c21d60054d025
+Payload = 617d54fc6a23601c79e3984f93bfc2d151fde420863206b3
+CT = 57b3414db48982c6567265e1e0173bf38fdfaffe4461fbebc1411af83237c0f9eb0bfe8ed914da66
+
+Count = 251
+Adata = 8fabe14dcb3aa2fd28281147c326e98ad699ca7997f03a105d
+Payload = 337290d0b4ce1e87afc3cf01d6c98f8c17a4603120dcfcd1
+CT = 05bc85616a64fc5d805232afa56176aec9862befe28f01897ed6e23720b60ffe54bbb9f7ff371008
+
+Count = 252
+Adata = cf193eb3d755cb8e06c5be2334b5c8b7a22b6524d46d547ba3
+Payload = 01ef7ac6470aa02ccd8c1712827e52699d05751b78e4c5a6
+CT = 37216f7799a042f6e21deabcf1d6ab4b43273ec5bab738feb6aa6b284e7720acbd027a50317f816a
+
+Count = 253
+Adata = b4cadb5f9cb66415c3a3b71421b926f147566a174160a0bcc0
+Payload = 64fb9322210fb7d8da8e762498b233b0eb172c91231c50cb
+CT = 52358693ffa55502f51f8b8aeb1aca923535674fe14fad937058e9c0164ca079668097fde19e5302
+
+Count = 254
+Adata = 48400d76ff882d6d5129c8674acc71f445356c9db9c91f8256
+Payload = 291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4
+CT = 1fd4b1d21a105eac9b37075c91d66d2386495116fc18fbfcf988611d5ce0f65b217bb4787bf59bbc
+
+Count = 255
+Adata = 749d369d837002ad33feb8aa22c3f68705eb4872e1b8f85a7f
+Payload = 141cdd7f964a78815be144a785c6a2a298c54230e73039e2
+CT = 22d2c8ce48e09a5b7470b909f66e5b8046e709ee2563c4bad6251a5fd375a48583a6d0f8eb75cbb4
+
+Count = 256
+Adata = 80214108b16d030feff6e056c9a07a00a1d5e3ebb07abd3f4a
+Payload = fa2441cb7f9d072b8a3f1a496b2be6728a38b94a4f44c9be
+CT = ccea547aa137e5f1a5aee7e718831f50541af2948d1734e6af1dab0f105414293cb130bea285fd6a
+
+Count = 257
+Adata = 8b9fabe29718a8f297c9bf6f199c80bbc71f94eb3034a11ecb
+Payload = c8ce88ab40b62229223d46cc44f21bb39cfef27aa9fdccad
+CT = fe009d1a9e1cc0f30dacbb62375ae29142dcb9a46bae31f51cc3f7640a42460be877fb7059a3ed61
+
+Count = 258
+Adata = 8812f28a0cd5fdaa226fdd44ed857241007377057be3bea577
+Payload = cf59f75ca4d6d216cf8862b44b5192c382c140f862def117
+CT = f997e2ed7a7c30cce0199f1a38f96be15ce30b26a08d0c4fbbe0ddd2e7f4aa2024b3fec9281b6cac
+
+Count = 259
+Adata = c8f05e96d703a4850bae1421ae9ff3aec7531baf9b899dfd75
+Payload = 4eed58f381e500902ba5c56864f6249d191e14d1b1fad3dd
+CT = 78234d425f4fe24a043438c6175eddbfc73c5f0f73a92e85e5df1e5e96bb84f730fcb253d468278f
+
+[Alen = 26]
+
+Key = e19eaddd9f1574447e7e6525f7fd67e3b42807e44fbb60e75d8c3e98abc18361
+Nonce = a8c459ce0223358826fb1ec0f0
+
+Count = 260
+Adata = ef88f4393d6c1e7b7be55a12144209ee051bb779e440432721ef
+Payload = b3b0de10b7c0996662f1b064e04e528b7d85ca1166985d33
+CT = d63e6082c95c6c5ff2bc0771321a4f883ef61cff7b99e0ea8a20a1abe7c842ebc08c8c81a2743c81
+
+Count = 261
+Adata = a4c891c9dd1fcc982c35bc74cfe71651bae424602519672b466d
+Payload = 4f0b40913f07269550b7b06ab9027a4d9331f8ef98a45dca
+CT = 2a85fe03419bd3acc0fa077f6b56674ed0422e0185a5e013845e2d6de83ab729dd200a21088a1ec3
+
+Count = 262
+Adata = 4db5730cb9794f3b1facc9d6738115d02ba9f27ba02330fbb856
+Payload = 841e032773d58bc72a3237bc9b24c61b9efdd850fc2ea605
+CT = e190bdb50d497efeba7f80a94970db18dd8e0ebee12f1bdc10ed272c732247a696a608ef67510f9c
+
+Count = 263
+Adata = 471a900ee49f2cfa1d3eb37c951d810c349364d4cc3b5b64fc47
+Payload = b4db42e523e65557157b93dc0281601f7997e6731543a914
+CT = d155fc775d7aa06e853624c9d0d57d1c3ae4309d084214cd15f0df52e392c37ec15f7458469dae84
+
+Count = 264
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5
+Payload = 73e0ed35c0e847188e607cde46586eb9e237fbdc5d59163c
+CT = 166e53a7be74b2211e2dcbcb940c73baa1442d324058abe5421433dafea2b5484ba87b5050e1fb49
+
+Count = 265
+Adata = d563f5c048a1b45265182b99ca7b9004fdc73a9cb07806dd44fc
+Payload = 4f7669caaedee961dbba6bde9d09fee1a20eee55baaf98f5
+CT = 2af8d758d0421c584bf7dccb4f5de3e2e17d38bba7ae252cdf91749fe3cd52a9431d9a847a8c2a9a
+
+Count = 266
+Adata = d301a61eb17366d4e70942ab69b4f4bcf8ff6a97f5972ee5780a
+Payload = 154454fb74e9565c56775a8e4654f75a38b954dd28c4e939
+CT = 70caea690a75a365c63aed9b9400ea597bca823335c554e07563d37846f5185bb44d71be1ea6a73c
+
+Count = 267
+Adata = f74b48d168f77fbd3429728c0b168ecbd854264eaef70b74fffb
+Payload = 716b371857e68a17b20ea06651cdcfd4560a741830ca8a13
+CT = 14e5898a297a7f2e224317738399d2d71579a2f62dcb37ca55e93bc2d3f05d7016747690fb920e12
+
+Count = 268
+Adata = 3a257ce3592a8f88162f0bb4ecd5db3bb79b54ab17b0bbc61506
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb39303b4135269
+CT = aa55cdf1e6c6552366b55f36afebaa845dc045eda912efb01c46822f839f09c41b7aa6dc06035c93
+
+Count = 269
+Adata = 21916ebeca9e66b77cf55d1cac80a4c85d8b6b014f268ffa73ca
+Payload = b4b67ac551d1966caa20d951351387f384c2e5d81a76a92c
+CT = d138c4572f4d63553a6d6e44e7479af0c7b13336077714f54f8e77600c5bbc6d028fa25ba61a1719
+
+[Alen = 27]
+
+Key = 9498f02e50487cfbda1ce6459e241233bd4c4cb10281dcb51915dbc7fb6545c0
+Nonce = e3bd4bc3a60cddd26c20aa8636
+
+Count = 270
+Adata = 70cfcb828d483216b46c3cd22e2f9ee879e9e3059b566179b6e16c
+Payload = 0d16cc69caa9f19b88b05e151b3d26accd018ca4a5786a80
+CT = f1c4bedb8d6f91676881daa37656a7e6402f472735b04a0f1f8332f4236437737438e7aa1b5100c7
+
+Count = 271
+Adata = e7e5779282db80f424dc050b2c1e7754b2a5d3a8beae77beb74e34
+Payload = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c
+CT = e85f94f2b407756d46c94172eb5944b1f4fd7c625e3135138be2f6f356c2eb401468be15104e7763
+
+Count = 272
+Adata = d17e8189a94a559b07be9549f73d653172740e8e978f5b0a38ad43
+Payload = 00a23b25bca7c206edd051814d81083db1cd00048ce8ead5
+CT = fc704997fb61a2fa0de1d53720ea89773ce3cb871c20ca5a9646f2b6c2455603f1a6f20ea5a4611a
+
+Count = 273
+Adata = fda37ff136895de7ebeaf81e701e5751245201baed2e13d7e1b591
+Payload = a89409b0977f60a029dc4c1560ba6dbe7c65b068633acf74
+CT = 54467b02d0b9005cc9edc8a30dd1ecf4f14b7bebf3f2effb303fa5d8321241b1c9e18a5909d6e428
+
+Count = 274
+Adata = 9c179fd0d6277a5e073e77dd6abb4cba00ad9c9932e6c002b951c7
+Payload = e16c69861efc206e85aab1255e69d6d33c52cf058dec9d0b
+CT = 1dbe1b34593a4092659b359333025799b17c04861d24bd849e8cb01db1da077502814db1610662ce
+
+Count = 275
+Adata = cf5703228e615428d3d3805e428e754961d205c5aa0297ecdea71d
+Payload = 62036cbed3666d85624d3dc9c1f437454b9ab5c03ce0de92
+CT = 9ed11e0c94a00d79827cb97fac9fb60fc6b47e43ac28fe1d40a02a49857d7b280330b8105efac854
+
+Count = 276
+Adata = bab7e36098d59d3a31d7784d549aebfc6938bbd0612c85c0edb796
+Payload = 790ac86c5e9d8ce8cbec1dfb7e4fc4dca3d0b1039adfe585
+CT = 85d8bade195bec142bdd994d132445962efe7a800a17c50a5ecfa9dd03e2db70aa212ee7dcb573fd
+
+Count = 277
+Adata = 96f0b7cd7439721d4c9cc4f69585f8c90a95bed8fea22150efffba
+Payload = 3cfacd61ea3398de20ca6bdb00e81af482320614bdfb8642
+CT = c028bfd3adf5f822c0fbef6d6d839bbe0f1ccd972d33a6cde17a7a0cd162945a3616892e101e3e93
+
+Count = 278
+Adata = ee71e53d0b4eef82575c2bd38d7bd21b41fabe58c6f571954fe159
+Payload = d75c153e34ae1c6d1fcf5b1052190d8882041e1f9c5490e2
+CT = 2b8e678c73687c91fffedfa63f728cc20f2ad59c0c9cb06d15fadc2d79841d230cd55c04379f22b4
+
+Count = 279
+Adata = 18a4aa894861c7720ddb43809c3d2ed2af2f1bfe8f9fd4f872c14c
+Payload = 0e728056c7c64214be8f1f1727408d8cca8c42e2ac7bf67e
+CT = f2a0f2e4800022e85ebe9ba14a2b0cc647a289613cb3d6f1b229b9bae4634eea6b723f432e19ae55
+
+[Alen = 28]
+
+Key = 3ac7d5bc4698c021e49a685cd71057e09821633957d1d59c3c30cbc3f2d1dbf8
+Nonce = 54c8ff5459702aac058bb3be04
+
+Count = 280
+Adata = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c049dd1ec
+Payload = 89198d3acc39b950f0d411119c478c60b2422ffe7e26e00b
+CT = 7717b8e4447afcea1eeebf3e39ffdab2f52828e7931ef27e475acd27900478f09fec1f479ab3a7c8
+
+Count = 281
+Adata = 9a04820205234795ecd540b6a0b2fbd0b19f18106c42f374a2b98425
+Payload = c0f61950f98110db4226e269cf197c7e2794c5b87ad68cf9
+CT = 3ef82c8e71c25561ac1c4c466aa12aac60fec2a197ee9e8cf7b7ed6e8ede6ef5a73b484bf13b3424
+
+Count = 282
+Adata = 0e4dbd167da0240298f4795102ef18ff9a8772c6fd73b3374cdfa30a
+Payload = 7960dbc9136880e2eea7956c3271adfe2aba7dca53da917d
+CT = 876eee179b2bc558009d3b4397c9fb2c6dd07ad3bee28308e47d08ea0788f7ca0ecd846689c8027a
+
+Count = 283
+Adata = 2de4291068a5d290b599a73c6a8ecff4f9fd6c9cc48f14c233e18581
+Payload = 0c5d7055bbfbd2bc213cfbbafa763b71b1fde6f4de96fa59
+CT = f253458b33b89706cf0655955fce6da3f697e1ed33aee82cd081f66b1c7b70718dc50367c3da6792
+
+Count = 284
+Adata = dedeb714f555575fcedbd9de8171484090e6466dd4fba3c6b7c42eae
+Payload = b5654edcc8f09e4f80d0258c9376d7c53fb68f78d333b18b
+CT = 4b6b7b0240b3dbf56eea8ba336ce811778dc88613e0ba3fece672883438da186741e6c542b3f805d
+
+Count = 285
+Adata = 03d340904ace1cd52d4b72a96d96afd77aee68ac3936415005ed0d56
+Payload = d796f3409a7eeb896c3d4ebef46e9c6e553aab28b1cc4a90
+CT = 2998c69e123dae338207e09151d6cabc1250ac315cf458e5cf58d4a5552bc8ed1b1dda46703a256e
+
+Count = 286
+Adata = c67f9aa8cf1be3b4377c30c175d33ab2af390982c6a015d99209acdd
+Payload = e4dd279a79a381c68de777df941a4779e50a1381c8aa9122
+CT = 1ad31244f1e0c47c63ddd9f031a211aba260149825928357f95cf2b57e06de4d01bbb6c0e39f37e1
+
+Count = 287
+Adata = fef1b2ccd661b9fac85ba005addebdf8317ab104920549d3a490a21a
+Payload = bbf0c267d952aeb6f810601b9cf1962a92dcaba7273e6902
+CT = 45fef7b95111eb0c162ace343949c0f8d5b6acbeca067b777589cd12984286af98908db88920323c
+
+Count = 288
+Adata = 693fae7af84aa397f0b2baaed9b3c7953f75e7424c49b6349c2fc20f
+Payload = e8b13a263e0c4fb5645e500e88ab8074ab7d92e5a8dac6aa
+CT = 16bf0ff8b64f0a0f8a64fe212d13d6a6ec1795fc45e2d4dfee8fc441da990dd92c0caeac9d956699
+
+Count = 289
+Adata = 85e5df4ddec99f0bea14b3338b2eb190ab6584f5253c6c2ee3064637
+Payload = 067de2869333ed22c7b63ed7eeba1301bbac69b0d430adb5
+CT = f873d7581b70a898298c90f84b0245d3fcc66ea93908bfc0d502f5434bea8c3c13ad5422ff90e218
+
+[Alen = 29]
+
+Key = 948882c3667caa81c9b900996e3d591e6fcb3d08333eeb29911e9c6338710c17
+Nonce = 43b0aca2f0a9030f90559fa6d3
+
+Count = 290
+Adata = a516ca8405e5c8854e667921b5c5e1968bdd052915b55ac9984b7eefb3
+Payload = 8b9130b0c3c15366831bbb19f377e3209a8dbf7619cd09bd
+CT = 4646b2acdeb11174171da23999cd54e297daa32bbc13d30512e57c576b315f48c11877178389aaa0
+
+Count = 291
+Adata = db3121ea71294983b185207a9d8de3e484a66c0431bf07c962eb82977c
+Payload = 7f369bbc99b6f08049eeb43566269a174829d4dddb05cb9b
+CT = b2e119a084c6b292dde8ad150c9c2dd5457ec8807edb112366775e693f93af6575dccc7903538065
+
+Count = 292
+Adata = 1651cf38fd9b2da65ebb4922b97dcb861128eeefa060d6c1c94b25eb4e
+Payload = fd0900b5fa72e2fba43d611bad25de40a3507a5cc5d186c7
+CT = 30de82a9e702a0e9303b783bc79f6982ae076601600f5c7fb70d8de40c2068de96a274d3b5086b5a
+
+Count = 293
+Adata = af87b347b59e37a424004a00907dcbcf6a554e6782a9be12cb3047625e
+Payload = 36318d80c02a1da41ef1652d9a752e155526b5f597fba226
+CT = fbe60f9cdd5a5fb68af77c0df0cf99d75871a9a83225789ee7da096d2fb28f20f64a000fe93e96e2
+
+Count = 294
+Adata = 0680d5bacefa2ab14aa12b0e517a1432862d4215dc72dc4d5ac6b96c1c
+Payload = 7a29aa2994d11215ab3ef3382b3db6ed581164a235c4b1d1
+CT = b7fe283589a150073f38ea184187012f554678ff901a6b69b88748a2de31261534cdb2237565bf8a
+
+Count = 295
+Adata = 9af701f0a9de52309267289bd170fb97c03c131c0a169d736137ff3d74
+Payload = 3542fbe0f59a6d5f3abf619b7d58b199f7caff0205093f8b
+CT = f89579fce8ea2f4daeb978bb17e2065bfa9de35fa0d7e5330c003eb65ceedc98ae4e38ef341ee47d
+
+Count = 296
+Adata = dab7845fb7ead205569475753c7e26540c09d3a74312f2de25181511f8
+Payload = 83c15520d9541c86b3dd809ede42de22bbb2b75ff18a023b
+CT = 4e16d73cc4245e9427db99beb4f869e0b6e5ab025454d8835c2fb596d8ff6a863604cd224fa3be42
+
+Count = 297
+Adata = a844d6dbd05545ecc736994dc9fc2260c5ab63ed6ffdc40b915f8744a1
+Payload = 793a188fa3efa32f41d6e4c5b42353b95024117d546c79ca
+CT = b4ed9a93be9fe13dd5d0fde5de99e47b5d730d20f1b2a3722ac782e2cd8ecb06172eef2cb9b0e331
+
+Count = 298
+Adata = f9112503884615c0e8a1d8414724b0d19298988f393a27c436b2b6734c
+Payload = 6b237444fb0e1f4150701546c4cb24021c5edad30d9b31dd
+CT = a6f4f658e67e5d53c4760c66ae7193c01109c68ea845eb65f814492b42571033f4dffc0282ea2f51
+
+Count = 299
+Adata = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c2c94d3a5b4
+Payload = 6342312e8a72f71f2e5afe04cfcde4d60a41556111752103
+CT = ae95b3329702b50dba5ce724a57753140716493cb4abfbbb75999099df2de6e436bd99f0341423f4
+
+[Alen = 30]
+
+Key = 3bf52cc5ee86b9a0190f390a5c0366a560b557000dbe5115fd9ee11630a62769
+Nonce = f9fbd02f28ecc929d369182752
+
+Count = 300
+Adata = ebf0b3e3199a5c3773c761c725c7600add5f9d8321c9f8e5e5fd1c7a5d2f
+Payload = 094b538110495e938b08cf748a6bcf3e0c80ff9c66570237
+CT = 4d8b53016fc8bc9677184c0fa15bbd3d671b9366d82ecb67f8562eadcdcbcdbad1299bea1523f5d2
+
+Count = 301
+Adata = a865b88d512e485ab3f2844c29e6dde0cf1151efa9ad3b3021d06fffb74b
+Payload = 23edddd8732cdbf03af08162f0e4a24c9222bdbb4549c663
+CT = 672ddd580cad39f5c6e00219dbd4d04ff9b9d141fb300f3359ff77cf0962455b3539dbf91f3077cc
+
+Count = 302
+Adata = 16918dbc785d94a8f1720c5ad234dde860219874c9fb076a5c290903f85b
+Payload = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0
+CT = 535828ec4840b24a3cc7c35daac685047a743c977247e0806dbed76d94c90595b49d50c84c3efc76
+
+Count = 303
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918
+Payload = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32
+CT = 49c2770fef2086a105bd2aa754e23ce8ff8b0598aa61266248fbe60c146056e5cb01268403e4b9f5
+
+Count = 304
+Adata = 2de5222a0609f058f60e9e581b6e4f0ddebed84fc8302c8e985d17b89241
+Payload = b0c3858231e284af6d231f043b95772f5e7b16a34ffcd2ec
+CT = f40385024e6366aa91339c7f10a5052c35e07a59f1851bbcacff35df1ec942b43eef5aef980cb038
+
+Count = 305
+Adata = 3fc7453df038a92829dc103d44b63ad097d7cd7f9ae7996547012090c7c4
+Payload = 319f396cc02834f8e69d65f77496d0eb31ce1a7b7e324820
+CT = 755f39ecbfa9d6fd1a8de68c5fa6a2e85a557681c04b817091a93f5fc28e5f4f351cfb888da763dc
+
+Count = 306
+Adata = 18f1e92bd3c4a597ed970911d03a78ff9a6790147c9bb0ca5f23b70cce7a
+Payload = 25550c03f8fa02b3781330f96e0fdc58681b0c0bc5e83fe9
+CT = 61950c83877be0b68403b382453fae5b038060f17b91f6b92c6a90ef2e9a969ec0576fae1d126a85
+
+Count = 307
+Adata = 09ecb2406054716418ff3600c3c5cacb0845a377a2d80542abc36ec81bb1
+Payload = 210ff7975e08388b9a46eb732230e3a3856a497549b5eb49
+CT = 65cff7172189da8e66566808090091a0eef1258ff7cc221959fd6aeb047200907911621e8756b45f
+
+Count = 308
+Adata = 62d515bb0525b565a6a3613ae20343c8da7424c8368e8cad6a862b7d37a5
+Payload = 5d867265965bb2aafebb0691de9e157a24066d06fe3cbd7c
+CT = 194672e5e9da50af02ab85eaf5ae67794f9d01fc4045742cc4db6d5fd910c83fd77aefba3f7665d8
+
+Count = 309
+Adata = 00617ca141e55b045a188e4934caf6db63d4577f634db92c22010e1cbf1e
+Payload = 396b27afd16a1081f37bbc1f742b549f5f68df799b93083f
+CT = 7dab272faeebf2840f6b3f645f1b269c34f3b38325eac16fdf5f21f32cbe5d272004f1c104cbcae9
+
+[Alen = 31]
+
+Key = e45bb1730d0d539aab3805350ac986540de9f0f6c239ee70395c291397b70309
+Nonce = d5c7824af715bb7822b6b340fe
+
+Count = 310
+Adata = 860f4a09ad8b3d345c2aa18ffb803f0bc3b734a4d047a1437701a5e3d95288
+Payload = bc8b3bc48c7a88c9fafde258b6ccaa9d4f0d018703d63871
+CT = 95f083ad6bbaee6ab540fe023858f8baf25e333fd3e89c00e678a392d228b210dc5c991905dacf3f
+
+Count = 311
+Adata = 8a84b57915bdbe7bf5a1c1a426512b3c178d883251cc46c95a8bbc8ed9e56b
+Payload = 9499ea48edab9bc21b91dd614f04934ca20db8630622f481
+CT = bde252210a6bfd61542cc13bc190c16b1f5e8adbd61c50f010fbdd3b305522dae6b652322d89d9ac
+
+Count = 312
+Adata = ed8540f7ce451c522c1ff5d2d1030d7b3fbd1219a21aaa84044c4f23c08f5d
+Payload = 73843a4e9e7937fed24bb1fae15822213b1aa86c07f1b5d1
+CT = 5aff822779b9515d9df6ada06fcc700686499ad4d7cf11a08b6b08548e794eaf85ad9f5de80b1c00
+
+Count = 313
+Adata = 61bb196b212feab645f05a8aa1986f6210a384c15bc749245d840b3565fb36
+Payload = a8e24266e5981b2ed14213a29f961cbbf7f02f63a33c987e
+CT = 8199fa0f02587d8d9eff0ff811024e9c4aa31ddb73023c0fcc73643a7ee9291e15137d7046a92f3f
+
+Count = 314
+Adata = a49c2df94ba65107f375ce1c53b72406143f6bcd270945de5b7811682fe361
+Payload = 3e3c402caeca41687d12897102e04312edf7b8c7d8567a22
+CT = 1747f845490a27cb32af952b8c74113550a48a7f0868de53204438662ea82f423a69c6e4e3c0623a
+
+Count = 315
+Adata = 7c48480e9bc87ba299e03899698b2259eef150ee0f2efff40a5583b80ab484
+Payload = cfa9292b9052ac6bb863205d3c0dc2d9e20d2ba6a680d2ed
+CT = e6d291427792cac8f7de3c07b29990fe5f5e191e76be769c6ea00b9cd881e3f4b1e838dfa31f6560
+
+Count = 316
+Adata = 5cf9744090366d828b477dc890eab8ebebd44f6aeaa5b101291bf67d12867e
+Payload = e0fe4e139ab0deb4fdf2145b719f35c50b869e6cb20608b5
+CT = c985f67a7d70b817b24f0801ff0b67e2b6d5acd46238acc4c59b3b87d722a58cd1de58f3963d12b3
+
+Count = 317
+Adata = 761d74be5fae170a1bdfa16081b44c1e49972e15ce0818df1390bf7204f619
+Payload = 665fdcdf55a1231e9912562eaa5a5011d69f6948e29e3f8f
+CT = 4f2464b6b26145bdd6af4a7424ce02366bcc5bf032a09bfe158759886124f1f0ce8147c94f4e7114
+
+Count = 318
+Adata = 9815353b69d0b4effa52cefff13703fa71a6296f9cca0f02568661be4b64cb
+Payload = 7b2d52a5186d912cf6b83ace7740ceda3f5f443530c5a49f
+CT = 5256eaccffadf78fb9052694f9d49cfd820c768de0fb00ee6310a79c9932456dbc00515b264f3168
+
+Count = 319
+Adata = 69dd1a050c8d79dafbbe3403af4dc1f070b9b2b980888aa796e6cff68d9060
+Payload = 3cea5ff50167c5641066852fd00061df35b1f66bedb894b7
+CT = 1591e79ce6a7a3c75fdb99755e9433f888e2c4d33d8630c6da7e97f9984a7db3b93aefb4316d9acb
+
+[Alen = 32]
+
+Key = 2e6e34070caf1b8820ed39edfa83459abe1c15a1827f1c39f7ac316c4c27910f
+Nonce = c49ccef869bb86d21932cb443b
+
+Count = 320
+Adata = d37e35d7cdccd9824a1ae4c787819735e4af798a3beb49d4705336d6496853ad
+Payload = 771a7baa9cf83aa253349f6475d5e74dba4525307b022ba7
+CT = eebac2475004970071dfa2cfb855c4e78b1add8dcbccfc0bd6b14027324b657a56263df148665393
+
+Count = 321
+Adata = ab22bc22bf2628b0e0ab245c3db2fc5128d13a011c2cc9b9fea05a79a3410704
+Payload = dad95a4b4d3754613f0542caa62cfe4e375dfbdd369ec32e
+CT = 4379e3a681cbf9c31dee7f616bacdde40602036086501482a8c810b6944815fd2e434193520b1d5b
+
+Count = 322
+Adata = c48c5aacf701137fc40fd0d3649641aaa5be427ceee702cf7ddf6408f458a581
+Payload = 3f28df9263e473be648fabad163aa4142b633388b16d8392
+CT = a688667faf18de1c46649606dbba87be1a3ccb3501a3543e8aa447b79284c588bef50b423de97908
+
+Count = 323
+Adata = 477c2484cf5c56b813313927be8387b1024f995e98fc87f1029091c01424bdc2
+Payload = f83107b50a1f192ed45cc43fa80e6b519bfd859173ea9ee9
+CT = 6191be58c6e3b48cf6b7f994658e48fbaaa27d2cc3244945d4f4a413eb3ac2c474134995d4db9a16
+
+Count = 324
+Adata = 143bc037f1d0bd4ec16825c58cb3796bf8989200d27bda9beabbbc49247f59f7
+Payload = dfeb324ba459ec4a5c54d2534e98002412e67db19cfc66bb
+CT = 464b8ba668a541e87ebfeff88318238e23b9850c2c32b11756a3fb2e06734b28fbd57942a609d914
+
+Count = 325
+Adata = ffc416f1dae4e43c1a01339a604c44d6a0f25ab9ca3978c6aacb6d270d510ee6
+Payload = 0765949e6f22c422ebd47dc1ed73f1b849d7a058a1656fc2
+CT = 9ec52d73a3de6980c93f406a20f3d212788858e511abb86edb94280d3c4a1cd8cb00705f60ae36f2
+
+Count = 326
+Adata = 6090b596b4082ec6926576137f6561cf13916860ad1cfc43650d1b5142a12041
+Payload = 6db320cbe76bc5b8cee9ef89aca11765571c6c501993195a
+CT = f41399262b97681aec02d222612134cf664394eda95dcef612caca26cc3bbb289da3be0616b3445f
+
+Count = 327
+Adata = 178ba75adb7c5bea6769270bb3b4f6ce208d4a786913d3ced7bb4090b5f65544
+Payload = 0875020959ed969cfb38636d1d5aabce9658b00171a7614e
+CT = 91d5bbe495113b3ed9d35ec6d0da8864a70748bcc169b6e26cc8c665289d907628eb0e299c2d411e
+
+Count = 328
+Adata = 90f0474dca998916075b1b1428df14d90be05491bb8d5d88e32e65ec890ba9d3
+Payload = 4f89ca6ad371f86a6e073ec12fb1b928bb10d6639233b918
+CT = d62973871f8d55c84cec036ae2319a828a4f2ede22fd6eb4f7e481607a2a0529f9cda1d5903325b7
+
+Count = 329
+Adata = 5ad8dd40ecdce52d5b30424ca0bccb666f34f66b0c9a4c1260051ac04ca06aab
+Payload = fe2009d0a4a1711b83057b948cd0b174a3a042fd97579ab8
+CT = 6780b03d685ddcb9a1ee463f415092de92ffba4027994d140a1b9ba2bfe5bf778b859f0ff0c29a67
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp
new file mode 100644
index 0000000000..b796541cf5
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT128.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = c0425ed20cd28fda67a2bcc0ab342a49
+
+Count = 0
+Nonce = 37667f334dce90
+Adata = 0b3e8d9785c74c8f41ea257d4d87495ffbbb335542b12e0d62bb177ec7a164d9
+Payload = 4f065a23eeca6b18d118e1de4d7e5ca1a7c0e556d786d407
+CT = 768fccdf4898bca099e33c3d40565497dec22dd6e33dcf4384d71be8565c21a455db45816da8158c
+
+Count = 1
+Nonce = f7a5098b2a4d92
+Adata = bc498326755503ff25d02805eb3517221b54eb4fd79af0fcdf9312b2a9ad95f7
+Payload = 3e2144e2a381b718962a77e167778bf579957a8fae29612c
+CT = 98ce91033fabaa8fe853d347be6cbe5de102fdccf042e7be697b41c9a69acaf8386140ee6e36f406
+
+Count = 2
+Nonce = 732d2dd64b4a25
+Adata = 495b03df82e317e4f351c5323d17c673f4c77856983179d7c7cb75c2b0573c72
+Payload = 4bb0d170bdcc70fd18f19605cf9c6181082c4367f1e6fbce
+CT = 9bd9304259962448fa8487bc15d950303621213afd88f1e32d442ff663242fa269c4a742a220edc5
+
+Count = 3
+Nonce = fefd3ac595428f
+Adata = 91ffb6be8e129cef9189f7e0fec8e937afcfc6083b6a79a778a724bb3e8d0794
+Payload = 9e8c4f1292e8d7e5179b34ae5d2ba2491d7754acc54bb91d
+CT = a5d012b3062cc93b831860d76539169c88854b85550c67fc564a2f1cb7d77e0223287740d5ff9003
+
+Count = 4
+Nonce = e14d81ee3b873a
+Adata = ecdc5249ceb48e8d5a4483043921c00c1acb1843fae00155a28f3a127150b1c4
+Payload = f99e23288e6b5ae85c14610994d90d5fcbcab62b4ed1333e
+CT = cc4ee711d0202deb58664e00cf0cf70b737f48ddadcefd6cd217fb611daeb66fa2d8e1bd43cb2131
+
+Count = 5
+Nonce = 2cbeaba94dbbd1
+Adata = d129674c6c91c1c89f4408139afe187026b8114893d0f172f16469b183fee97e
+Payload = 1b42cb685bd462fbd40e0273a81c767aa81cb43f17d3c0c9
+CT = 1a1b1c7130aa63098dea17ffbb2216d1d276cb10145b0762a45116736e95d823e579d73dc31dc487
+
+Count = 6
+Nonce = 8a961df9c23f6d
+Adata = 07185502bf6d275c84e3ac4f5f77c3d4b30d8e106603be84410c11849a3c18ea
+Payload = 434e182d04ecda519a6119fbaa4c45e8c9803a9a3eb51dae
+CT = 3f603939c6226d8208b2b0e675b82557609ceaeeee4032c7837ed517dbd7e6fe34ea42b01c69d370
+
+Count = 7
+Nonce = d3604d390faab3
+Adata = c95e7329d36145664da69d25f24b301d334e1bca2baa74b2d5c325ed7d04fae4
+Payload = ee104be898a225eb1da99163bbf768d8ae6d5850af6f8767
+CT = 3e6a7683d9d804f791f77d2b69996102ba82477ec4557747ef2e0b322f51abb366a1e8e37f4fe4ee
+
+Count = 8
+Nonce = db5004a1cdae8e
+Adata = 1370fc9d5bf1ad2d071be5a28b235402a85270f536b5601c221519a3b329c71a
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 6db54d6f5c3f3efa6da67aea1234d46e8b679a5c257c66d82e4ef944778281ed186b4a8099b47fff
+
+Count = 9
+Nonce = 783477f981ef05
+Adata = 04bbf2a826bdf3d55069b1936c4f8e8e08189f54066a035c950c7347604b1b65
+Payload = 6150f132b25727ebbaed9f16bd91ebce00c68e5b39bc0ef9
+CT = 36f78cef22cacaf9f3d4464821737f7fbacd79be517b4727bc5c098625c51ac7fdd15da2cc9ef4b6
+
+[Nlen = 8]
+
+Key = 0b6256bd328a4cda2510d527c0f73ed4
+
+Count = 10
+Nonce = 21fd9011d6d9484a
+Adata = 66ff35c4f86ad7755b149e14e299034763023e7384f4af8c35277d2c7e1a7de2
+Payload = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2
+CT = 5a0be834c57b59d47a4590d8d19a1206d3c06e937a9b57f74034d9fdb43c3f48932aa72177b23bf6
+
+Count = 11
+Nonce = 97f940d7c1230bd8
+Adata = 78337ddfe38be7897372b0f805603a9a9e55598452285764641c3bb7aeb54a3c
+Payload = 772aeff60eb3adf5a9589ad54dda0401cc9765589609dbd3
+CT = ef5c408dc6d0b501925a47def54d8deb9880a07a3e6380bca20a3995cf25c5a7b9477d8916adff73
+
+Count = 12
+Nonce = acfdf302ed116ac4
+Adata = fe9d9989bffae3c9e6161eb0aa9d54ee8f5051f0dcabb5a750c5478c11798ce1
+Payload = 99ffe16de323a9b65fe60305a2d062cae490ccca6d9fe9da
+CT = 1bbc2c7877d845591660636cb6ccf4edcd4c156996a26a707d0e2fe322f203c08f44d7f9bd7258c3
+
+Count = 13
+Nonce = c8d36e13b7459c47
+Adata = 3f3c3a4c26dba18f385274ac5ac3df73282686488d91bc8190b7f61071b07f62
+Payload = 316ee95430329f706348886b8ac7779e3056809e25da0a03
+CT = fd2db9611a26a3e90f4861467df60edcc595f442332b089905fdd72307c3355b19ea66d4a16ef17d
+
+Count = 14
+Nonce = 5822755a3e47c27d
+Adata = 1d72d6b371e85ca359483761704f80b3360f4d6610e6d5e490b0d509f73c3233
+Payload = af4ae8f19cf6cbd199677fe033859f56906f1979b1b5926d
+CT = d5ed6f8d5c42f4f3ea527094173b278724a2ba787e416ad759124db19ab1373a5376f46ec7095ef4
+
+Count = 15
+Nonce = 6c1c94c2e71b865b
+Adata = 298cac1e4684182786f386ef3de79c11e30b2dab7579b8ca18d0312200860403
+Payload = 6e4d992d7541e02a4aa167e56c7e47206abc25fea6c5125d
+CT = 560cd43a502a6e8b1af478a3b640a68937d1a83057110d38eaa52d69ab9790edc384b9a5d8c91dbf
+
+Count = 16
+Nonce = ce7ec65cfeda31da
+Adata = 13c1298cbf7fe6a9ab378f86d3c2207944cc2a232f9383513ceb3b202086d365
+Payload = 196c80d02b663bdd89fdaa31e329b5a8f7c596236ee8dd80
+CT = 00174dd83a7f8edc71afbe5da095160336be9184f693db3db1f45de395e021c6fb1b2991c91bd643
+
+Count = 17
+Nonce = ddb739acda6c56ec
+Adata = 7f89bbe513b9a7ebe9be3f6eb88782080593c83e8cbe47fbe15bdc3e5782090f
+Payload = e95e142217c838d1f998a52e342e4f2d80b1cfd35cf6b73d
+CT = 819d73dadaf095652cf39729b2e2cad7fc7783887a5acc15713d941b845d96a5bf65e9f80ae7f923
+
+Count = 18
+Nonce = d9bb71ad90152d5c
+Adata = 20bfcba120cdbeb07c5f4d70338ffce493822d78a03c9e80b5b934e16e39f70e
+Payload = f1fe98b50ea2f9f088f6f93910757cf744d5aabf3081966d
+CT = 36decda8ade6ab104a201c6d370412b907a559738eef59665e99761cb1ac77d772b9cce9345d9a75
+
+Count = 19
+Nonce = 2c9ec9f1f1358c50
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = d74badb8ad7f2c2bcdf67e497151d35a4fc2a3c4c871868a
+CT = 0e9066270da6e03cb4307c43adc71b4b596213a63fc8032085ce60506ac3bd97327904ad2e072a6a
+
+[Nlen = 9]
+
+Key = afdccc84f257cb768b7ad735edbd1990
+
+Count = 20
+Nonce = b7776aa998f4d1189b
+Adata = 9f9ac464de508b98e789243fdb32db458538f8a291ed93ddf8aeaacfbfc371aa
+Payload = 56d0942490e546798f30d3c60ad4e3e110fc04f5b1c1fa83
+CT = 96f124c74fd737819008ddef440320f4a3733d0062c83c893e259aecf12ba08f2a2e966a3341d6d4
+
+Count = 21
+Nonce = 278cf1f09b13f467fe
+Adata = af9627922758a9f7792345716782e8837ca78e8f9db16e3fe12a7124a3d4e99d
+Payload = aa9b9e80cef47b6db3816b1d665f233e696337e21bb8333a
+CT = 5eba7e3b3ecab78121b0d56acb9dbfc6756c1255b42f145d11751638ed36c1fd3c7268b71633c1cf
+
+Count = 22
+Nonce = 4ae701103c63deca5b
+Adata = 5872a1507c833c581ac2750b2b54add4b92be14e45d72db7679f8fa2b4d1eeeb
+Payload = e832b053854fbd40c0d8b6d6b8fd5de2da0c173f5fe594ef
+CT = 3b2b964c3a90d51c0ace186db79818b4d0f7b81236d36017d3635aa1d8167087600b01643b0a5ce5
+
+Count = 23
+Nonce = cfb5b12928e1c36849
+Adata = febe755bb8e4475d8d12f5e96269abd0d4e40d73cb966e2c523343e9a6d2d71a
+Payload = f46d6970dcc37d32d93ff062e68034c1906ee487fd28eefa
+CT = 0d5332a42fc583f4f81744b899cdf2a64cad1e78d577112fee6f8c4b252e10b42fbaf8c7af1e9f3e
+
+Count = 24
+Nonce = 68d5863cafc69e6ceb
+Adata = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab7da44d2887485954
+Payload = dd4438d7ba3edc73872e42dbbf78cf300fe4bf0eac9e16b6
+CT = 874d3ef7f916db2c2799b6892ef4bfbeb4729ecbf26ac4983a8639f21f8548fae45dc76de57bcee0
+
+Count = 25
+Nonce = ea09fbe5da0fa4fe91
+Adata = 63ee18eb720b21ee4c157dafcb8c7bcc6817f54d5c1b8dd7058c37228a03f8ad
+Payload = c1811d613bf0789beeef693611ef733cd173da703b66ab3c
+CT = cbe5c799952b28fadf414607a6cf8194e9f41194abace4541d3853a52971b0ab46cc0a3eded435c1
+
+Count = 26
+Nonce = 0021be18ed76b3a34c
+Adata = bb5eded483f0ae1106fd08c5e2b91cf06d3a7a73518ad4c479fb05e631ba5399
+Payload = 2d5531d1c51c6ea100b028596bf9f24dd90be14eab58f07b
+CT = 7af0449f7359b7f3e5f6c1e7bc264c7724037f4f16077fd0a2a8e3cfb827c7e6edabb34f7bbafd01
+
+Count = 27
+Nonce = 449b51ee0760179e35
+Adata = e99bdf783070a3a48431704e90277ca65a9704c12eeae2e2d70b62f816115267
+Payload = c4896d58442877c986e4f862a9f3a3179f0e9b96316a90d8
+CT = af7531c073df01077fd5c8ea9a5530c2fe1688d529e5c2f24aa8feae6a500919a336dbba1d9fb7e9
+
+Count = 28
+Nonce = 232114642e0c6b55b5
+Adata = da288d2014616f16a2abf5923dea49aded1748592adbcd97415c33ebfa57150d
+Payload = 11fd3f94b5a5ce94f2740a27a0771aeeac77f3155d2bc12c
+CT = f0c174a7927da0bb88e92917af8ae1df4ffc3527004e9e2d0b25cea7ed6e4fe9069a2ce49875230d
+
+Count = 29
+Nonce = 660cb6d654afcbdab4
+Adata = bd96c3c225099fc58cc1f97779304606b11efe9712fba13abf74fc1d7d44a900
+Payload = 793c0bc3deb6e0bec4c1d1fc17e455eb1aa5e9e25cada861
+CT = fa4b14a381ee41fec7b7279e58f0d06a3beec26d645f81336218635754d5563f2cd48bdbb267e5ca
+
+[Nlen = 10]
+
+Key = 6ccb68d3838d4ddf660b9cd904cad40f
+
+Count = 30
+Nonce = c4fb7519a19f13d9d1fc
+Adata = 092e64fef08b5655a86cdb8de63ffaa7772e8730844e9016141af8bad2216246
+Payload = 5ea35c082e2b190e9d98e6b2daad8672f587b4f2968072fc
+CT = cda5fe3d15d00150b99120c7f206b88a4c2c4a39ca9143425603ab284a73a38cc916f8b653c92ab4
+
+Count = 31
+Nonce = 45927852550961f1ae9e
+Adata = 53ae030474795ffda4d9ac0fc3c45afb592ddd761f7b5335c13a6747e21075a7
+Payload = 6c5f468077536b4c9a94ea4a6fe3cf621083a210daee45b6
+CT = 694847b6429cbc3902d9cb7049625aef1e97b569e1e3169035bb811491d142cf1b26350f8451bd14
+
+Count = 32
+Nonce = d8c54463dfcf02d0e327
+Adata = ff95c0ed0da32d1b5f57570b815a50592ecdc9c1c4e727e0f6dfd93fc10ce88d
+Payload = 7321a6de8d694ea05623206f5df438c5c2cdd6b1eccab4d8
+CT = 9cf8ef119aa5cf3d6305d50b2b520a0b10bcd240e27276749c68e8e641b0120f7dd66e8f0cfa4205
+
+Count = 33
+Nonce = f690f3a996928275050b
+Adata = 41c05fda535770699ed22cef253753b658437f833afe65c9c393581d835f0fea
+Payload = 56520a4bfd7b73a471e0446f9524a407e81c2681b7329e35
+CT = 14aa15f9f64c4c64f6e88094e012ecb24193249f044c033dda44a62f97c0fead3f65b28928bfbcc3
+
+Count = 34
+Nonce = 26eb9ef25be62148fa61
+Adata = 8f45608a07521de86ed5a84a851e629b579b51d7bf4cc7202a773e0f9e9d8748
+Payload = c68094c26c7f017b79f126dc26b3bbcb95f97535ca412da5
+CT = 7ba8a0c2fe2b230768d1c1874085ddff8926931961bc4558f0d5444466bcc631bef8e58fe5818af7
+
+Count = 35
+Nonce = fad21bc27dabafe7a4ae
+Adata = dc5d7fd97bb3243ba585fa0d71a07191667af418e30a6b76bedd05b32c673403
+Payload = c247fa8d8091cd3f299cdacba7fb7af93549e9e3160f9cf8
+CT = 3097d2ec0f8bf00b22504ab03a75e740d3e59c269c3ee3f00b5419293a67eb008aef0f9f675201df
+
+Count = 36
+Nonce = c911348848fe67406dea
+Adata = 50d50a0b5ed4d6904ec3045263af0255a6494b7a7e2e95ea806c4bb788423dc1
+Payload = d846c170ae0111348362901503b26d58f5efc17b6d296aba
+CT = 5d72562f7dfb47bf34b90ee4ea11ff9f726c915b07f4d843dec5a554f4bbecbf6943ffdab8d8a26a
+
+Count = 37
+Nonce = bb921b46a16d20ae4046
+Adata = 7d17f8f60ad1e61a168b5b0e7fbbc90cee79b612b6d6c0d7ff6ede042341e8a1
+Payload = 71bb6ae84262646c9be95e0f4289ffeab7555ec6746c6ae9
+CT = bac123320888b553666249756e6d63b3498760791cbe9e34e5b1162b7489a59a50c0f0f3618e6c2e
+
+Count = 38
+Nonce = 61a8b8cbfc9bdbadb2a3
+Adata = 51cf2a8949e13eaa087a34c9ec4d7fd92b862efd6a0b1fef8b016fa2c6933426
+Payload = 362f9a46aab59fb6213c83d791b2129b34367ac2de2048fb
+CT = b8a57e8714d8789f4ef2af29e0efec21b1ef67fdabc7cdf0ed5505f1f0ff77723771338585c456b7
+
+Count = 39
+Nonce = 6bc4cd23c32a913998a7
+Adata = 92fbc970b5e64198ce2a138de92767edff8d82f12f8832444b346d159657356b
+Payload = fa442383da234cf8f0c5fb667218bc3bea0c091b3a8e6b77
+CT = cdfe3e83aba43a9804c5a1832e0e47a9a153359cc32db907714025f485c7f40256049f16f859b859
+
+[Nlen = 11]
+
+Key = e6ab9e70a4fb51b01c2e262233e64c0d
+
+Count = 40
+Nonce = 74e689eb5af9441dd690a6
+Adata = 42f6518ee0fbe42f28e13b4bb2eb60517b37c9744394d9143393a879c3e107c7
+Payload = ba15916733550d7aa82b2f6b117cd3f54c83ddc16cd0288a
+CT = dcc151443288f35d39ed8fae6f0ce1d1eb656f4f7fd65c0b16f322ce85d7c54e71ac560fd4da9651
+
+Count = 41
+Nonce = eb118fb41284bfcb1bc338
+Adata = b5a6067fbac46578cfc8d3fe04108588c9de077eb009249374f205553bba9d02
+Payload = 863da00c7accf45418d47c1eda72338734dcc49cd599f328
+CT = d64de7a56146b971e21bf5784d67bab32dd837cfb81591da4a0177883346dc896eb39e8a32bc1393
+
+Count = 42
+Nonce = caba2716d07e95de83855e
+Adata = 0e0ff2c73ea5fa8f8726a3514cf906ce1610a1a6dc19b22682f9e4619f762d82
+Payload = 2af6d5636ab65db2058b2ba16df257369fc4e8aef8b9481c
+CT = 3c9e006c7d8eff5f448b0cc9c27c964713241aa7fed3665d775ea25fb272981de8b8aa0a637498fb
+
+Count = 43
+Nonce = 314c136999e41d137bd7ba
+Adata = 366c659bc45d0a88acd54ef7eeaa3e140e1cafb1b01474a065a9d460c5e83bfd
+Payload = 217b19ea6a431a1f66bd9d02b718e8507a08ab8e6f603e3f
+CT = 33d7b672b23e8b03a39ff3fd1e7b0f2be67163e3e3bae072f2aaa211dec623947a50b1252bc5aad3
+
+Count = 44
+Nonce = 6fe51f5013f53d4e4fd907
+Adata = ff182f2e179d790e827cbfd0bd8b9297ecae57ffcef9e25ef114474a22e4ec5b
+Payload = c6bf582b49dd4ab6cb33f3f88e8a4d14fe32b308ee3b4682
+CT = 26cd5dc5eac2acda283ca03354260ad57af79e20c5e92f5775ed171bb0fbaa6f431c5411cf9b536d
+
+Count = 45
+Nonce = 24bc8dc1e2354667b79ba4
+Adata = d0d48d01fc79685c6bee04d45e40d06cdf1f4607542b1ece556fc2d1bb2b03f1
+Payload = 90f52ebb1bd5439386faeaa194623285f750672a7baae64b
+CT = a7f43f56c50705a1a101044b954414fdfbe32b518e934d38f391749ea3acd624c01e4583ab1506b7
+
+Count = 46
+Nonce = 89ce46b3de3afaf2518d41
+Adata = 5767202c913584d653f37d926a0c5ac1c67db3efd1dc58fbff998778a6856254
+Payload = b2ab379a0dd15baf91415eee3a4e56e7eca54d4c1c3094f8
+CT = 9f530e455a54b86835eacd8801b34c884a3b2ac819ba38f894e43a6b1cf73cb2d6a1dd8331549520
+
+Count = 47
+Nonce = d3208eb695e84c7a925037
+Adata = 91d8fa65a6885f162a795afe2898f391990a8b3a87c11f94734dcbddf5f58da8
+Payload = f15e39f0e4eaa5bf81359d8e30186522f1a1a415436668cf
+CT = 7f1d9fcd9e5cce3a81e3495bfecec817fd7180d8bbfe0abab27fb6425fcc3537ce471425a5b17dcf
+
+Count = 48
+Nonce = 067de2869333ed22c7b63e
+Adata = c31e441fd551b3fdfbe23ceec5ec1f838f31a5300f6055ad2a936a9d0c1c856e
+Payload = 1536d9c9a09302d142c85638202f5bbf0c287f68115d51d8
+CT = b1a5c7a7fd23228dc7ea26885802daa0719f6a23681e1d65dfb879c21b46f3307ef22f1da579303f
+
+Count = 49
+Nonce = 15f61b4526d19bceae1093
+Adata = b97b122af73e928e617e98684f845be4cb80566345739b7a884c6a3eec5102bf
+Payload = 37c81988c07a5b01e2b40ff9f9ada5f50ca764efb717ff9e
+CT = 0d93a5c77482d573b7f1b8c5e283f2571efc9f54216a4c01900504a73c8817ff2b55618b2602bf38
+
+[Nlen = 12]
+
+Key = 005e8f4d8e0cbf4e1ceeb5d87a275848
+
+Count = 50
+Nonce = 0ec3ac452b547b9062aac8fa
+Adata = 2f1821aa57e5278ffd33c17d46615b77363149dbc98470413f6543a6b749f2ca
+Payload = b6f345204526439daf84998f380dcfb4b4167c959c04ff65
+CT = 9575e16f35da3c88a19c26a7b762044f4d7bbbafeff05d754829e2a7752fa3a14890972884b511d8
+
+Count = 51
+Nonce = 472711261a9262bef077c0b7
+Adata = 17c87889a2652636bcf712d111c86b9d68d64d18d531928030a5ec97c59931a4
+Payload = 9d63df773b3799e361c5328d44bbb12f4154747ecf7cc667
+CT = 53323b82d7a754d82cebf0d4bc930ef06d11e162c5c027c4715a641834bbb75bb6572ca5a45c3183
+
+Count = 52
+Nonce = 6a7b80b6738ff0a23ad58fb2
+Adata = 26c12e5cdfe225a5be56d7a8aaf9fd4eb327d2f29c2ebc7396022f884f33ce54
+Payload = ba1978d58492c7f827cafef87d00f1a137f3f05a2dedb14d
+CT = aa1d9eacabdcdd0f54681653ac44042a3dd47e338d15604e86a0e926daf21d17b359253d0d5d5d00
+
+Count = 53
+Nonce = d8e133e7ff8e0a0ec6c4096e
+Adata = ef9e432c15d8c93a4b5c0666608e61c824cd466d7940d642acd3dc33057c0395
+Payload = 2836de99c0f641cd55e89f5af76638947b8227377ef88bfb
+CT = 5edb056d85dafeaaf74bdf4caa47339d6a75bf1ee998565e9f9cdf6ab825f6e026f5be2ad895033e
+
+Count = 54
+Nonce = 2fa8120398d1a946f391367c
+Adata = 377cd407ad28dc02bd3835a31d92f8295c9dbe597f56662ceda112c588dc73a5
+Payload = 7a37255b682766a0bfecf78e5162528885a339174c2a4932
+CT = 701f5f506fc7e9ea4a27a4db5cb890f7be3b4f6bcb20f97ed3021f6ad620648b8196ab1693710398
+
+Count = 55
+Nonce = 8d638ef43f56dece910139e9
+Adata = 87ea7b095388de70ac0ed23e86f502400910028a8ab5e3bbb91d05821c0d2d61
+Payload = 7370d9b453936955b9c9d336f4b283237986232de007bf41
+CT = be2f03f6ce1731418a5f53b6f6e467b73992a0c8102d8ffc2d236162688096d80b8733d2afbcd244
+
+Count = 56
+Nonce = f479ea8812b6b2f6ac78fe9d
+Adata = 20c2b8f5d3a65a66ba8a25e2ee339a779a32d45f5db91077efae6cf308feef50
+Payload = 59ff9f7581a781808d36fed378080963f35c00ea5a6e3932
+CT = d127c956349c16e2186f55b72254c677f03c61f1c4ada9e661bb9415b32d6a58f5f7647ed41de685
+
+Count = 57
+Nonce = 423515f7bd592d6a7a240866
+Adata = 19eef6f798fc68086aad1cda6d7976cdcfe6b8af74598032972c939db300d8c1
+Payload = 3c379f90b11c622a765756a15efc8fc3ca7b08b3281945f5
+CT = 15792e01fc17f5294c3405484291082c00a8f46dd9af8ca230ba95c4058501234a1b97543c998e9d
+
+Count = 58
+Nonce = c3f3da69e13c5733039744b1
+Adata = eedf00aab5edefdd6549d37ed44358e11c588c24f141dc5731303fe0bd56b11e
+Payload = 9db6fe9adb8c0fee87cac9a7f01a7ed8a84f0512d09b1834
+CT = 9b6b829ca1dc4e90d4402188632ea3377cbec2ba60f0f072afca1b08b6dd589a17a32d49b6f7135b
+
+Count = 59
+Nonce = 0a57d59f21ead5b6d80cd2ce
+Adata = de5f2d413c98c6ea2a5640a7b1c424aebe75cbc78b06710b5bff8bec6afb5a76
+Payload = 0b5f6389f7c20f4ba326e8f05d373ca27b7ebe59e6d729f0
+CT = 0b704e14bc7d2977d89e0b2e7ed7fe3c9e0f2ea80d2d6165f344f2f1b2218d9b4283fe640a6d315b
+
+[Nlen = 13]
+
+Key = ac87fef3b76e725d66d905625a387e82
+
+Count = 60
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f3898390e90d0a0899f69f9552
+CT = cabf8aa613d5357aa3e70173d43f1f202b628a61d18e8b572eb66bb8213a515aa61e5f0945cd57f4
+
+Count = 61
+Nonce = 2a27257bfaadf23a87df082c57
+Adata = 0001dc666c9daf3560daeaf514270db0b5075d295068e6caf231c1de0e1a9300
+Payload = 6cbbfa6d736fbcc4cf73ab4d7be537420e0e574ee1f2d1b5
+CT = 72d525e6bb312bf2c20b91f41108779789c25720797ebffa4cd9d735f51430275387c565cf1a69bc
+
+Count = 62
+Nonce = b94ac8ed14895c80a91fda8367
+Adata = e1eaf35fb266f243a3fa407cd41815ae6432ad79877bfa59d8f196cbf19bfbb2
+Payload = e6ec561496ce18d96b26d594a47ffad02d68ef25d2d2edb9
+CT = c63500445239bbdf71a8dfe3f8c01061d659cfeb038b825dc89fb5f507f5aeefaa9365f0b18dcb3c
+
+Count = 63
+Nonce = bbae10aa491ac9c668a3ba8d7a
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 9c629c375f014e162895cfc25a972c29839f97407e7c7cca83d0a61d453d596fbc5c2e315d9780bf
+
+Count = 64
+Nonce = e0b10e78e9fb41ee970143e9e3
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf3c99c9d1a35bd8e4ed36596789
+CT = 867799b30558697d6efb4afcfe458cfad8da21139a0b43128e8f8e13b7896b244d0c9aa52ed31a95
+
+Count = 65
+Nonce = 17b61109f5e37754e4e92a28d7
+Adata = 0bc2fdd890c19882640f8d4188b88b9db99cc1934cc3e98a5df08589287968a6
+Payload = 347c1eb4aff917bc0012f005e74caadc93f4f18f2b614ece
+CT = ee19f3120991b67b2389e6f36543d99590f2e6d785c9c8ecc40eb85585cc3b7520a940a4e993327d
+
+Count = 66
+Nonce = db3ca9e80ab761804349379961
+Adata = ce01369d08d37dcda2c899c9fc0d11ccf94a0051b2816a1d6c3ad07fc8dd02d7
+Payload = f0e1af1276d2918be91a191814660bfe735463d3983de1ed
+CT = 0f1b1228729b181772d7cf55ad257fbcb19cd46f7b31a885401358c7b44aea27617b429583103a1a
+
+Count = 67
+Nonce = 1f57959cecbd377374477e33b3
+Adata = de1c7c83ac61e1f99ae99b198f4af5d24f8de60ea98fe637f3a801fab38b2a4b
+Payload = 42a42b84df098ceb43519c4cb86c14c2fafca39346159e13
+CT = 12425453de653d0fe8103013fde1ebf4a8fe18f76f0c9d60e93525fe8048c3b2147a149f12eaecd3
+
+Count = 68
+Nonce = c9db03e2efbab713b0b6404210
+Adata = a2969243b0955402ab45a430fef2ef9e0c025006732bf8e592e3d3884918696a
+Payload = d633a5a3defdde6a68f959ef39a91c6ea6e13ef1a7859d2c
+CT = 5cdc183c32b4c1878eb83e8473a17c55c88e2ad6b944ab1f64ddee42614aa737231207636c114575
+
+Count = 69
+Nonce = 89ed296a3ac03fbfb71422b921
+Adata = 1ffbe1aff0a1e7fa3e68be31a74612a1519b59397e7007ef61fc015f316d55b5
+Payload = bff42516e30c92ed46710013c656600406a48a84c1fa32ce
+CT = e08c1ab4ae7edb5184c30ffb3e74689ea855f50b0e890392f26b130720f75c422fdf66fb174383b5
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp
new file mode 100644
index 0000000000..06e9ff5655
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT192.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = ceb009aea4454451feadf0e6b36f45555dd04723baa448e8
+
+Count = 0
+Nonce = 764043c49460b7
+Adata = 6e80dd7f1badf3a1c9ab25c75f10bde78c23fa0eb8f9aaa53adefbf4cbf78fe4
+Payload = c8d275f919e17d7fe69c2a1f58939dfe4d403791b5df1310
+CT = 8a0f3d8229e48e7487fd95a28ad392c80b3681d4fbc7bbfd2dd6ef1c45d4ccb723dc074414db506d
+
+Count = 1
+Nonce = 026a0b8b17be95
+Adata = 44caa8ecfaf38e5e773cb0366e1b04aa0b9fac5c34a362310f471960c4a1e1c9
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 3417044bad5fddd9455579123dda4fd342c273a57ff6333dfedf191496d88cbe17c6271b65096e66
+
+Count = 2
+Nonce = ea09fbe5da0fa4
+Adata = 1d9799f2bb0f7ab57fe3de27949ff64066131c81bfee172b308f9bb0b3171067
+Payload = 469ff9698cfc96b581d7115c822e4363d7355ec5daed2eae
+CT = 1dae7cc16f1b469290902cfad47b959784b4d6f48a79e690d47e30b635d10d1663477d61d7ffb55d
+
+Count = 3
+Nonce = 8d27bcbf9ebfd3
+Adata = a7070b85b7add9193c9dcd2e6c03f6e7ecc52ffe9e099866baf7472f20c03aab
+Payload = 225651d072dc9d93762dd79691ac2b6ddba00ec1252d69eb
+CT = 5da819adefbf794612eb458519debcd524c283763eb3d7252eca8766bdf0db6bb2dcc793e1749c21
+
+Count = 4
+Nonce = 13f560187b6077
+Adata = c4ab4244db75f8256e55c5b613a07b11c963c3cc24f66128aad4ba8b7ca99331
+Payload = a38231af405dc7b70c8dbc8cb84e6be8a0dc2e95fddc2ce8
+CT = 3aedcf8347aa23fd3325ce08b6b00462536baed69968a753feab6761c55431bb5668e1f5b7505e89
+
+Count = 5
+Nonce = 61e0e28bf344a9
+Adata = 5f998952de70449ad46428f2ff8a01c5af43c0107a1bcc6930f19d4112598666
+Payload = db21b37e875d7709a02239ce6ea529cf37255d5b617c153d
+CT = b8f5fed39c723d7643d6dcf2efd3bbd1ba0da1ec901305fd64b2302ace4f66216ca8b4d776197692
+
+Count = 6
+Nonce = f6be4aad63d33a
+Adata = 18339be863fb8a887d04ae9ff3b4a7db095075cd5d113a9ec87b41fe85ea405e
+Payload = e53101e6eabcda32c13d7b1dd1d88e7c2ca3ddc2064f64c6
+CT = b758858ab60e1630a0883d4d330119a593729a3015c42525effb985b9c2dd9ec954bd25d9c464c67
+
+Count = 7
+Nonce = 2c1c59aa0d8eff
+Adata = d44af86b89fda8448a9b2fcae20ea156dd8738c8251699c02b785811c830bf72
+Payload = 1fd7188a43dee7b059420e8634d71d2c0658f6d0d308dc73
+CT = d046f845a67800a5a58f461e5a8641e8fc9b4c53b32e61d172adafffbacb297d67f6b5c02b982e04
+
+Count = 8
+Nonce = 48e4598edd191e
+Adata = 61588bdc980ea2310e87dec4c651e9a55c27e3858b6505cbf3bf85e51931badc
+Payload = c25868f390af5e59c035cb5830e018c62c5b96bd35b764f1
+CT = 0ece161bd77b7f969b3b20c818769a98c178d84524544664500ff4cfe66ade1832babc019778acc3
+
+Count = 9
+Nonce = 6d576ce3c5fcb5
+Adata = 92c598cb5ca2926c11f67c3b3cf25493d77606fa60d7290430e0e975091644a6
+Payload = bcd97479db934357a163a9e5f5a85999ca987f8243d8017b
+CT = bee185e11b3d42bac846b9d92c70a078aebfa630ab763840391031b3a22b2adeb9791ee35765c8cc
+
+[Nlen = 8]
+
+Key = 1dd56442fa09a42890b1b4274b950770ea8beea2e048193d
+
+Count = 10
+Nonce = ad749d596d88a4b4
+Adata = c67219909828adef64422286008e1e306867a1c0b3da95444507a68b45c953e4
+Payload = bd92d6744cde446fc8621625658fc4bc00dcb97f06195ad7
+CT = 076cffd0ca978fe2bad411ced45a090abafb22a99896f6a75a1969276aa2b0cdb37ccaf2845dbf6e
+
+Count = 11
+Nonce = b1dc81d116d94f5e
+Adata = aa4b71906b6642f10f66c2391ec157c7cde97eb322db10045af4c5248807f691
+Payload = 9aa6dbe1cd3eb98d330c937d31ef93bee8938b6c5cfd38de
+CT = 720f6876ac91665f20147483f0655fdbe21963a01e36f1daa67e36d7cc8d54cfec0762514475127b
+
+Count = 12
+Nonce = e758738df5c89af3
+Adata = 5715fa238f432c926e62dd93708d0e3145428e0ed45e1efa8148d2c4ab6cba50
+Payload = ce80b99039a16e69018d1e3c239dd1bf06e94a78b0b1df37
+CT = acdf7ba3edca1563727ed85cabf085c2f0c8f27556c3c064ef50d85bc3ade6a773d956b2660ac367
+
+Count = 13
+Nonce = d586c4c67d535476
+Adata = 1e8dc63c6c54a540b6b02067ba7c719221cf289fa3897299722c9a2bd6eed05b
+Payload = 2f88305117f9a5d807d54b7e95ecfeb7327e52d9acac352f
+CT = e42b86e619be1a38973c934babeb4688243a9012c85d643d81e024aaf0a62b353f9bed36681288d2
+
+Count = 14
+Nonce = 77e83758f68d272b
+Adata = 25c80edef3d5bd8b049fa731215b80ca2ee9ee6fb051326e8c6d0b9e11e3d7ef
+Payload = 92e47b82b728d639777d5d5843de2a5c364956cb4b21cabd
+CT = 1b9177f5b76403cb8c690b39c3dd22b55da35cebccb9b64e05fe32f796f0b4a75a459fce6c7d740c
+
+Count = 15
+Nonce = 311dc245549206cd
+Adata = 87767f13bb4904d0df0d64eb22c9ddb65e81b5739baad86ad5e2c239ffde9f6c
+Payload = 8691c0301a216a5f3ed9123886d100309bd85630d6b845f5
+CT = f39fe3620a03b37a4bf457909e0770447b498ad2a2f0f9d7b75f9e4239e43bbf93066897e60f6fbe
+
+Count = 16
+Nonce = 2a17b70f10e120c0
+Adata = 981fc31e64fbad244ba1ef0303ba1e4beef5bacca74f60ffdb9142a25a1ad5a3
+Payload = b9bec3e2adc83620772048d6cbfb6f78e4fad74d754ffbbb
+CT = 92187955ee1ae702ef01a385537119b2bd4545402e8b2384a0c069a2439a2d8843302c6a9999e658
+
+Count = 17
+Nonce = e0b10e78e9fb41ee
+Adata = 9d072b8a3f1a496b2be6728a38b94a4f44c9be40c8793b69afd81d01696a6b4a
+Payload = cea28e7cd0eff0c5eafeec908d4aa8ba303e72ada33db087
+CT = c605e48f2e66e8e0a92471e466981ae5e31db3e4ad80b09f5005b06d15f63f2f015cfe447828da09
+
+Count = 18
+Nonce = 02d72dde23f9772c
+Adata = 2dc44c39940e2d9c94d2dbe40bbf5cca5efb4d4b250a31aa24f208b87e9c2453
+Payload = 809343e986f6ff47f54d4cac22ed39babd12271d4c7edb58
+CT = 0bb59581f22f6b15de76c0066645495a5c19e44381c349263ed92ebb789c314a89c83542b15ed694
+
+Count = 19
+Nonce = 28c4d6de3e2ce51b
+Adata = 913a8eda924589d3206ce0a951fef93668c6c0c454824b217997bff6b3026d54
+Payload = a19f65ffdafd6ad5ee43570f7e168f94a8b4a7b7402ac80b
+CT = f0c91a29f1222b906550ef5c7c0944c5c4236cb6c31122cfada8e796f2ce7f9449f42de504873868
+
+[Nlen = 9]
+
+Key = 8cc622645065c72d0d2aca75802cf1bbbd81096721627c08
+
+Count = 20
+Nonce = cd84acbe9abb6a990a
+Adata = 447b6f36acdad2d1cfd6e9a92f4055ad90142e61f4a19927caea9dbe634d3208
+Payload = 597b3614ff9cd567afd1aad4e5f52cc3fa4ca32b9b213c55
+CT = 2d7fb83e6621eed9073e0386d032c6941bef37b2cf36a4c6c5e36222d17c6fb0631c3f560a3ce4a4
+
+Count = 21
+Nonce = 1fc7a43ed124745d04
+Adata = c892b095173076a40e24522297be27fd3a765c8d417f24c71a9f03b3fe3d8e20
+Payload = 415cd8312dd20a1c26f4b90d98104cdfbe06739466fc0aa5
+CT = 7bebd6f55f15ae57ab73f92f7be6ff37ddd99740e988f01a7a2a13c22df4a156e6d6063235452c85
+
+Count = 22
+Nonce = 19ff5e7c1f2c594abc
+Adata = effcea4e4dbc57410426b39fcf51c9daecd9d310888590d77827973a29c4ebff
+Payload = 97fd2c259a4e672e9555a9a5b98f4c0ec8c4c49c7ade26a4
+CT = a460674c2f358762e97dfc958d90973e1e419dbc6a832e987579b2c4a6bcf0356f48cf8959cfa54a
+
+Count = 23
+Nonce = 64d9bd368ac2357cf2
+Adata = 62c5a16f946b4312517f67c80afe2614c822e3a01b87dc81538c00bbf3fc0108
+Payload = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f9
+CT = 8fb5e0954388b9b58519482962487e9b0768f0cee08afe9a92be2b06a0ecd2d00877abded7d9634c
+
+Count = 24
+Nonce = b4aaf2cd93efc0ce93
+Adata = 79d8841ab83279724ce35e1a8abd4e158168dcf388ab4c3d1ae70413e4e43d14
+Payload = dd42449da4c95e858b796085b6b5b3b5eef484dbf3c2bc8b
+CT = 893f86e29972928c1f3c3e25c73947c8d677814bca7fff2cf8d301ceace678f9bf91fc361dff5812
+
+Count = 25
+Nonce = 132f3e19e12f462a74
+Adata = 176cc5a280f6171d00e247edacc81f05c1b9faa87fc831163ac9d76aae59a6c3
+Payload = 8ea05a5033ab8b009664fa2800c24e217488ce6888cad147
+CT = 4771d210ea678dbfab96e320e9c44b68f47cb05b01826ccf42ca4f4ccf986eb6a6b85b99db2fcd93
+
+Count = 26
+Nonce = de709ba64cb75704c0
+Adata = 0cf8e9ab95766b6fa85e88d86e4f349a17c0d90509939e343eede988e7462255
+Payload = 51dd9fda9549f25dd868245a6a54b8d59346d2f336adf9af
+CT = fccc3e44afa6bd2fbcfc5c834db63dc9d152c04c0dc0b43d393162252ae91ca46fb8e8338cbeb75d
+
+Count = 27
+Nonce = b11b4c1b7a26387265
+Adata = 14ed867cc909c0619f366918a7d5ae25279fb137e1dee7fd98ddbe3bd19d841d
+Payload = e35ea4a16e274fcab457fd4dc7886c3d81fc668c19e0f374
+CT = dcca8aa2eab8ac3f5db9cd9560ae0758d7df40d7d868d1f71f498ea6ec8251a6d149c7ca38b25fe4
+
+Count = 28
+Nonce = 20d03227a7fcaef1ce
+Adata = c5c15245e641687d0ca9e913406acd2de3f21fbaf2dc5e4e8963222da61d02a6
+Payload = 6775e5faffd0b13e78da70a789042245d5ef31eab5245380
+CT = 4bb8ed2207f36f40f62d3a2c90f8e3bd8f589059b69037118ce3ab864545ea81943ef0ea9489d223
+
+Count = 29
+Nonce = 267f76b9ec0f5e7c6f
+Adata = 2b421be47d07dcb12a0706f7490d05024fce8f433079e18ec78f4c8678f5f155
+Payload = 9330bb23428ab45f573923e977db74882282cbe1371da68e
+CT = c6ae24f82ac5cf9c18a2d98e610027eb2566a1ccfcf99945655e14c7bc8be97ea47388cb7b18bcf0
+
+[Nlen = 10]
+
+Key = ab72eef2aba30205c986e2052d6e2c67881d24ae5fceaa8f
+
+Count = 30
+Nonce = d7a46e726ed43f1580eb
+Adata = baa86f14271b2be7dbb37ddc7c95ce4857e57aa94624d594d7bd6ceeaada8d5f
+Payload = 2a794b84fc9e4a7e6d70a82b5141fd132177a86b4e8fc13a
+CT = 2d7f76464417613bb61d3657481346b74fc9d6abc6a3babd39365dce86859cd82395d11bfc8cf188
+
+Count = 31
+Nonce = d0afcbc1b2524a4a4553
+Adata = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4a36bf523e89e9da8
+Payload = bfc5ce1316ccdbcd8ac62484e7656c87947ff98cbba8e1e9
+CT = 4772c121367d0e8d3edade883342395f3ea065fe7dd7be8c8355b915ca2633fd557ca7ed41e00926
+
+Count = 32
+Nonce = 6eecffd227e8d5349523
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c122e0b1587302894c391
+CT = e2864c6e12ac089daaa1e94af4b2ed04060d7ef65d2f72f0e7d017514d498f1f3c07d650afde8293
+
+Count = 33
+Nonce = a67c0675753f725a8fd4
+Adata = 7dd546397a9a0129861fb6815d419a307f90d259d55f3503961754126cd1b776
+Payload = 80f1f1ea46c92d28f2d60eab39ce056a4aefe63fa688538e
+CT = 882c687c03eaaad9d7f591649e736f0c1c78f95e40d40cd77499a8544bc2a8fe95f55fefc7316f8d
+
+Count = 34
+Nonce = eb83928f0d5f7aa3a74f
+Adata = 060cd3e4aecdb03837dfa9f544318c0a16cdc37fa2a3135be7888ac67e7eb26b
+Payload = 81e9174e9472777b6b184707108c01d6ea6b5d108ec3c6c8
+CT = 243cfa0a0a36a4c20333968910e6f52acc04c6f74e704180623f3a13fc13db958cbac49f7421d6af
+
+Count = 35
+Nonce = 5757abe01f7a1183fdcf
+Adata = 744629263041f0eccfce4a1ebcc18c4c984010f9241d35966263a8b2f72ee26b
+Payload = 991049f26b529af8b0bee0cc83989cf817d248254182f332
+CT = b20469b5f33f0996e8de869ad10ce09924a0bdd7b67a89a09c447a3132fbe5213133650000d50b06
+
+Count = 36
+Nonce = d9adfc5b44ad7aa94b05
+Adata = aa6a5448c6ec87be75eca35725ad2e902dbccf840d25b2bdf7e62e4a8fa4a511
+Payload = 14682301a99bf680805d1ffe62e1506d48cee8c51ef1d255
+CT = 9b44efa185b0c10325bb4c3c0815e6a6e46eea366b9a416b5ae554cb440eadd875657fd5cecc214a
+
+Count = 37
+Nonce = dc3ca30782c9c0a7fe89
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = f9cb86f24536931a1b095b426a07e4621c000cf09b472bf8
+CT = 463f9124d1cc387a0f8b971d1e2da448f0efffc3956ebb2af8312986315522081f0989838ef0429b
+
+Count = 38
+Nonce = 9523f53f92b6e4ba86e5
+Adata = c3b123ccc916d26a2e6a8b5e30041ad69a944217e9b402b7acc0170c31e8c2e4
+Payload = b9bdcac80f64175836ab51bb1a1bee5ffe3a6b9b71afe3ef
+CT = c356b5a78cebd123808fb740754dc47a8ec7c9448bfacf39768e94f062e86129cc9210dfcd3e6128
+
+Count = 39
+Nonce = 16bdf18c09d60f3a2a32
+Adata = eedd0796f23612749e9fd282c864f3118d0683409d3bef1fda352e1422273c7e
+Payload = cc96133e473d197be1bafdfc1a21d58e57d0d89b2ba1c3ff
+CT = f9d78e9e3a41b3bcbfe756385a3715776eb84bb7d8d15432978757883f07802b25e9a5b15c43b451
+
+[Nlen = 11]
+
+Key = af84c6f302c59aeee6d5728ed5da2e3c64a5a781c52c4d1b
+
+Count = 40
+Nonce = df990c42a268950677c433
+Adata = a6ab5d78427f297a4b7e21f1091ff3a5b20caa3fe1cbcb09459d9df596a6c8e1
+Payload = 6db41aeb5f7c24df8929dbc30483b3c7934b3bd1cdce5bb9
+CT = 8c9328258bf71970d33e23a3ff81cc1c9cbe196a1294264bfd6a7255e4801963bb30a63de3fc5b82
+
+Count = 41
+Nonce = b7ea72641bbe2dca6d85e7
+Adata = 4e0f2ddf183281ec131693bdcea3fc9743733c07a486a42d5737735b3f6e3fdf
+Payload = 726844e41b1e4d883024b32fee0dcea38c889cb328885b7c
+CT = 9a133e4582c2ebc445862a9c6f2f4e39223c84081e322c8f262de30da6ef505fe640c53d765f672c
+
+Count = 42
+Nonce = 446fee1e75e79c0dfc9ddc
+Adata = 42b598eaee271e06d9e98dd94152b28ef10f506d65bd660b2fb8b1be9a2d7254
+Payload = 0cdcf348ecc9c3588001802c2106fb64be9c301adcc66e73
+CT = 0c2657b0482b6ca92e1b1c8fdf75eae3b0cd3af205e9bca396ecb1e46beb16000d585e1d9559ee22
+
+Count = 43
+Nonce = 2e6e34070caf1b8820ed39
+Adata = 8bd1ef3a1831fcc8919d736fb23111ca3ef4cccaf20264fab8eb3b071e56667f
+Payload = ca0860cc1e96506c2beb25b53d2947fbab634f0372afc8ba
+CT = 19e4774030e43e6853ab5bf176ba9c4b59f29f285977e3c15198cbe3e34c884c3f56a732974aa1d6
+
+Count = 44
+Nonce = 428542ecfb94a745980aa6
+Adata = 8efe01716b9018084e2ea7616f85b7333d945c0c970f8cdd400130b98db67cda
+Payload = bc6b59120ba2845b0e41f65a55e2ef1c45a81485c926c14c
+CT = cb48b0af6fad251d409d14ce0fbfae9cd9c40bf4a0c1e2b7e7cec415030997e1ac5db974b617b5a7
+
+Count = 45
+Nonce = eff703e6d72ddd23ff52d9
+Adata = d7fc74035e66709d2590b7bb3276245dd43824c9896fbd801ec1d07018b39b6b
+Payload = 1a5432e8085511ddac1be91be3e2945f85f0cdcc3a1c9f8d
+CT = c0a00cbaec65b7ca525fb26e80ee0cd18c7ef47c39c704833e59bfecf263bfdb24686627fd95e120
+
+Count = 46
+Nonce = 6a652ce21334a40a259dcf
+Adata = 5d24d80f22afe713c4076c200c1bab36917907fde7b6d34e141066f543526db6
+Payload = eb8f1988cb405041bf48d138ad41da7ef364d4ac59a9e324
+CT = d4f23166c09a15466c7e0e2b30627ee5a84f22d7e6135b4a0652b67d559a84b4a915ca6a420fd300
+
+Count = 47
+Nonce = 9382e12d447c0ca23cc9c3
+Adata = 239129eb760f8a770410c160e4e13a6b9497077c3e463b65397393fcd3cb5c70
+Payload = b40e80564263c7f450c53ef84df67247d72e8a04dbb284bc
+CT = 6de2ba26caa80874814816154784912c55e3d6da83488e7250f5a52f82211542b4e2661cf870c80c
+
+Count = 48
+Nonce = 2c3a4148cbb02504a2483f
+Adata = 33c3bdbf185b580353de79e51e675b03b31e195f19ba1f063d44def0441dc528
+Payload = 60a31736d99c3dcf25b349f6110e1c152b93506e85a01e67
+CT = 4d5e705d08f3ed1ca6f1caa74b46e4b1eee18a0783686f207de16aaa41d06bc071657dacf14da754
+
+Count = 49
+Nonce = 691cdf6fe9ecc2154d0101
+Adata = dc096596644c4e09c44078b86e5e0887c45094042eb0d74a6a13aa2524463076
+Payload = 77e6441ee017a93dd876ff2c7980540c77ee15edb0f23933
+CT = 24cecc81c8ac7ca9906372dc5263f2220b4dd162f1e08283f07f23e65475a20fd96e45c6c695cd83
+
+[Nlen = 12]
+
+Key = d49b255aed8be1c02eb6d8ae2bac6dcd7901f1f61df3bbf5
+
+Count = 50
+Nonce = 1af29e721c98e81fb6286370
+Adata = 64f8a0eee5487a4958a489ed35f1327e2096542c1bdb2134fb942ca91804c274
+Payload = 062eafb0cd09d26e65108c0f56fcc7a305f31c34e0f3a24c
+CT = 721344e2fd05d2ee50713531052d75e4071103ab0436f65f0af2a663da51bac626c9f4128ba5ec0b
+
+Count = 51
+Nonce = ca650ed993c4010c1b0bd1f2
+Adata = 4efbd225553b541c3f53cabe8a1ac03845b0e846c8616b3ea2cc7d50d344340c
+Payload = fc375d984fa13af4a5a7516f3434365cd9473cd316e8964c
+CT = 5b300c718d5a64f537f6cbb4d212d0f903b547ab4b21af56ef7662525021c5777c2d74ea239a4c44
+
+Count = 52
+Nonce = 318adeb8d8df47878ca59117
+Adata = feccf08d8c3a9be9a2c0f93f888e486b0076e2e9e2fd068c04b2db735cbeb23a
+Payload = 610a52216f47a544ec562117e0741e5f8b2e02bc9bc9122e
+CT = 83f14f6ba09a6e6b50f0d94d7d79376561f891f9a6162d0f8925c37cc35c1c8530b0be4817814a8e
+
+Count = 53
+Nonce = b4cadb5f9cb66415c3a3b714
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 22bade59214fa4b933cb5e3dc5f096e239af4c2f44f582b0
+CT = 2296e3f8a2245224d274f1b90ed1287cbeeb464c70a89ee475ecb546efb8872a3f8b0281b3901752
+
+Count = 54
+Nonce = 72e6cebdaf88205c4e744286
+Adata = feaf010f462ad40a38eefb788b648e1cc292cd4bb08ebeff3c39182862296042
+Payload = 30655a6b5a5965db992e7248d24141055e988d726abb8e72
+CT = 69b27f2bbaa61c4f24e1c25e0779147fef79ec1582486b4651cffa571570618e2ada3376bd9f3e5f
+
+Count = 55
+Nonce = d8030fb31eca2c43f3f5eb88
+Adata = 66704365ddd0145febeb33f68b228a3f09e1e5a4b68149e6e06d886301841295
+Payload = 9d014a02507a6f266bd1ace21b55ab8b73983ff503bb9adb
+CT = 233a883650538ab8c0da30b90527f880fcad5b16bd435e762beeeea7a638c717e63764b3a5118a0c
+
+Count = 56
+Nonce = 58038cc35ad3dcd75195e125
+Adata = 3da7a757e942409a3b39ccdc0669ce6401f7e133c07c4c42e366d70a8e9bdd49
+Payload = eccfd817fa5e3a0146967fae13fc2471ee3944cee37969f4
+CT = 415a36872a04f5b4b5372f63394ab9fb353e0eb9b430450133a87fa29e5fbfa9bc0430b0cac00b7e
+
+Count = 57
+Nonce = acd82ae31bfcabd90af5af45
+Adata = ce22126f01bde16249c47102b4da68ad3edebcd4a16c24a16ea7ccdd5d364d10
+Payload = 9d2126d34963d3ba12cd841bd321036cb82cfb78f2a6535f
+CT = 88a5b889e6fd74fc15336e23374b430988416c7e6b6e7248b336cbbeb64fbebf2e7076a98ecf5bbe
+
+Count = 58
+Nonce = d24457d567fd0a65fdabf219
+Adata = 0091d39f3478d2c59bf874b96db9ce0f7e8b85a9b805e07dc96b219819d51663
+Payload = 6da3ac85505e93c4f391ea367a9e15fa9b388ef7ae2693c1
+CT = 7039a8a49cfa6402b4ba3b840e69200c13ac4a3eb1c709a30ea909047af4998c660afbaf346ed65b
+
+Count = 59
+Nonce = 50c59ca54eb64575b82b13c6
+Adata = 5e4e42cbf172853c351d597c7d6d38b1a9cbb7ac92c00863a80ac4a2d9f0e7fd
+Payload = 25b2ba0a937b71f3ee68e7172cf2c4524b662efcd08ce2b3
+CT = e95fc44287ce39c5ad6b91c88582563fa68a9e304094deb8b193dd767f17783f0b51ac0fb7323301
+
+[Nlen = 13]
+
+Key = 36ad1e3fb630d1b1fbccfd685f44edd8984427b78deae7a9
+
+Count = 60
+Nonce = 3af625df8be9d7685a842f260e
+Adata = 308443033ecd4a814475672b814b7c6d813d0ec2a0caeecbcaba18a2840cdb6c
+Payload = 8b9db1c8f9b4892a5654c85467bcffa2e15e28392c938952
+CT = 6bc6890fee299c712fb8d9df9c141f24ee1572b8f15112c2f8c99ccf2d82788cf613a61d60dae458
+
+Count = 61
+Nonce = 24eaeaa437649e61b706942b8d
+Adata = fff75462f96157d9554bddb6aac156fefd88fd4a90a8536dfc28cc577f19c83a
+Payload = 49ff4ff85f7407ca383cfa4fd7177adb4dab26e642c8186d
+CT = 3647fae50c588d792442f43a20125e77ab5db3c469391d24d0a421bbbc002eb9ac9ad01f625f824b
+
+Count = 62
+Nonce = 7325932d6694aaf61a8204c172
+Adata = be20ceb8ca14e9bef7158b280a26bcac763da79cd0eba9b1833ea808c5e7a66a
+Payload = 2861494eb40b9d964d339797c1b6aac63c6674187768957c
+CT = 286dc74001e2a6000a23db164f4b2912de4afcf1df8c3aa5ee32a7ffd4e7bc303d3482fbac431828
+
+Count = 63
+Nonce = 61c9949df5853e42599e5ee0c7
+Adata = 243d09ceb16755cb58d62065df84890b840ad9b7eec1132c6427cd7c3d843fcc
+Payload = 943a49073db6ae94a88844ed895f8fd99ed25c3f42a2f78c
+CT = d3c56bd265a2cb0811dd218f248800ceade4f02b5403b9635eb30cbec49cbb51c41cd5032b7fd759
+
+Count = 64
+Nonce = 07b6c18dd3b0fd9e8ff026a436
+Adata = e85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b8ca9f321a178a2056806
+Payload = a18b0a4618063c0519818d113b8e5435aaf153f664058f1b
+CT = 69f933a2a5e774e8d013cbf78c6ab0b73e6ca323d0c52691acb5cf2631987d3d963349b035324aac
+
+Count = 65
+Nonce = 0c075df70630dec2fe81834945
+Adata = f3f5c5ffbfe8247bc0c33c793652f749fe91b6dd141cf0db56e71cef8a2fd266
+Payload = ddc4bac4115e8cb06d29d22e400674dbc615a667f933603d
+CT = 26bdd25c9f204fc7520d26c161464c28fb35e395b295b3db4e239d33283d18415b54c2aad4bde354
+
+Count = 66
+Nonce = 0c2d20375057fcd4241d290f6a
+Adata = 70ff1b9ff8ec08fdb18b0e7dbe01127ed0cfe0b0a449ca2ace4992b7b6248b71
+Payload = dacbdf1979e000d52b573e74800761b30acc26681f372acd
+CT = 6a642c389433a3464fc64783ae6a14a9a45f0998b56a5b9162d7e0320dc930df3640a786d7ea9ae4
+
+Count = 67
+Nonce = ea0801cb3dab853750a922dd25
+Adata = d83360d0896e022bf014bd33710ab212ddedda6d95a54996f33db304e5f12f01
+Payload = 46cc5653bbd8300dfb0df6d0af3fb7c7639a830bdc9f68c7
+CT = f1b0728920351d9edfdbe7df360b21f6cc5b628dcf43a3f10d06b4a545609a2128a95d4d73471559
+
+Count = 68
+Nonce = 97e6de379c90fccf3fa8f27013
+Adata = 539f8eb802bfecaa4fb5b19debbf3d4847db9c4e0473a308ab3f3c859e68fecf
+Payload = 8b013f52a828905013f250fb9c006a173f6c66a64b5ba317
+CT = 556a439bc979dac1cfea8c5b64aa78547f52a62896c19893f3512baf72cd79ba9301194be204bcc0
+
+Count = 69
+Nonce = e832b6330d3e5e190598cb9c61
+Adata = 093be516277e8b197ba5e9c85a831529befff0f3971510ab611dfe0dfb50a2ad
+Payload = 635d2d7894bb816f154210946a369df37ea492993ba23af9
+CT = d8e19c67e5aa7f14a16ecaaac414a2b15a15bb5f966932e6b0bfe9a5857fd36df94aeadda7f83a79
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp
new file mode 100644
index 0000000000..2817684910
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VNT256.rsp
@@ -0,0 +1,456 @@
+# CAVS 11.0
+# "CCM-VNT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Tlen = 16
+
+[Nlen = 7]
+
+Key = 553521a765ab0c3fd203654e9916330e189bdf951feee9b44b10da208fee7acf
+
+Count = 0
+Nonce = aaa23f101647d8
+Adata = a355d4c611812e5f9258d7188b3df8851477094ffc2af2cf0c8670db903fbbe0
+Payload = 644eb34b9a126e437b5e015eea141ca1a88020f2d5d6cc2c
+CT = 27ed90668174ebf8241a3c74b35e1246b6617e4123578f153bdb67062a13ef4e986f5bb3d0bb4307
+
+Count = 1
+Nonce = 195c0b84baacc8
+Adata = c7d9557b2ed415652ce6faa8cff5217ac803530ec902890b31eaaf3eeb0aa98b
+Payload = fe012718481b2c4e1d7f9a7685e3daac43ccf22cad0df900
+CT = 893af0f130f1317de9f217234274b0c04fcc202cea9a0df882c00b5b463654adbf82888099a7d258
+
+Count = 2
+Nonce = 363e0e921c6f11
+Adata = 805678936d4e94746ab4818dc5f50c41e32cf32e7a8aafb300fb91af6406108c
+Payload = 7e7e33e1a07d4e8fde2f33304f21cb564d146860ccfeb49f
+CT = 645cdd11a1c232815ce1e07ca3ea83f372eba46cedafddd980adf2762a1617adfd4d8356bb48aa8a
+
+Count = 3
+Nonce = e323cc866af462
+Adata = 163c747f3ba4ffd68af87f2475f48f2714659a2ec43b9ed115e02fe0e3c8be99
+Payload = 2bfc76f3b108ba3118b07433c4d3d5f41564d22547c12822
+CT = 0db04c6b068e73e3c4d71059bdeee3d27622f99dfd07d868fb9c02753c57fec7e1a5fa8f3860501b
+
+Count = 4
+Nonce = 03ae777078b95d
+Adata = f1dacf9062dff9a6a3d0498f9d058782f891475684196bf2d8e7e905393acff7
+Payload = 38c4275a5f605fd1d99517e13deebf0c9794ef586070fa9a
+CT = df8f524872b5f06f3f219ba76524990b466409894930d7e0d104990e598eabd88cc8342ac16424b5
+
+Count = 5
+Nonce = 1c6c351d4fe9be
+Adata = 14285e97cc3cae452e1a52e2fa0bbe24df96abf2faf6b9779acc59764612eadd
+Payload = 9e2220f3c17532e1ce0d6f562b049fcef35bcaf9a7e196be
+CT = c274b28228a6b13b670c325080f88d188d40d78d385481eae004894b1861db5d2d8ae98ed8926c1e
+
+Count = 6
+Nonce = a121dc27479397
+Adata = 359421e9f78cc4a31f4f019977d7fd29780524e20288798c50002a682a6368b9
+Payload = d42b16b32e77637724144eaddb21ca8d7db4e7f73acbf707
+CT = 56e3e3e59e978161355e7d8573dc0657db400ca0b083dae8ed2ac2cb63e1b9d7dc598634198fe4fc
+
+Count = 7
+Nonce = b1f0e26b60bf1d
+Adata = 2ab4239fffd13762fb5391f5a4760d12d96ea12666a793b4d651e9f4891c22c1
+Payload = 9a2851083ad4e7b915bb0526bb4054e4c0b4adf8626edc90
+CT = 5b2e0215523ff37f0df46e84f996fc9fc779986c766fa51595b8a23ee377d5c2850f4ed95a385253
+
+Count = 8
+Nonce = 50412c6444bcf9
+Adata = 09cdcaa87ddf8bbe6db8411d14bb9064e4a121286cc8a6e97fce1844935f436b
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 05cbc32a6ca797684636dedd16ce65a1eed69bcab1b1bdbd514ef5cbf9991a919fb4974d55506ce1
+
+Count = 9
+Nonce = 225557b0faca3d
+Adata = 21611da060fa90cf7fd68b721caf303307a56e56453326495b628c7dc93cd175
+Payload = e831b739e8eb9f787f63c0bb071ddcc9f44cab8d5b447d23
+CT = a97e0879407eb3b7f93118ca73f17eb34e9f4baf43b07be2e8a3f7b848054cb235e1b58d6a12c5cb
+
+[Nlen = 8]
+
+Key = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+
+Count = 10
+Nonce = 790134a8db83f2da
+Adata = a7a86a4407b7ecebc89434baa65ef173e88bd2dad9899b717ca578867c2d916f
+Payload = 59eb45bbbeb054b0b97334d53580ce03f699ac2a7e490143
+CT = db4961070f528ccd1a5a0681ee4d0ce3515fb890bccedc2dbc00b1d8b2bc393a8d09e87af7811f55
+
+Count = 11
+Nonce = fb2441d1594a488a
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f26652249d59dc974b7361d571a8101cdfd3
+CT = 1bca7b0d35a68c0ffc568ffc8221cca738b67b95e3ab26efee21c5738d1f7fddf3030d004a702704
+
+Count = 12
+Nonce = 0855263860043207
+Adata = c7fc24863c33f7e8cf97b337918495d52d864ac570c99cbb09d151758d6b504e
+Payload = 61fcd7ef9bf151b9d8a81dc1ba4f82c45e9c2e4784627acd
+CT = 9b939b6b188e1d0fe016f366fb01eb79a99ef7b1b57c6f7ab223454c57c714d96681cd4d55615afd
+
+Count = 13
+Nonce = 415cd251a5e36943
+Adata = 1a393c7e85fb286709f4eb50f09640e1d65ec1135cb4443820136b3cec69772a
+Payload = 66ae08d494dc9df9b7f8f53199fa37d0c88885458b168c57
+CT = 1731e260ae31b8068ad1099313b167d9e6cbe49f471da61a9af96d3ce4ea94213b60cb69d92050e6
+
+Count = 14
+Nonce = d95bd65242bb2265
+Adata = d0e20e1358be5cc1c45c1cf02c82d0a6d0824cfcb65774cf95f047b9f2cc1d3f
+Payload = 312c3791c64d79205a11eebfc14b2d7a6b00391793c9559b
+CT = c3fbe558ff9ea83ed86b7d66503ee38eee94e4a41fd53f0f627a352d056712e0d44404c61712e2ab
+
+Count = 15
+Nonce = 3f0bf0141dd3ace0
+Adata = 9dd4ed18209dd6cdf19cc76fee443827e7331aaf020960c15d7bbed0f6a3b1f7
+Payload = 08354480047eee3beeb5ab165da17d23f2f1a4ad98720611
+CT = 2db9d2c54134d37ebefcecb9e2076034b975677fde58ef6032645a322fa9bc8aace600f942a84db4
+
+Count = 16
+Nonce = 3fd8b3a3ff563a42
+Adata = e58327efebad3276a7cd1b1ccb56db0caddd02a303cd9fc7ea5c607a2ebefaae
+Payload = d1abd89351384e1a3c3366f77c3175f6390801554d7cd783
+CT = be284dcb357ae99ada7cc891730320ebb32ca627eb8c80623957a2a5b6164218fc83e12c42d5c532
+
+Count = 17
+Nonce = 14db1ffc1c87117f
+Adata = 6c2b091433833a0ed915354dcb70d982095b614dc51a95a22cec417184d8e786
+Payload = 0594307491f157821e63f50c94034f9284f095d5b897153c
+CT = a114c84a10071e359bba2b2ba4ea67f893e27e6ea880aa4b2cf16ce68a93f8839245baebb2278300
+
+Count = 18
+Nonce = 40b0f74ff27a3fc8
+Adata = 3b9e1f4e9b57a6dfb5e0ca7ef601fc6af30a1f8650228e51e0dc61180d0bec6b
+Payload = fc8b7dbceef6b0ffcbade789e09303044042cd671607e819
+CT = d00ef56074a8213740af8b8f974f778db560ac365d6ce916b8d191130e864bcfcd1dec94a1aaeaef
+
+Count = 19
+Nonce = 96cbe9cd19351359
+Adata = cf498fd042f9a07503e490cec4873d4df91162cfde60bd2cbb2b710c6681a9fd
+Payload = 315e81c9ce556dcf97a5b68503fd2228a7a6a174a15cd618
+CT = 7383c2de08bce3f0b7e504dc03d062f44396bcedd2180fd954e6ec9f6ae1e0976ecf04dbee6463c2
+
+[Nlen = 9]
+
+Key = 58ae7965a508e8dd2eda69b5d888a28a1cb3783bad55d59d5b0da87137b72e93
+
+Count = 20
+Nonce = caa3d928d2bf2b7f2c
+Adata = 304678b3ffd3200e33a8912bcb556b3cfec53ca17f70ecba00d359f9f51d3e3b
+Payload = e61bad17640ecff926d0b0238271ee4c9f8e801dd7243e9e
+CT = 7bb1137c14cb4d324a4a8f1115c619ebf74927f0bed60a8d5a9140ff50dc4da375c7d2de80de097f
+
+Count = 21
+Nonce = cf09ca67659a583bb1
+Adata = 5507c4c3107cb446d19975f91207dbf3e2a51d1dcfd7da2f082159dbc3f41547
+Payload = 1887bb0c02500093a30a44b99e137483704b06615d308c6b
+CT = 834d3b2e5f0915c2348c706b4d2ff2717983ab4490edcc63971f02b7122d1e4f78de9c3376520f5a
+
+Count = 22
+Nonce = 97f940d7c1230bd8d2
+Adata = 56be2c9e09b555373d58f6fe2a0ca9b4ddba899addddf12b0fda860ad791773a
+Payload = 5ac67c9bec9b95c54e187a4a6812f5d701c4ac8f847c005b
+CT = 9f372ba1c87a115847cd708aaf5b8a143b6981ffc2c61cefd30ece13481609809b218de04c4e5ed0
+
+Count = 23
+Nonce = 147c7ebb6c92245054
+Adata = f95d64a513a9f3e6c95c9ed27b22fafd7dd10da52636029523142149116aff53
+Payload = 08f199a8d7e3ea821dd3106e8947cd2e9d485342b25a6471
+CT = c438aa6d187643d030dfe4d6b5b578f84838f4dc5c396d700c0986ecd7dab44e5e97db37392a485a
+
+Count = 24
+Nonce = b9bad794d49cdac9b3
+Adata = de9ff2a43f49cdc502cd17a373989bafd13fa6ccff6660557ce05b6295186d47
+Payload = 40d1cd4063750184356a1d7cae1cf1824f552c5d59a62dc1
+CT = 9952b25f4f4f375440cd958456184fe61610381ba92ca48f38dd977042c4d97da84e4effa650799a
+
+Count = 25
+Nonce = bbe054fbef86db3ce7
+Adata = dcec76181e3b872a5a6e79f070354e38866c7f67fc428fbca29ae6d929b1dd7f
+Payload = 5f29808ba74b672a0f82b3b7581dc32478c6e790e2b8c61c
+CT = 4d176f48b09b772dde8adbdaef720aba128a8d38a902847ebf22c81a5d824b4916660be6f9b513e6
+
+Count = 26
+Nonce = 6a35e1a4307f6efc6d
+Adata = af28120505a84a75b0f6b18cc9d8c75c661bf143be29c11d8ede78b9bb98c98a
+Payload = 5e2f601395ec406fcf96785f768162e849f867dca77667ab
+CT = 4e305e26d34711c6aa775f490939cc6560d3cb6905f5b0f5588ace6fc303600abc8e5825cbaedc7c
+
+Count = 27
+Nonce = f6c237fb3cfe95ec84
+Adata = 038f8ed89444784417a9c23bf11e9b436174e6c10959e00faa1704ce2f7f2c7e
+Payload = dfd9cacbf7d73d688447ebab13d2e13f3613652379b386f6
+CT = fb16c17a6b22a8658f446203ad46a48b34808083b271cabb015a1f78abc287bd2a63381ead07c558
+
+Count = 28
+Nonce = 50d024a3e7455d7249
+Adata = 8513365786b7988b208984e11022c15573f978bbdc29e8a7a4745c8a81885a1d
+Payload = 400317786b7df63373ffe541efcee6318cfc95bb673aad3e
+CT = d33b3141fea3a9ebdeb80d1da32dae42680be78471fb3023721f714120162514555b60560afa4256
+
+Count = 29
+Nonce = 02769283d5a06c363c
+Adata = 292c0be3713c6c588cb4e29a1c43b3e6353e33556194e568e800e4e44e8281e0
+Payload = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb
+CT = b15b1789c323a68568f86f35483bd7e204beff8f318ae14351f5e62b3b923a937e6c307af202fab3
+
+[Nlen = 10]
+
+Key = aecc5e18088bf9fd7b17f089bdd5607b69903b04b726361f8a81e221b1c91891
+
+Count = 30
+Nonce = c527d309ab29ee91c5fc
+Adata = 8f9a73e7bc1c11e2919020ba3a404cbddf861e9e78477218e3be2cd4337b278d
+Payload = d4291c99901345afe29f58912a414a7498f37b44362bdf3c
+CT = 392784a9e0b14bcd37639ec5409d6ead3e75f855e5a92c33ffc040ef3977e0035ce6ea6d157c18d3
+
+Count = 31
+Nonce = eebc31a5813b4fb93b63
+Adata = 9c87ad77953bf8a811e001ddb946eefafbfaa598150e85f0701853fa307d77d6
+Payload = ebcfd71120b0f9a2cccb898e6dfa082998cbe10032de3e61
+CT = e38eaad1e2df77e85e7129a8ce0f82cfc32b0aef79ab651bade65aa17e4dfb0aafe18cf71a72b180
+
+Count = 32
+Nonce = 231b33dc406c9210f59a
+Adata = 38be46d271bf868c198052391f8a2147c663700d9bb25a0caaa36974f18dacea
+Payload = 9032f910347daf661092b5c1f15b5ffed1369b194d9e12f0
+CT = 868b85288828501cf1d06610fec25e8b8a4b437e2e4f5563b7f3b898a2356909784598f8a8916f5a
+
+Count = 33
+Nonce = f2a88c3ebc74e62f24c7
+Adata = 5f495c5da035cabeb77e8aef10e91a05bd5aa414d1a37fa1099af959b26e5403
+Payload = cfe8ee9b475e36058471e2984ae66f6ba1b3cb477b15155e
+CT = 22c16333ac651cd9c183e78aba3e9312fb3b77dd6f9199502788860aae5534cf84979e30c3327d37
+
+Count = 34
+Nonce = 9cbaf1c83ba60b1e90ea
+Adata = 7ef136bd9a5809676abbaa68016d6fc713e34ac4b768a8246b1198c959f43085
+Payload = c3bcb0aaea93893f05eeb6439c8619dec17670a6439e2921
+CT = ebd9fb86563aa8f10062624441336f982c161ce5717d990a599ca6ec1c61a14c37b5902389e47aee
+
+Count = 35
+Nonce = e25322845d87d8a76753
+Adata = 2a89b9f0e56a1cf87dd38ed78028b6286ef8b7141dd2b3c65c5a8e1ed79bf4aa
+Payload = ae622ff9381854f831892c318bae5c003e74b15199bc12c0
+CT = 144c920f0fe278f353d0b053563d907c7589e4f1479d7a93a0604deb3fd9cea2d89987833ff5c2f1
+
+Count = 36
+Nonce = f4d7978fad36223623cc
+Adata = 8671de7e994967f2521d263925e745af9273682d9c08ced07d4a98fc985f68a0
+Payload = ef9b4ff8da108cabc972192ffecd5f96594c6d0871ffa6aa
+CT = ae4948b3bc1e50beb9f5d005871fc0d3dbde295de1c9ec3cbc866ab47bea7a4d0070e52b492fb8f6
+
+Count = 37
+Nonce = 6597ffb9eaad0fd9d830
+Adata = d2967ddf69ef62a9e23c9118dfaa55df92b4116322f1c9275131e3875dc92faa
+Payload = 5015c894b2437ff15c46bca9236830ff4bb057cd5764f027
+CT = 0b1dcb3cb0b4c32f398f3c43eccfe8f4242f33c99a2a2283efcb3dacac25bed0304f227fd5b77b8f
+
+Count = 38
+Nonce = 80e376b87272d99cde28
+Adata = c9cc8f967dff45c05b9345d03813b6e30dace99556f7df75b7120bb6e5f55827
+Payload = 615f657e24129a3e0f119988959608821219ce8354c4be26
+CT = d3e8b8f7ff8faa666ffe2509187fa7befc7412fd4e3bdb06cd2f7494b1fb0a0c6a2184e5c4787fea
+
+Count = 39
+Nonce = 344cce96455541d403f3
+Adata = 748cce18fb40126ce125dbe341fbbc59d2aacc170ed5ef0293b15713c9184a07
+Payload = 828b6a4cd49f499a6e8e8508f9ab35255d8e9fed33ba4d91
+CT = b67e582a74d7f022a16ada2de7ec18caafdefa6b104baf4ed93b6f8c8a1bf72be75976e4ebe6dd1f
+
+[Nlen = 11]
+
+Key = 97bc7482a87ba005475dfa3448f59d4b3f9c4c969d08b39b1b21ef965c0f5125
+
+Count = 40
+Nonce = 0bcf78103ec52d6df28887
+Adata = 049c10f0cb37ae08eae2d0766563b7c5a8454f841c2061a4f71a0a2158ae6ce5
+Payload = b99bf4dc781795fc4d3a8467b06e1665d4e543657f23129f
+CT = 0d3891fa0caac1f7ebe41b480920ffd34d4155064c24f3b17a483163dd8f228d1f20cd4f86cf38fd
+
+Count = 41
+Nonce = ab6374c6b2faefd92fa3d3
+Adata = f19c044023e5cf339203738ee70e76527519763664c06ae00e002a5ba94c32c6
+Payload = a2e5c51f516db01688b64c173bb25645182a005018022ee1
+CT = f70c598df3c64d3527ebb7fc8408b7de2cfaa1da7984ec361f1ad61758d828b70d4881b7d6ae8cd0
+
+Count = 42
+Nonce = cfb89e7ddcba601e875110
+Adata = 052714010da516c896ac5842a839ae845324643cddb080e6206148432d0d0407
+Payload = 037f206cab78a6ca0745dc8fc137e22e14f3d7183917ef83
+CT = ccd675862502a2e2520a33250150b8b7b220e84db854888c316dd62075fc761e2bc80edc5c564bdf
+
+Count = 43
+Nonce = 967cb6f8530bf8a43adb42
+Adata = cf391a84d03e2e22aec1965cec821f99e7bf21a7c3580dffa531464b22d83225
+Payload = caa3d928d2bf2b7f2cd8a7f357055b6d6895a5e34f47972a
+CT = 4f4f509debe6e52eae4af8b1740dde0a5338f78711a3b4ebfc8b5aca6d606222d6af7cfea0d1f4e1
+
+Count = 44
+Nonce = f5b7b5dd2b5e1ec93710c9
+Adata = e7a6b228a67d37b9d29a38efc547e50b4a6d95d599b45ee189ece21101ac6b5b
+Payload = 4a74ff35418723f2cecec1012484b52114067b2b2393e7f4
+CT = 25b140922a9d4f2ce153a4ff86596a49d7de6a6184e931e8b2ff27a98029b23484e00c2a5d291887
+
+Count = 45
+Nonce = 713de00faff892977d99d0
+Adata = 14ea93488d4284d21d4c7ce14414adf45c1ed9d2d99db866d0e59accb6234dac
+Payload = 3820db475c7cb04a0f74d8e449f026ec951fa59667738698
+CT = e4d92ab8d1ffb0976670d891cc8338da12f86d5d79b334103d2ae816edf857c810b6fdc7f2c71f1d
+
+Count = 46
+Nonce = ba87934808de09b2ae829b
+Adata = 30e2ea2a505f19e8760a0a84961000c7a0b7fe3460a9d3f5a38f54149be2e9ee
+Payload = 0e52a384cedcdf7f179348de6e7336aa86f8855fbd903cfa
+CT = 6df893eed2be958e5f542f8cb4adb392b34786cb4ce821ec93fc57997b977948d55bdb026db5bc48
+
+Count = 47
+Nonce = ea09fbe5da0fa4fe911e18
+Adata = 237dc8512b29bccdeb8ee39cf83b9b6dd203823d175c44d5f605b194e7ec136e
+Payload = 41cee0ecaf9c65cef740440af37954ef49a585779d2abbca
+CT = 2f204ebcf549ee2a800d870e6341b9a89a41ab4ae91b6902ff704a2bcfb8becd0226f76d68fbb08b
+
+Count = 48
+Nonce = 5b80d7affc4ab4a4b68bdd
+Adata = 3a38dd7da30f5c312fb1e978d87b7a39792fd9ea3e9ab1565874e99df587327c
+Payload = 5ff92f6d3ca791421363e10cc84b4e8e21e0ebe5d8c55d6c
+CT = 05472db7875d59f8bed45606f355a516de93740aa2baeba18df9400df42baee6b9a0d75b45840104
+
+Count = 49
+Nonce = 514bba483fe7f2b7e555cc
+Adata = ac8beb419099cdb42a39e9b46fd900cc52eec4b43a96ed18b37b899b63fb931c
+Payload = b0b11dfca9b3936d1b4a423c5acd3d012b399a487c19c994
+CT = fa20629d514c4ce7bf727629bca5aa1c0c7e7851fc1bfc5c847729a70d7b4cff5281aece37006015
+
+[Nlen = 12]
+
+Key = d6ff67379a2ead2ca87aa4f29536258f9fb9fc2e91b0ed18e7b9f5df332dd1dc
+
+Count = 50
+Nonce = 2f1d0717a822e20c7cd28f0a
+Adata = d50741d34c8564d92f396b97be782923ff3c855ea9757bde419f632c83997630
+Payload = 98626ffc6c44f13c964e7fcb7d16e988990d6d063d012d33
+CT = 50e22db70ac2bab6d6af7059c90d00fbf0fb52eee5eb650e08aca7dec636170f481dcb9fefb85c05
+
+Count = 51
+Nonce = 819ecbe71f851743871163cc
+Adata = 48e06c3b2940819e58eb24122a2988c997697347a6e34c21267d76049febdcf8
+Payload = 8d164f598ea141082b1069776fccd87baf6a2563cbdbc9d1
+CT = 70fd9d3c7d9e8af610edb3d329f371cf3052d820e79775a932d42f9954f9d35d989a09e4292949fc
+
+Count = 52
+Nonce = 22168c66967d545823ea0b7a
+Adata = 7f596bc7a815d103ed9f6dc428b60e72aeadcb9382ccde4ac9f3b61e7e8047fd
+Payload = b28a5bc814e7f71ae94586b58281ff05a71191c92e45db74
+CT = 30254fe7c249c0125c56c90bad3983c7f852df91fa4e828b7522efcd96cd4de4cf41e9b67c708f9f
+
+Count = 53
+Nonce = 225557b0faca3d6cbaedec5c
+Adata = c7aafe7d3b419fa4ea06143897054846ac4b25e4744b62ba8a809cc19253a94b
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb3
+CT = 2369b56f21336aba9ac3e9ba428e0d648842a7971182d5ffac57f6ae1080efab4ed93f8b4ce1d355
+
+Count = 54
+Nonce = 78912be1a35e156a70fb72f7
+Adata = 12ba8eddff1c2a03ddd25bb924ff065a93fd712b2c4f61eb80d77fab2c4900e0
+Payload = 113efd182f683596862ccd5eba2e2d4ffa709d9b85c6f1d5
+CT = 835a22eb8d718c0ee1531a2d1bb95f58215c997c612908eeed3ccaeb7a814f69d3ec1fbf2ee9792d
+
+Count = 55
+Nonce = 91ad90b58d2044abacf957e1
+Adata = 4fc795b9126c23dd7fd514c2e5a8ca583e88a783b28cbb2a5df09f8b520ba0d1
+Payload = ed55f6b9eb8fe74474c037ede94ffd84ada846ede4ecff74
+CT = ecb595276fd5d412a7cc3f5cfe960f47a0d0e2df0b08a11ac257d67143722a976c9d7f44b09a767d
+
+Count = 56
+Nonce = 4bbe4ca29122c4892ca09b5b
+Adata = 367ecd1b71dfb96a84e2369f28705dfaebf0c73ed35d5364449b2391230be846
+Payload = 8dd497bb777bbc3e56e3af25a43545007bb00f2b9e9f815c
+CT = 563d61fc0a5b82804a580a7d752a8e61d3342fb39372b39b6843a685bde3175695796f6e64f35901
+
+Count = 57
+Nonce = 218e7b8a8fd62927f90b70e5
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf001429122e46bde21735f63adba
+CT = aaceb16589b9de253c99d0d32409a631db71e8df8a7644bfd027e3466e8220144cb0552f9b2800e6
+
+Count = 58
+Nonce = eecc9f106a0721334cc7f5ba
+Adata = bf38d0ee11a796a517539bbc9ab00ff85a4ddbf0a612d46e2bc635180ad34c50
+Payload = 36cefa10af1a3446a2c8d4a1171144b9ddd8e33a7cd5a02d
+CT = 9bf3b2df93cf5b587ecc96f45fc75e6eb066cb286cb06f284c9027fc41bb8c848025fcf9d092a873
+
+Count = 59
+Nonce = e41af8ca408c4c12e37561a4
+Adata = e0b20892875f60b5d8763a04958487fa5b7cf8d67a456e430475b337245d671c
+Payload = 32a4da08bdd51336ed5798c7177b853a534bc98f2e6f7d4e
+CT = 95ffdc68f721cf2294d0d88002e3814167306fd906dbebdb7e6e0e5dc0a03826e51bd94269d7a41d
+
+[Nlen = 13]
+
+Key = 4a75ff2f66dae2935403cce27e829ad8be98185c73f8bc61d3ce950a83007e11
+
+Count = 60
+Nonce = 46eb390b175e75da6193d7edb6
+Adata = 282f05f734f249c0535ee396282218b7c4913c39b59ad2a03ffaf5b0e9b0f780
+Payload = 205f2a664a8512e18321a91c13ec13b9e6b633228c57cc1e
+CT = 58f1584f761983bef4d0060746b5d5ee610ecfda31101a7f5460e9b7856d60a5ad9803c0762f8176
+
+Count = 61
+Nonce = 8a56588fe5e125237b6cdc30f9
+Adata = b3aee5fbf409bcfe9b46ae68d570edbbed32c12d13926ffb5ddc60ff0bdb7f85
+Payload = eca81bbd12d3fd28df85e2cc3dcc2ecbd87408002fd00fe1
+CT = 9aad62a5443550d11f9efdab2de0eba74d47ae4f7d16adf4276664f6567f2f978bd4be4d80cd07be
+
+Count = 62
+Nonce = d908b04840caca2280e5293ade
+Adata = 314a202f836f9f257e22d8c11757832ae5131d357a72df88f3eff0ffcee0da4e
+Payload = ad1109ea5c79bb55d22e9713eb2df42767cb29a2eba3ad2c
+CT = 61fdcebb158cd03151697ae7871c0a998802997e0672e5886e5a9df1b1d6284ef657cde6f74734bb
+
+Count = 63
+Nonce = 6df8c5c28d1728975a0b766cd7
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a95f06b821879df3fd3ac52fc99a7c1d3e9775263b7d036
+CT = 704f60f9cc3ef7bc00b4f7a271ca70a89f4d5605387b3e2f8cc80aa08572b90e9598d0a73712b720
+
+Count = 64
+Nonce = 6c6ebacce80dde9fefb7e5bb47
+Adata = 93f0fca0c8c84d5cc48160b25e246226d489225c0f8275e52856da592c715aa6
+Payload = 46820aec46ebd0d61706129584058a1498514928a87fe620
+CT = 00f6cccf45f046da1e6266afe61eed61c60c28515b2e1ab386b2c952055899184f0d95ffe3959f89
+
+Count = 65
+Nonce = b94bc20d8c9abca7645fc6bebf
+Adata = e1c083c93663f5a066ef337a61aa3fddde7c301a42463137c375cc2dcdd76954
+Payload = f1fca581d3dbbc61060c0c02adb47bc57954d25a283f66d6
+CT = 90c65d23e0e1786cebb95f9b1306d001b2e503842cdedb75e37a53d77b9e38605febdd7b2b666f98
+
+Count = 66
+Nonce = a4974791d417d7e9eea0f4ae8d
+Adata = 33602f308f3a0f7e1c75fc1e4321d545ffa278234958dbadd37f59a0f85349c3
+Payload = 41712c058d2d56b43b2c79278e790858a289320746c15a60
+CT = aab5656a1ef060c9b1ef7e2f3cc0bda40ff067900401182563ceb824708a20724c99c83f1caacd70
+
+Count = 67
+Nonce = 6003b771afe4e99e1ef1ed4a31
+Adata = f60d8362b2ebf523681bb051fd3ee13919ad86acd963c703c4178a5f01a84236
+Payload = b766022311c5e1d74a607fec7cb8ee805b8397a6c5f374c1
+CT = f73b2a6dbf8f798d4bfb489a6578c9c79152e42aa3b81b64a84e7af3116a18f7ce44ae93f420270b
+
+Count = 68
+Nonce = 27861168ac731a223dc35c03e8
+Adata = b7ba1c66282cb6092ba601407ff9578afdadf7ba7a4d08edef06dbbfd87171bf
+Payload = 0822e3e6ba982091d532cd5271fbde25305d1f6e71880f81
+CT = 5ab3e5296cd1f08704c82f6b42939702515b7733853d723d4009312bdae46958d844eca502bcb005
+
+Count = 69
+Nonce = ef284d1ddf35d1d23de6a2f84b
+Adata = 0b90b3a087b9a4d3267bc57c470695ef7cf658353f2f680ee00ccc32c2ba0bdc
+Payload = bf35ddbad5e059169468ae8537f00ec790cc038b9ed0a5d7
+CT = b702ad593b4169fd7011f0288e4e62620543095186b32c122389523b5ccc33c6b41b139108a99442
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp
new file mode 100644
index 0000000000..f79db90b4d
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT128.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:24 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 2ebf60f0969013a54a3dedb19d20f6c8
+Nonce = 1de8c5e21f9db33123ff870add
+
+Count = 0
+Adata = e1de6c6119d7db471136285d10b47a450221b16978569190ef6a22b055295603
+Payload = 00
+CT = 0ead29ef205fbb86d11abe5ed704b880
+
+Count = 1
+Adata = 98d477b7ef0e4ded679b0bc8d880f09823ad80e9732fde59c3a87da6a1fcf70b
+Payload = 00
+CT = 5b85d144bb51d4927074d3536a2db83a
+
+Count = 2
+Adata = 28f32de10b6c9d3c3f46efec7aee24006208a54c4d1c2bba4b8cdce166cab7d9
+Payload = 00
+CT = 01045de4a09486eea5efa33ecc6cd299
+
+Count = 3
+Adata = af397a8b8dd73ab702ce8e53aa9f0189995c6c9e920dcb75795149550b499deb
+Payload = 00
+CT = dfd75400b59c3ad387bc86dfbbfb52ac
+
+Count = 4
+Adata = 3fa956bfaa27e249bf0a1276468d808259f3b8e2687851d780885d44cc2f04bd
+Payload = 00
+CT = 2b11d2549b4e2f0a81c07ee90af4d081
+
+Count = 5
+Adata = babbd1b44cae3af06e0150bf0e3d898f6fe862b71ea9f6b727accfc18848fc79
+Payload = 00
+CT = 10f76ab445f4ec158ccc1f7c6fee3ede
+
+Count = 6
+Adata = 7fba0bfda3b03c736c121cf9a257db55060b621be5168619ec4182f13ef6a408
+Payload = 00
+CT = 59e02d6a6aa3fb2692b04e65a0e735da
+
+Count = 7
+Adata = 057354a29808f4ed77671ed3dc36f8b03f5cd952caac5cb80dc3b319f3333e29
+Payload = 00
+CT = 367a2ade4087964dcb0ca2984d44657e
+
+Count = 8
+Adata = ec08b618602d091e9304715cb552b357c16fd1d7f7f023a28d84a98ba21ca0ab
+Payload = 00
+CT = 47cb92cd40bc89328d4dd44fbd727032
+
+Count = 9
+Adata = 45622834ea658b09b17f32777d18b34b387ef957bd344468f68e7178417a7c24
+Payload = 00
+CT = f5185afb8359b5ef995483c0bc4192c3
+
+[Plen = 1]
+
+Key = 6ae7a8e907b8720f4b0d5507c1d0dc41
+Nonce = 7f18ad442e536a0159e7aa8c0f
+
+Count = 10
+Adata = 9c9b0f11e020c6512a63dfa1a5ec8df8bd8e2ad83cf87b80b38635621c5dc0d7
+Payload = 0e
+CT = 4c201784bdab19e255787fecd02000c49d
+
+Count = 11
+Adata = 73616a428f1a567b2e9af86b1fc8aec6d597b1b55f2aa2219b3b662fa6bd3407
+Payload = 30
+CT = 72f14519f06b63fac3d5b2d9bbfa0cb758
+
+Count = 12
+Adata = 6d62f4e15e8bcc9ba4993bc50a046737121016f0d15020b90068250551167b1c
+Payload = 34
+CT = 7676b581a28ca0a0ba5178eba7fe028da6
+
+Count = 13
+Adata = 8f0b8289a1834ecc2167b59ce3c9d3b58465c4cfaad50c728d04360cb7e5bc41
+Payload = ec
+CT = aed99b805c0a4785ff2913cab3e50f6205
+
+Count = 14
+Adata = 477b2a6932f838f0d1bc420c0ca306981d8e2dab945b6f259e15fe888667220a
+Payload = ec
+CT = aeb50e41cd7af84a8fdb6aee144e904616
+
+Count = 15
+Adata = d6518d409b1f05708d0b44f18fb5721f20f3220f8d2f2718650aa9932e4579e0
+Payload = d1
+CT = 9312639c863974f077fe8236c943b464c4
+
+Count = 16
+Adata = 865e7cde73b558e9bfd05356923f8a697970811fc484acad2d5b3528baf1f986
+Payload = 24
+CT = 66d7265cde50bc7a3989458437baf06db5
+
+Count = 17
+Adata = f0c3c67a935eace53ed32435655dd0974fafe283622e8294a15d70977398eae2
+Payload = c5
+CT = 87063144b25d2268063815d1b42ebbac34
+
+Count = 18
+Adata = 341e71b2ef26e9db03882e06d06cde2c0617326cd157d5984d22f6f3407a9c39
+Payload = 34
+CT = 767da45c10d0d6498716bcf3f13ca7e26c
+
+Count = 19
+Adata = 31fce6735ba9a3385df11c153179b8e4141a3c6b8ad6eceaa211f3f17bfd0474
+Payload = 7d
+CT = 3fcb0a6f562974cfb3fb7c8d5cafd50f2b
+
+[Plen = 2]
+
+Key = 3d746ae6cac5cefd01f021c0bbf4bc3c
+Nonce = 597b3614ff9cd567afd1aad4e5
+
+Count = 20
+Adata = 90446190e1ff5e48e8a09d692b217de3ad0ab4a670e7f1b437f9c07a902cad60
+Payload = 4360
+CT = e38fdb77c1f8bbac2903a2ec7bc0f9c5654d
+
+Count = 21
+Adata = 6bc3d30925c67371573271f1a4273ad76e91e07dfab65f7bce0b241b5e4cd00e
+Payload = 17c6
+CT = b72955210d62e1393e4fda647c2b2e59a47d
+
+Count = 22
+Adata = d1bb4cdfc3f2c16d92576068543692aa4b5a427d688387af0f1583e91a0e8b3c
+Payload = 6575
+CT = c59ad54fd88a47b9f6e39cb4606af86d13e8
+
+Count = 23
+Adata = ae6136df9ab43631ef143515dacedbe759b3459e951bfaf4712a21c86352f1c0
+Payload = b1dd
+CT = 11326de841af64b55bb7ebe3fd30ba493c7d
+
+Count = 24
+Adata = ffead34ac26e21158212d07c367c3a7cb6b795887ee2d3d8ae25c60556ea88d3
+Payload = cd16
+CT = 6df93a206339de534271f6469edfa5ed07d3
+
+Count = 25
+Adata = e768e7d867820d46c1cc62ee0e51d4dac6f5c4b5785b5ccfbf05236871bdce2a
+Payload = 12f5
+CT = b21aa8f65144f2ec5809e2ccb38c8760f7bc
+
+Count = 26
+Adata = 402e802885e4119df17fe85f141c3d1af7727fcdb00f8e2c34e42a436d04ac5b
+Payload = 39c0
+CT = 992f9af825957abe7d89e175b6e8c0b84b5f
+
+Count = 27
+Adata = 8a3a622b3d347c0c5210d484adf77fa33205ba02224ddceea71d89c9ad8429ae
+Payload = 912f
+CT = 31c025d6a12e91e84e355934547f6b5dceb8
+
+Count = 28
+Adata = 636114e5e5f83cec94e1df21d6babb9f6a14a532fcbfc3bcf649fbd79ac1abbb
+Payload = cb6d
+CT = 6b826db959a21e9e4ebf25ca4f98501b560d
+
+Count = 29
+Adata = 04e84f9156998c2eca9e96079a6001f2947dc49a081b3d75e47d75f71ed4a606
+Payload = 5bd2
+CT = fb3d2006ff22ff231a6646ae561923818a21
+
+[Plen = 3]
+
+Key = 3e4fa1c6f8b00f1296956735ee86e310
+Nonce = c6a170936568651020edfe15df
+
+Count = 30
+Adata = 00d57896da2435a4271afb9c98f61a650e63a4955357c47d073c5165dd4ea318
+Payload = 3a6734
+CT = 384be657bfc5f385b179be7333eb3f57df546b
+
+Count = 31
+Adata = 50f6e6dd57bd3a24f6bfdc8b1c7b5a36ebdd07fd6d194e6e82da47151d9c88fb
+Payload = 4ffad3
+CT = 4dd601b8ca97bda492546d82dccdebef441f8b
+
+Count = 32
+Adata = 70e132023acae1f88c7a237b68f5bdce56bcfc92be9f403d95d3bcc93b4477a9
+Payload = 8a594b
+CT = 887599fa0f3e397d9a580aa39c7028e1a508c9
+
+Count = 33
+Adata = 08d2b011f36e05dc728c1a8bda3d92c779a3d2f27c4b041810bd6222c852b14d
+Payload = 1f89df
+CT = 1da50d593460d335e2f7a6d40b8fe305b0f690
+
+Count = 34
+Adata = b207eb870aeeab27c6201ef04650bdc7ea30028a243420f7d198f1c9c9a43023
+Payload = 72e9c1
+CT = 70c513a2d49e1a113767ea4219107819d88b65
+
+Count = 35
+Adata = 74294088721fc9e7aabd5f1c66b5369b1e2d2cdb3e73abaa28ecd1c37d4ecea2
+Payload = 016083
+CT = 034c51dab1c819778be8453db163c882063af8
+
+Count = 36
+Adata = abbd347999a1c26368cdb17ab08bf57a8e942d1248296e952f5f42f2cabbf0e6
+Payload = 25f665
+CT = 27dab7537eb435df8d0e48c3f7e0bd1877c866
+
+Count = 37
+Adata = 231b33dc406c9210f59a5df1cfd595c803474db34b9b1848f0bcbe7b28df33c2
+Payload = 158606
+CT = 17aad4da549fc63d55b5910bbbf64435b95220
+
+Count = 38
+Adata = 69b851e63a78baef90637978e3dfe8c47be4b21e85bb89bf67051cf251004376
+Payload = b07452
+CT = b25880d5ee29fb2af47f8040fad585921057f5
+
+Count = 39
+Adata = 9b1f786c887d310b8efd3e8192fe504f603024c94aaa4ec9123736a40bf1605d
+Payload = 65187c
+CT = 6734aebc3ee43e10205f83143e0d3794a6734c
+
+[Plen = 4]
+
+Key = 7ccbb8557f6e08f436d0957d4bbe7fdf
+Nonce = bb8e2ef2ed9484f9021cda7073
+
+Count = 40
+Adata = fba1d18a74a3bb38671ab2842ffaa434cd572a0b45320e4145930b3008d8d350
+Payload = 4cabeb02
+CT = 32501f4235c4dd96e83d5ab4c3c31c523453c317
+
+Count = 41
+Adata = 78b3faecb2bdf6ed14ac2b86ded07aa791b60f5d54f9e24a965a8453f5131898
+Payload = 5ff73653
+CT = 210cc2137907d6a03e66403a7d9330d30d934a8d
+
+Count = 42
+Adata = db1239528eb464dd063e2a97ee83a87d6002ebb4fbafa77036f72c14f3fe959b
+Payload = 062fa9ca
+CT = 78d45d8a44f4bc78fbb969935076134437df82b4
+
+Count = 43
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cad710b4
+CT = b42ce4f459692911fea2e0034d06c3b2e89af3d1
+
+Count = 44
+Adata = 7381471a62b1fa6f5061c4c37e9721f07099d007ffaf8639aa2ae3f82da5a559
+Payload = 7ac716b4
+CT = 043ce2f468484e22381923bfcaed16e0cb85b0f8
+
+Count = 45
+Adata = 19bea6d92d5892216e8e4a30dda802387800bb046a6717817fc46c7edafe17b0
+Payload = 362da02c
+CT = 48d6546cd081de39c247df309c4b56c31c03690d
+
+Count = 46
+Adata = 8503c8eb9cebc6110f259e35e03a0740267768130ce6f61b1c7d1d25be942274
+Payload = de52b209
+CT = a0a94649c6c6bd7b3a9d7c4dfa2738847ea3cb33
+
+Count = 47
+Adata = d2445db6efecaa3f426b06de8d496ceed54a1d0171384cc762e21b31e265c6d5
+Payload = 8fe8b383
+CT = f11347c32ca874d18d0b790856837555f4d4699a
+
+Count = 48
+Adata = 8cda7d1e135cf5fde1ec9473c4b42c1bbb445c27fd87b5f73df61ceb2d0b6f75
+Payload = d8d6b2c9
+CT = a62d4689932c2f8d78e322aaffc90846025190f1
+
+Count = 49
+Adata = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5a4c25393ecbf2025
+Payload = 6a029e53
+CT = 14f96a13c346a4084918081b4bbe53b50d896788
+
+[Plen = 5]
+
+Key = 3725c7905bfaca415908c617b78f8dee
+Nonce = c98ec4473e051a4d4ac56fd082
+
+Count = 50
+Adata = 11bc87f1c2d2076ba47c5cb530dd6c2a224f7a0f7f554e23d7d29077c7787680
+Payload = f5499a7082
+CT = e378b776242066751af249d521c6eaebdff40b2642
+
+Count = 51
+Adata = d54219ef4fb851bebd1c546011ae3922b8337e19c28d4d58428efd66f80edcf0
+Payload = 513c46fcce
+CT = 470d6bfa68e7258df363e0e9af67a543c86db3c994
+
+Count = 52
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = 9d62e557c3
+CT = 8b53c8516572b7573e5b27a1d0e15cdb7b06c8857f
+
+Count = 53
+Adata = 77d9c306aa257379053cf1f2043c388a301dac2a9e2bb89eb8bab6eb3f150fe3
+Payload = 7a05db235f
+CT = 6c34f625f9de691a412ad54bbdb6ceac45ed45902b
+
+Count = 54
+Adata = 081568ae0b948aa647b9d4dda5d42641ad5de72aa9874d8d0717d872007720a8
+Payload = 30a22ca0fc
+CT = 269301a65a8a1bb8ba3d6763dcb1bdd3400e3459f7
+
+Count = 55
+Adata = 695ba4dea0f84baf190ec25a25fc00cb9898902d7a17e6f5ff2df323b974f7c4
+Payload = 35e25aa51f
+CT = 23d377a3b9403897d496cabcd5bd9de3282199a8ed
+
+Count = 56
+Adata = 1f3ba0336a634efdd11f8168c0fe25039f9403bfa70b3898f4dbe577dbd52957
+Payload = 8bde704c74
+CT = 9def5d4ad270a81f7cb0ab7ab2b495f51d66abeee5
+
+Count = 57
+Adata = 097b9ebff3ff93a143678d59721fdf359e95cbc82585ae47727a773317925d38
+Payload = 428542ecfb
+CT = 54b46fea5dce68e9b01a4462a2221bd2f3cadf64c0
+
+Count = 58
+Adata = 76d0341dd44c39e43a23dbcf4cb602f15d5fb9fee20c3d0d262d539c3fd1dfd5
+Payload = bd6866ded0
+CT = ab594bd876f2545964ef3978cad3387d61104bab84
+
+Count = 59
+Adata = 7e7c40ad64b511005b4546f9ec61ca24829390fbc4bd8507225bc348ae0807d7
+Payload = 5822755a3e
+CT = 4e13585c98002c41938a935d51905b2a708a2c5194
+
+[Plen = 6]
+
+Key = 80bead98a05d1bb173cd4fca463b8fa3
+Nonce = 8a14a6d255aa4032ebff37a3d7
+
+Count = 60
+Adata = bb4e706e73d21df66f64173859d47e247527cd9832e20dccff8548ed5f554108
+Payload = e479990bf082
+CT = 89c9246238878427f36b1f6c633e4542f32b50ca8edb
+
+Count = 61
+Adata = 9db2182c8a4f5471082bfa1a8496602cbcdef2790f7e8f71f791303bd48dcb05
+Payload = 017a7fd1aecb
+CT = 6ccac2b866ced76fe54da69af5edf8309c7f013bb07e
+
+Count = 62
+Adata = bf483f59fb73681f27b68168c998c90ea8ceea997654c6fab2bd737dcdc884f9
+Payload = 512fc5e4973a
+CT = 3c9f788d5f3f662f53d17f7cb6673415bb2324ca0666
+
+Count = 63
+Adata = b91e641d8210e1ef705fec2beb9f58a391c7d1a38935cd1d13f2c00363388ff5
+Payload = 06212e989616
+CT = 6b9193f15e1340c86156b1065b64af1e4d6c89b32603
+
+Count = 64
+Adata = 5cebf908e232d797fcce8453c4c3000868d4172622a4ee0d6a1bdd876a0b7c96
+Payload = c45629069ebc
+CT = a9e6946f56b9c07ef5349903b928e39e99e2e32625de
+
+Count = 65
+Adata = ab92cbc97f3aa6f9ea4dae5d8c3d9e91231f43ffff548da7b668e61c183ac2cf
+Payload = b949ced37725
+CT = d4f973babf205e40654ea16e83cc6faeaad668c416f3
+
+Count = 66
+Adata = 2c3d2f9c7e89c2b9e07317c4db6e9f00f5faadfad531c5bea79d164ac24d4543
+Payload = 517ff7b383b7
+CT = 3ccf4ada4bb23102a502dbba0c280e1d5fc627fe3a9e
+
+Count = 67
+Adata = d798e77ab0f3697768f23014fd31b9e8762ae65b6aa8a4bbc17ecb8cbe78461f
+Payload = b40d863ca4ff
+CT = d9bd3b556cfa6745fd4c954396e696697731e1f9a262
+
+Count = 68
+Adata = 45b44e3dec57e24d960fd1767797ffdbbab81e38bab37e6974df262c3d932327
+Payload = 56e00289a003
+CT = 3b50bfe06806bdf2b2dd47077c98234eae5d47c3b594
+
+Count = 69
+Adata = 645d27970ccce096d082fccfc1183955bad2611af0dd7c58c9d54430f28bd992
+Payload = aa22bb1de579
+CT = c79206742d7cea66649ad7e204a344d3234125aa324b
+
+[Plen = 7]
+
+Key = dc8ec91184ba18eae31ac2d3b252673f
+Nonce = 0da4c988f521f5648259f2bec2
+
+Count = 70
+Adata = 6d5573c9279897d7d1602d8a95c04bb5ca3fad2dbe89a024b3651eb227e73bb5
+Payload = 2a5775986551c8
+CT = 4f259f2a718faea852a7c4358dfa9f5467357638acac90
+
+Count = 71
+Adata = ff0ab5021ef466e2e898b0993d691145168be558682c74914c172f2b5e863754
+Payload = 8db3c1ca0580f9
+CT = e8c12b78115e9f8767c76e707d48a2144e090812e0192d
+
+Count = 72
+Adata = 2ee03cc28f79773af139c4ea55ec4daa48bb2885b8adcd5f066eceda5c4ec27b
+Payload = 3c69e2e83236b6
+CT = 591b085a26e8d05486df740083c959fb62ef7e2e221602
+
+Count = 73
+Adata = f041504d4c1b3d5be358bd6d350af42921205d29ab22b44ffe221358adef5bb4
+Payload = 777828ab5ccb68
+CT = 120ac21948150ebdc4d2b86b2528f75db4a7f5423f4395
+
+Count = 74
+Adata = 81ea116832d69542ac8d3d22c16c82eecf2ccac39264dd933c4f9c13c8d0f1d4
+Payload = af556fef3584e3
+CT = ca27855d215a85a7b06d1b710baa15daef19069ecf46f0
+
+Count = 75
+Adata = 8a0a120ed290a62456f002da1c250a0ddb1ebd57185a733d8fb562aad482679d
+Payload = 98f26635351f14
+CT = fd808c8721c1723811129add52e1406d50cbff4aa82802
+
+Count = 76
+Adata = 12b5a76faedf6f855e328c2cb87be8aea78c5e926b32d828e167b46205c86de5
+Payload = bd22c1ec05dc26
+CT = d8502b5e1102401563d3da8a6cabb7515f642e42fb4b2e
+
+Count = 77
+Adata = 8dc32f35ef4bcbfd040ad25dc36d0bd2486f93d0cabb7704cd1582dc99f65449
+Payload = 2a87c0d64806fe
+CT = 4ff52a645cd89817609a21f703253e5e56beef4ac71759
+
+Count = 78
+Adata = 83ced632359a11eb0c4c99baad84df5cac15bc5453b6593d9ffb4c5e8c84037f
+Payload = f05f39eb0a3d64
+CT = 952dd3591ee302236c72f98da859b54be7c598d85c37eb
+
+Count = 79
+Adata = 771a818a24e7da7b98f4b4291ef34bec7e1656b0c6c6e9474a989a04ea7de385
+Payload = 59dad755af92c2
+CT = 3ca83de7bb4ca464c8cd38cbcc46e7f09bf3e1c6590c71
+
+[Plen = 8]
+
+Key = 19f97ef5318b8005fc7133fa31dd1236
+Nonce = 01ce9814c6329dbee1d02b1321
+
+Count = 80
+Adata = 85853f120981f33cf1d50fde6b8bc865fe988a9f12579acdb336f9f992b08b89
+Payload = 6d972a673fbe1ca1
+CT = 2f12a7e7acecae5d2563309efc19368cdee8266538ca89d3
+
+Count = 81
+Adata = a4ec5aee89e2cce2115b6c1f42570bc5062887cad08192a682d0b4508fcd936a
+Payload = 68b1b6367a15fe49
+CT = 2a343bb6e9474cb528096a5fec5e5359c369833eac3b7efb
+
+Count = 82
+Adata = f5499a7082bf1e6e2923211271f5f7f6d7c7b26db7963071705a58ddc4dca0dd
+Payload = 707023615563a40e
+CT = 32f5aee1c63116f2754a65863efb60c98dbb536e2b5a69d8
+
+Count = 83
+Adata = 765f267befe6fcfaaa4b46eda32e7bfab87f12ceb07fa3b37be74965bb664a21
+Payload = b56454bc50df3e28
+CT = f7e1d93cc38d8cd40b6e9b7f3b3541ffee66a1f668f67d28
+
+Count = 84
+Adata = 9ce65598cd1f86afc9aaaf172809570cc306333c25523f863c6d0e0154c55e40
+Payload = 962f765da3565bde
+CT = d4aafbdd3004e9227018c9db8baf6be349d93d4eef7d7c9d
+
+Count = 85
+Adata = d0125e30c36232a8c07cee9abc53453b276849a7c04ade80ad586ed8cbcede51
+Payload = 4f18bcc8ee0bbb80
+CT = 0d9d31487d59097c501b28887f05fd66f050525943d101f8
+
+Count = 86
+Adata = 90dfd9e7bb7bf8fb70c22a879ffa760d14cda7b79ce4968f69b8a7f2b7a59642
+Payload = ca293c9e1780b401
+CT = 88acb11e84d206fdda53dde2e1aef96b3658a7635ee54188
+
+Count = 87
+Adata = 58f518710e6b282482a7f1950fa353b13bdda10c9aaea6d5f0d7ea0a965d31e8
+Payload = b9df9fb4a6b299b4
+CT = fb5a123435e02b48b62a5ec234f1efd1b52c8fad1cf09890
+
+Count = 88
+Adata = df052e95aea3769a433ce4e4e800b8418649bbe8c6297eb07545e6802de7e807
+Payload = fb2441d1594a488a
+CT = b9a1cc51ca18fa76bc051ede6f37cf67543a7252d7d9b203
+
+Count = 89
+Adata = 0875020959ed969cfb38636d1d5aabce9658b00171a7614ea9e5395331c7659c
+Payload = 451101250ec6f266
+CT = 07948ca59d94409a5be4be6bc6b18104fac167b6e3fc15f7
+
+[Plen = 9]
+
+Key = c17944bfaeeb808eed66ae7242ab545f
+Nonce = 910b3db64df3728ca98219e01b
+
+Count = 90
+Adata = edf64f98b3ab593cbcf68ab37a8c9472e49cb849d4a744deae925a5a43faf262
+Payload = 7caae2640e734539d3
+CT = 0dae8b3ccf0b439f6ff8ee4a233dfb7753f6bfe321b3e26959
+
+Count = 91
+Adata = 29ac8fd6a20a5df4ec79660c44d373da42de7d7c5fc35982b6c29b480723b484
+Payload = e574b3a37af3bf2251
+CT = 9470dafbbb8bb984ed63b1477d9506a51ae23abbac179d8b02
+
+Count = 92
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b227
+CT = 5f3899f74deec1149bdb0986198bce2e486581c041029a81d9
+
+Count = 93
+Adata = cc8e789462879e348d20be4e1161d7b7fc6f8371d8f8cb2d25d13f0e07de47b0
+Payload = 16f22817c5b79f9fa6
+CT = 67f6414f04cf99391a0cbb2df2079a6eb964c3469f4f326122
+
+Count = 94
+Adata = c63061f2800228269015693336f78bb535ae8b88869e4ccf4ead2f3b0ea4e48a
+Payload = 64fe8076d4e8538e18
+CT = 15fae92e15905528a4a40ca7622acf7266b7c24cf0c3202e4c
+
+Count = 95
+Adata = 71c14a7031033db15bfe23b75fed9daf8886dd11392a0b787660e7b1a581af11
+Payload = 4814aaac48bdf43c92
+CT = 3910c3f489c5f29a2e7de20e98586cd5d684bf015a7abbe82c
+
+Count = 96
+Adata = 8f4947f8588ed866ed7477d7f1a28046430c6470806a50e3c9e80958c61f1b42
+Payload = 392a692b57a8a97f60
+CT = 482e007396d0afd9dc8d503f5d87818f7c0e173b857cef4288
+
+Count = 97
+Adata = 9d44f6df58c2b43db67e3daa95b176c81daff32e996d670e86405e15eae72e93
+Payload = cba1e00e345b0cb7eb
+CT = baa58956f5230a1157c85e2283d9e80700268a6459d1451d00
+
+Count = 98
+Adata = b6ada12f7a28211e9d2c07cbb3d39fa77aadc077b34c46f93006c1ca2ff66f87
+Payload = 22f5b6752582919dc1
+CT = 53f1df2de4fa973b7d1056aea3d3e4f7a5219170aaa52465e1
+
+Count = 99
+Adata = d6411fd5b25433f67ca75e4560ceb809d3721266beec358dde126b2f6a514137
+Payload = 6e1b55d6f5288c5451
+CT = 1f1f3c8e34508af2edfbfcf8200a8a3f8d995f50284a7280c8
+
+[Plen = 10]
+
+Key = 0fb9df6f638847f5de371f003dd938f4
+Nonce = c9ddf61c052f3502ad6b229819
+
+Count = 100
+Adata = 4f9938d5bc3dcbe47f6b256d5e99723d0891e50c6175aba41b011e4686113c49
+Payload = e10cc36bc1c5d3c646ab
+CT = 7f797367de50be6dc04e4cf0d8c24189affd35060cb7ca3dd136
+
+Count = 101
+Adata = e013a2edd5b86bab8df5c9940d0a0c864478c1ad42668304a643141855adac10
+Payload = 15841284c959febe63f9
+CT = 8bf1a288d6cc9315e51c4148ef85caab151488c1a6b3df540d21
+
+Count = 102
+Adata = 147d77d509f642189594df17574a0ce62b52a838feb62310e11533995ba4c851
+Payload = a8b4e5829069c335d1d8
+CT = 36c1558e8ffcae9e573ddaaa1e7c22b3efa8362abb3d31ee8884
+
+Count = 103
+Adata = 0bb09658e23fe8a08c01a6994ef36cb8dcc9a806297a09c67efe3558ca56bb5d
+Payload = 1bb2da0f1ae7e044deb0
+CT = 85c76a0305728def5855317b141383ad38dd78569d5f846f2520
+
+Count = 104
+Adata = 34eb2e6149bad764837f6f25ddd96865e5b05d5cbf233c4f6cc2aa654dfea3b7
+Payload = 63af538196add9b3fad2
+CT = fddae38d8938b4187c374e6432971aecf6bf7cf5244d21f7f173
+
+Count = 105
+Adata = b69f26fda6d1cd92897e03758cae020c4e1beb019ce5ad987f872940780a9468
+Payload = 6ef2df5a1688ae795537
+CT = f0876f56091dc3d2d3d2e4d0ffc0f0add38a80c7ffe6b4701e54
+
+Count = 106
+Adata = a7375ba32251af0138bd9fd8fcd56a7c43ab2ca9a7fc0117d25f6d4ef9c2fcbc
+Payload = 3f46c83021069ac488a1
+CT = a133783c3e93f76f0e4447fdd0b2f29f39094ba5a7375e278349
+
+Count = 107
+Adata = f9b91f7298b4e43843fc739a2f41c57c3f2cf36378fe4c34b574a43f9cedee7b
+Payload = 86c10a6dfdd6a06ef638
+CT = 18b4ba61e243cdc570dd57500f913ee3f46801e1bba9d4db7ecf
+
+Count = 108
+Adata = 9d35876d9449a1642b5062dfbfc7a26a7ac080b7198f4aeff2c79e463565cfd2
+Payload = 196c80d02b663bdd89fd
+CT = 871930dc34f356760f1856a6b87519b4807a2114ced587f72189
+
+Count = 109
+Adata = f2d5e927eb507f889efc6f21d783851f638f978c74960cc347f89f2703476114
+Payload = bd27ae3ade0781a33d5f
+CT = 23521e36c192ec08bbba2101012808adefe9b8166e04685bd537
+
+[Plen = 11]
+
+Key = 006ff7d3153caf906ec7929f5aef9276
+Nonce = 57db1541a185bd9cdc34d62025
+
+Count = 110
+Adata = 7d9681cac38e778fba11f4464f69ed9ebfea31b7ffcaf2925b3381c65d975974
+Payload = 31be1b241cae79c54c2446
+CT = 9dd8a4244fbdb30b624578a625c43233476bbb959acd9edebe2883
+
+Count = 111
+Adata = 1b0012c468009bd2851653013782c7b71ef43c393afd4dc0aec4d6d0c3fa11c5
+Payload = 8802831e22092b30110cf7
+CT = 24643c1e711ae1fe3f6dc9d477ca066ec2befa854a1faef018ea8b
+
+Count = 112
+Adata = 48b216375c00ca7e9c4048834b37944d2543e24fa091fb3c7290e11c53a6b6a0
+Payload = 3b3f782d637319d7fd161d
+CT = 9759c72d3060d319d37723eb6be9a78dfbd9e16181679b782969ad
+
+Count = 113
+Adata = f3e06a45fcf1f6abeb00727bf2c9bcea00ce621d38f7b7eba17c27e51f04c793
+Payload = e98f5e5a20d02c80372d6d
+CT = 45e9e15a73c3e64e194c533d9574d95b821a5170e9b61d8e6b2ff3
+
+Count = 114
+Adata = b36e27729f9a139d8ec4f61215b7bf1149cbb4d93a5c14bebd7cfb7c6fe585cb
+Payload = ceeed4fde3406ec40f7ac6
+CT = 62886bfdb053a40a211bf8aa193d257907be1330abaa56bc4f431a
+
+Count = 115
+Adata = 8886ed7fa414d74aef704a9751b197cbab02c41c6aedcaf65cda019dc2d2d815
+Payload = b38f03449883773135c0cd
+CT = 1fe9bc44cb90bdff1ba1f31d92029a6428748664b5c815f15ca1b7
+
+Count = 116
+Adata = 816d81af167d2294497d9b06a39fdf75e37cbacf4d10c3a444068c891b361bba
+Payload = 8efb141db7b77c521003cf
+CT = 229dab1de4a4b69c3e62f1386e4ad7c72ce0081a85d4cfd34254c7
+
+Count = 117
+Adata = f427c47e10c45bb3c7e75e9e604503b3560427691470358efdef48ddaf3794d2
+Payload = 6dc38e37d1379732df4dd5
+CT = c1a5313782245dfcf12ceb98eeb05bc376a1042735569d5b63f8fa
+
+Count = 118
+Adata = f3df712b5e8dd8e4aa8b7c5f41e93bd11b0df66a3456a01f3d0094ad91482cdb
+Payload = e0e358aff203369dd5960c
+CT = 4c85e7afa110fc53fbf732065b03ebeb68a9153cb4ed152ce0d64c
+
+Count = 119
+Adata = 264f2c7b095a296eb8ff6b5151ab3d9497ea8dc0002a9e5b09c2fd0ccd32b6ff
+Payload = 57b940550a383b40f3c308
+CT = fbdfff55592bf18edda236fcd16c8360a408e2787f930ed275bf3f
+
+[Plen = 12]
+
+Key = 026331e98aba9e8c23a9e8a91d0b0c97
+Nonce = bccfe69bba168b81cbdf7d018a
+
+Count = 120
+Adata = 26e011143a686a7224ddb8c5b1e5d31713fa22c386785e2c34f498ae56d07ed5
+Payload = a82200ef3a08c390dec5cbf9
+CT = adf4fc6f9be113066c09248fcb56a9c1a1c3bb16fbb9fbaedacdb12b
+
+Count = 121
+Adata = 97a720ae4720546e31263a1a538ce1d35c198c23bd4362e0023a67536328ab9a
+Payload = 7fc58d1bb450b396b9161f53
+CT = 7a13719b15b963000bdaf025002120b619a391fbd23402e5edd4949e
+
+Count = 122
+Adata = aff6c8cefda055c67262e9c68825d1ad2a7488e5b09640a111fabf6254d96cc0
+Payload = e9ea182d7f895f312b9738db
+CT = ec3ce4adde608fa7995bd7ad48b6e9a8de0099a28cebbf5c2bad42ff
+
+Count = 123
+Adata = 35a3963b43f47855ef3df12af5de3626e0c5c8d9cd2a534c737cd695609b05a9
+Payload = cfbc8bcbb5e5bb744bb1f340
+CT = ca6a774b140c6be2f97d1c36df80fd62e751757bb0a32a987980afe6
+
+Count = 124
+Adata = 46a2e6bd3fd5336abf02eace3cd1e1f6dde505ab976a9fa596edd6fbde7175de
+Payload = a334f8f41897cbcaeb5cffdf
+CT = a6e20474b97e1b5c599010a93b211350c70adf9bab5c01081bdc6a99
+
+Count = 125
+Adata = d110651c00ac5540f9d1ed9eb175e06b97163fc36d43f048565e5d0c30a069b1
+Payload = 3f781267290e8e73c6355e75
+CT = 3aaeeee788e75ee574f9b103d7f65690d9a2fb6759d658c9bdfdfc37
+
+Count = 126
+Adata = 978644dc4e36f1d98a2a63e19bbf8af11785d09fce58a95c00cc6bf6cecf6161
+Payload = 3dc39dbb91efe8b16396d488
+CT = 3815613b30063827d15a3bfe0d5df472f49e7f713cd1373293810906
+
+Count = 127
+Adata = 5ae7528c5e965880b1533cbd78c1e81a8187379327a2fc3f76ff45829049e183
+Payload = 6caa8c0764512baa39dabac0
+CT = 697c7087c5b8fb3c8b1655b64bfca9ef00b0f2bbb03c1a3f7a0862e7
+
+Count = 128
+Adata = afe754828be6e3731d3eee54b021b4fa182247bd958e9074fb0094a11030f5e8
+Payload = b19bc92e2305883580dd7742
+CT = b44d35ae82ec58a332119834a03be1d1d262b03c0ab425d533fe4ec1
+
+Count = 129
+Adata = 0650859c635654ca4d815963c0a99f9d2f47456ad37f739c425e924d4360bd7e
+Payload = dab87e79544df1cc98096b91
+CT = df6e82f9f5a4215a2ac584e7da61ca8461925996880e2874393232d6
+
+[Plen = 13]
+
+Key = d32088d50df9aba14d9022c870a0cb85
+Nonce = e16c69861efc206e85aab1255e
+
+Count = 130
+Adata = 0eff7d7bcceb873c3203a8df74f4e91b04bd607ec11202f96cfeb99f5bcdb7aa
+Payload = 4b10788c1a03bca656f04f1f98
+CT = 89f15b1cb665a8851da03b874ca6f73242f2f227350c0277e4e72cdaa6
+
+Count = 131
+Adata = a533b3279db530eaed425842b0d3528f5c5e4c16acfa0f49de43d6491f0060a9
+Payload = de6ea86d3641d916c4394fdd31
+CT = 1c8f8bfd9a27cd358f693b45e594271cc06f81d510075728cfeb89222c
+
+Count = 132
+Adata = 8e6c1cde142e18635c1b4f0cb54d3cf817f22ad7c25bf6a022501682f6a7da1c
+Payload = 6f3b32adc8c0314872947f3d31
+CT = adda113d64a6256b39c40ba5e5ab1aefed75400a41447b2bd8f0605542
+
+Count = 133
+Adata = 248a4389da2d51b87907dc11c46253515503ba80de5d06c9b505cb89906614a6
+Payload = 0cc992a8c736b44fedb4ad498f
+CT = ce28b1386b50a06ca6e4d9d15b46b3a6463876f1a43a287748f339e913
+
+Count = 134
+Adata = 2e2c8244a2cbf53816b59e413207fb75f9c5ce1af06e67d182d3250ea3283bcb
+Payload = 98104fd3f3413ad1f57ef4912c
+CT = 5af16c435f272ef2be2e8009f8f625786bdc58af24b17c1ba34fa87baa
+
+Count = 135
+Adata = 4ada86d88d5f49dfcde13fc30ba9a1af58d5254b47fb1885a20fad915c87952e
+Payload = 3b4fec79d52d8b2a533917b75f
+CT = f9aecfe9794b9f091869632f8bd4a918290cf97208232c76908514b07a
+
+Count = 136
+Adata = 9e3b23232e5a9e69747f8bcb148cd6d282fd9b7ecd6d97e8bb5cdc261b2fc86f
+Payload = f10c19c76ae7ed55e1651155df
+CT = 33ed3a57c681f976aa3565cd0b01d6306bb91c315bb4a23fe23d496d09
+
+Count = 137
+Adata = ccea2c815ea4efadc3007f511d633e98f9fa38b0e0fb572b282ed6a610adf7a9
+Payload = fa34af376868d9a49aa200f59a
+CT = 38d58ca7c40ecd87d1f2746d4e620d9d3004587c5d510e2a857fc857ea
+
+Count = 138
+Adata = f7277fb296e2c0d2c9ceb7013ea8b59fe37e26b3b42a0b8cd01aaaa8d35283d4
+Payload = abe2fd996bb6804ed3286c057d
+CT = 6903de09c7d0946d9878189da982d2438a5138977bde5f514e2335c28c
+
+Count = 139
+Adata = 14dd1810df3eeee78ed3836c77edf510d91ea28f119bf57111e580d70da94b74
+Payload = 395ea6979b77dabd2042aee4ff
+CT = fbbf85073711ce9e6b12da7c2b78100a05448fa6e74bd3ed16c3bd364e
+
+[Plen = 14]
+
+Key = 7301c907b9d2aaac355c5416ff25c59b
+Nonce = 7304b65b6dab466273862c88b9
+
+Count = 140
+Adata = 2c5d114eff62c527cc2e03c33c595a80fe609bfc0fe13ce3380efe05d85cceac
+Payload = 484300aa3a506afcd313b49ead8d
+CT = 928ca58b0d373dc50c52afac787ce8eeb5d5b493661259a9d91ea31a5f7e
+
+Count = 141
+Adata = d9ebc1cbfab9034317132a72e0f11c341331146a59e7a2f26bf4f3d778da52c4
+Payload = 8b318f75ed79a7978adc17c4d2d4
+CT = 51fe2a54da1ef0ae559d0cf60725552193439abfedda67d765d030cef30b
+
+Count = 142
+Adata = 9aea86b9fbd9bd4504ee2e25054942b33d3cdbd84215db7ea337e548cb706780
+Payload = 0256b0d154c768c85070da6ea8c7
+CT = d89915f063a03ff18f31c15c7d3615013c2bc9338868fad0d2fac11df019
+
+Count = 143
+Adata = 08afe10bbfbd65b948a6561bbeaf3ab46a8e3d0a861f1cfc46584156197f30a3
+Payload = 89ed296a3ac03fbfb71422b92117
+CT = 53228c4b0da768866855398bf4e66c3c4cb8c50891d6523245e4c619aa99
+
+Count = 144
+Adata = 7d653792bb8683e07c7d2c800db6f7f08343c85af2377115df4fc86ff7d8fcaa
+Payload = 414b6acb1db479028f5cc8800f2b
+CT = 9b84cfea2ad32e3b501dd3b2dada792d2cb93e45811a4c897ae9d907c9cf
+
+Count = 145
+Adata = 4d73c1484f9429eb15742f29ab05cbab6552abf40e127b93427d649d195ed25a
+Payload = 163f67b3766c3c650ce26c5bd8b5
+CT = ccf0c292410b6b5cd3a377690d441983a87812eaa7b66c5a0e54a01cb882
+
+Count = 146
+Adata = 2fba7a881f019a8745691343d79ef3656e25bb37b93fb5ab7311889f92010a5f
+Payload = 9c5b4aa703c27d16d82013853e16
+CT = 4694ef8634a52a2f076108b7ebe7b0afabd23b33765a63753cad66b0e6db
+
+Count = 147
+Adata = a640343fd4a866aec07b667d25176e11a32fb4d8bfc08fde2c46dc9b492fa010
+Payload = 99eb86b3202c7ce68a2339065f47
+CT = 43242392174b2bdf556222348ab639b8d0f97540373a7b9061aa3b2f7044
+
+Count = 148
+Adata = 9efd58d3ef5f74f663b2b5ca5e96c5a2fe85ca5eac1495d7f1751c7d8b412b3e
+Payload = 3f5c1d038161e65c9ed955c961af
+CT = e593b822b606b16541984efbb45e312c803e29f7be7c5eb236401037a320
+
+Count = 149
+Adata = a7d7ba684c0903323f7efc83dc32815195df325394162fb5a18f201047be7999
+Payload = be8dea2b4e602a787ecd28f2f7f0
+CT = 64424f0a79077d41a18c33c02201fd929c717d75388387dc25bfcf90b707
+
+[Plen = 15]
+
+Key = 38be46d271bf868c198052391f8a2147
+Nonce = 6758f67db9bfea5f0e0972e08b
+
+Count = 150
+Adata = c6de3be97f11d0e2ab85c9353b783f25b37366a78a2012cecf5b7a87138b3c86
+Payload = 61bd1385be92097e866550a55278f0
+CT = 7c9fa8d99b38f825315ece6a2613f55e902f296dcce870263ae50cda4fadae
+
+Count = 151
+Adata = 7c8cf9c650511f33af82e807e60336ec086bd2d9400a5f35652b8c3fcf968ead
+Payload = 7e5e51301fa44a21f2734731ee3710
+CT = 637cea6c3a0ebb7a4548d9fe9a5c15cae8a9e4b606f5fbeac2b829b42a150a
+
+Count = 152
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75
+CT = 81c8805a3bf6b176ff72e06be0e670f5419c6085e5434f056162cf80f6729d
+
+Count = 153
+Adata = 238d3c9d9de32f2040b1dd0dd040b921e456c3653263f4020cffdc552b948a46
+Payload = 20660408d6890aed84aa65dfe23032
+CT = 3d44bf54f323fbb63391fb10965b377fedcc743389a9d48e6b871dc0dd63b2
+
+Count = 154
+Adata = 3b5d61ca21953fdd22280747dd4ae908a511750127875da84dfe7d0063a318c9
+Payload = 9ab83c81f2d2c896c6596660c3974d
+CT = 879a87ddd77839cd7162f8afb7fc488137e0a856d3d911af9f420b68d8110d
+
+Count = 155
+Adata = 78c1751e86144a78285a30dc04f51742bd47e3d36b607bab48d91cddabfff4b7
+Payload = c1ec469aa9c73b677af225a9f5f6f8
+CT = dccefdc68c6dca3ccdc9bb66819dfd5644448fa8445b6cd185bdf9b3718033
+
+Count = 156
+Adata = add33e9a1d7e91e2c160c1123537e3f7e3535881cb4aac1a80ecbe367379212c
+Payload = 9df1d6b6debffdd316aeb27143508e
+CT = 80d36deafb150c88a1952cbe373b8bbd38e4dc44f768cef0c51344e3a7f7b8
+
+Count = 157
+Adata = df7736560b1a13aa8e536500ea6cdb9a6757309aadf25a6a9189055a309c3f8b
+Payload = 19eef017100dc82f26ed0815c55c12
+CT = 04cc4b4b35a7397491d696dab137172e7f2ec918099898b843a34c385f2a57
+
+Count = 158
+Adata = b40c8d22069b8a65cddb51c1ea3571160cacb19fd371552436b19c7122b28d08
+Payload = 2af5db43f2a5fe8b494b40661510bb
+CT = 37d7601fd70f0fd0fe70dea9617bbe94c2709685b0827cc42f3a25b579db28
+
+Count = 159
+Adata = 9de5559ea8ccc70f4375a436ce0b72551a75960ad5ed6a1949ee8f6c47548558
+Payload = 5de41a8ca8ed8011304fa9e9f36498
+CT = 40c6a1d08d47714a87743726870f9d63bf4b40ce7e672587816fdcda16efbe
+
+[Plen = 16]
+
+Key = 70010ed90e6186ecad41f0d3c7c42ff8
+Nonce = a5f4f4986e98472965f5abcc4b
+
+Count = 160
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f2
+CT = 8e4425ae573974f0f0693a188b525812eef08e3fb15f4227e0d989a4d587a8cf
+
+Count = 161
+Adata = b6fecd1edeb55a9a4148b1aefb716a1e162779a5ab2a682e4adce4479c527bd2
+Payload = 0e6118d0409751d36cb642504678535e
+CT = 3e171226f809dde516bc264351e47cbedf7f186e8d3d7c21c549c41ebcc7f505
+
+Count = 162
+Adata = 5c3933c30bf9d4841eff4000aaa1cb4d39cdf8ef1240e2aabbf9da95bdee5270
+Payload = 5c8a5fb36f860d00c21ae9e3f24097c4
+CT = 6cfc5545d7188136b8108df0e5dcb824810a68be1814f53c09aca4066527fef8
+
+Count = 163
+Adata = 7ca7ef30d3ac08aa51a9e5d3d84e8b6bb7fdde921e72b98ad6a93ebf2efc6b04
+Payload = ebd1cb4b35257790c9806be476bd25a3
+CT = dba7c1bd8dbbfba6b38a0ff761210a43cc30245a6e64625c4f6531d7497fb144
+
+Count = 164
+Adata = 90f1416768fca7dd48d01230dabf95f2f1a0c044bf2d755448aaf72316c8448c
+Payload = 842b7e5f22d921b2b8ab3131684b7eff
+CT = b45d74a99a47ad84c2a155227fd7511f10d85725dacc274034669acf7f34fed7
+
+Count = 165
+Adata = adc5c36849283d57acb2bcbc0e12465cb7c1830cb4e314b9ce6e25acbd8d460c
+Payload = f0c2cc5a1b4c4cbe839338fa0d7a3435
+CT = c0b4c6aca3d2c088f9995ce91ae61bd5f731b465eb59c4989e42020d86102a59
+
+Count = 166
+Adata = 80a7a483d1dbcdf00ed02a700e93d8b87fa6ac5c7368d1e81bd1b32cd1621cd7
+Payload = 2c1a5f906f2ae0373cc25e3519df2ba4
+CT = 1c6c5566d7b46c0146c83a260e43044484bcd2775448447ed801b3b0ff071c19
+
+Count = 167
+Adata = 13c02992992d2708250184a579c43bc29a3a8cf1e02dade4496cbd8b1214f97d
+Payload = 1da5190517546f1ad852f64263e1f679
+CT = 2dd313f3afcae32ca2589251747dd99901d1919f1451ad16f115cde863f15303
+
+Count = 168
+Adata = f6f18dfe093e4c0c3fbfa8a5b1f4a703c08addc2ab959741611a594b93d08bf7
+Payload = 13ccb08a580efea53dfba6a59626bbe2
+CT = 23baba7ce090729347f1c2b681ba9402ccae4f6ec07bf73d6f086cf09e2e14ed
+
+Count = 169
+Adata = 63708e12dfa14f192ec5ee5856dc3cf2403817d9628c31899b4613f65e1e61c2
+Payload = e0b5fbc6c2269d445a60273bf844892b
+CT = d0c3f1307ab81172206a4328efd8a6cb2bad8bf67d32a855c3940ac908397a5f
+
+[Plen = 17]
+
+Key = 79eae5baddc5887bdf3031fd1d65085b
+Nonce = 9da59614535d1fad35f2ece00f
+
+Count = 170
+Adata = 46603500af9e4e7a2f9545411a58b21a6efd21f2b5f315d02d964c09270145b3
+Payload = 001343e6191f5f1738e7d19d4eec2b9592
+CT = 2162e27bfbf1d00f2404754a254665fd9270f0edb415993588b2535e2e0e4fd086
+
+Count = 171
+Adata = 278afebc604bb7d87bed3574a2c5053de17eb8ca7e18ddc7892f2c54b38104a8
+Payload = ba47d5bfb36f6150a100e36caa116405c4
+CT = 9b3674225181ee48bde347bbc1bb2a6dc4778e3c4a11f3f9dc42554d45796379ef
+
+Count = 172
+Adata = 3239b2ce4efe4f6a6255dc53347400a6446ed3280c65422386fab471ef09eed6
+Payload = 96eccb7f9b0e16c6883de0a381e4767f5a
+CT = b79d6ae279e099de94de4474ea4e38175aab5540cc01d867f641c9b196fa159291
+
+Count = 173
+Adata = e2a5488d5f7930ea4ce399f2a6c0810265f7c0dc52fe824d19a0fa0d9ffd55e6
+Payload = d68f5990da1a2fe39ed81af145ab834fa4
+CT = f7fef80d38f4a0fb823bbe262e01cd27a46366fbe302e142dcf6aa16337d98550f
+
+Count = 174
+Adata = 0071f1edb3a0ce57af3c88bb0ccf138f752697a77e55695838fb39de04c78dfb
+Payload = cdd4d8b3d8f6e4742793b456cefc9e686d
+CT = eca5792e3a186b6c3b701081a556d0006df88c07797267bf5a49b3d0f601a225ce
+
+Count = 175
+Adata = f5d6989587e463969d97aadabea9538511f8d109cc2d3cecf09ba7cc346aaea0
+Payload = e7d7fc60ae852b68102e01b506f9dab986
+CT = c6a65dfd4c6ba4700ccda5626d5394d1865c9fbf69d81cef238ac513562d4a0dd5
+
+Count = 176
+Adata = e0b5fbc6c2269d445a60273bf844892b26fed03b82869edacd6dd7a63fd69e8d
+Payload = be9f51abfbe2da5a56db0f9a31b67c9f83
+CT = 9feef036190c55424a38ab4d5a1c32f783e2c748c8c9e3190de095de8eb0650203
+
+Count = 177
+Adata = e6bd0010c98e60b9af7cf905c58e0653bc425e2ccc809bd4f9cd7b1f95c18786
+Payload = 81b9c73029cea1936ef8755c80ba8d4093
+CT = a0c866adcb202e8b721bd18beb10c3289305cf563c5b4ba4ebd5bf107f2ad3555b
+
+Count = 178
+Adata = b1688cbc058816974694cd26c0f28ba9418e9912867fc8c5f4e7bd9c891a8d2e
+Payload = 618dc26853ee339689467ffbc2a77be69e
+CT = 40fc63f5b100bc8e95a5db2ca90d358e9e60dbbd8f46343c8442b03a472da4e23f
+
+Count = 179
+Adata = 469e004fee9878ed40621b41d04ec34af175f213d64d16e2f77d0bb2b6efe2e3
+Payload = 4f18bcc8ee0bbb80de30a9e08629323116
+CT = 6e691d550ce53498c2d30d37ed837c591643352e46995e8c1aee43dbdb26b46c30
+
+[Plen = 18]
+
+Key = c14eda0f958465246fe6ab541e5dfd75
+Nonce = 32b63ca7e269223f80a56baaaa
+
+Count = 180
+Adata = 733f8e7670de3446016916510dfe722ce671570121d91331a64feb3d03f210e6
+Payload = 617868ae91f705c6b583b5fd7e1e4086a1bb
+CT = b2dc1e548b3d3f225a34082f4391980a0788b4cc36852fd64a423fb8e872252b248e
+
+Count = 181
+Adata = b6ec659856866959ef6fd4e71ba930f0e3e5fd49d7465fd65f6813ab4ca1a770
+Payload = b8b342c49c28bffc2a1c457db0b537ad46bb
+CT = 6b17343e86e28518c5abf8af8d3aef21e08895a66eb5b902bb23a1a8584249409fda
+
+Count = 182
+Adata = 89eb3636fff80230352a3582be5698e3401c9e0579d48f2680c6e5e24d99f74b
+Payload = 37d694ba94d0af8df662134f20d142903839
+CT = e472e2408e1a956919d5ae9d1d5e9a1c9e0a7fa792fb7246218f7d56d5fa4a5476bd
+
+Count = 183
+Adata = 03434f3709e19a1e37edfcaabc215116763b71ab1c5e053dbdb599f86959f25d
+Payload = 90e4c0550cb7b279ef61f9140b7d94b8003d
+CT = 4340b6af167d889d00d644c636f24c34a60ea83dc3f0012ae6da32a15fd1684835ef
+
+Count = 184
+Adata = 0e2ddb65fcc72094ac388d53a1055c7e902285c4c3c33c13bb6fbb4f1956414a
+Payload = 69b851e63a78baef90637978e3dfe8c47be4
+CT = ba1c271c20b2800b7fd4c4aade503048ddd7f09d38d3dba01995e36bd685c8ea3371
+
+Count = 185
+Adata = a42b2538ee2fb5f6a85d4d00524b01ad3331f61c404069243f35f28e2c2d0a82
+Payload = b7dbf8382115199dd2a2d87938c6ae6c4241
+CT = 647f8ec23bdf23793d1565ab054976e0e472c89becf8d2bb935cb17f44b950df3ef5
+
+Count = 186
+Adata = 09bc5c426dc1faa4d71f50908bd6f297ec8e754d4d20def005585b4bc1fa31da
+Payload = d53698d719c51bf9eae346269c6a1da07162
+CT = 0692ee2d030f211d0554fbf4a1e5c52cd75196e28badf0202097e80561451796194d
+
+Count = 187
+Adata = 2ac87e59c2c86532cf165af3e8ff4871d730f5e742cccca38bbcdffff4472c93
+Payload = cfdb7363985aa01af6f8e8237dbfb7871eb3
+CT = 1c7f059982909afe194f55f140306f0bb880710d4d7f66660891ac655d6eca4a3f3e
+
+Count = 188
+Adata = 05d2fbc3d0ec81f52f31cb0c4bf960c2076867f6d9f0174ed9176e20177b2693
+Payload = 56fdf10dc0c1dfd10965b83938e557459c61
+CT = 855987f7da0be535e6d205eb056a8fc93a52f90ab18925fea6964490f364a975a473
+
+Count = 189
+Adata = c2c3902cfe8622254b3787cc13e79c5a3c388c2357c29f1c1ab5539a10bfae5c
+Payload = e7c9812eda2ed7dcfc80fc5fe0d43e1e5982
+CT = 346df7d4c0e4ed381337418ddd5be692ffb168a00e5e7a39b371024927d3ac98fe43
+
+[Plen = 19]
+
+Key = c5e7147f56ba4530b8799ababeb82772
+Nonce = bdd38e173fb20b981659c597d6
+
+Count = 190
+Adata = 3a069a2bfda44abbb0a82a97e5e9047258c803da2c66190d77149e0f010b3af9
+Payload = 2f3bf0b566440912a1e47a0c07f1cfd39cb440
+CT = bd6265dcba9e14c59e515e395dc60bd053345fa6d7568c738e3a7fdf142d8f2d1562c0
+
+Count = 191
+Adata = 7709132415c94960025cc39c950ead208703a9d5a71e224fd022dc0a1817d0f4
+Payload = 7c880d787726c4ddeb2304b5d161b4a257298e
+CT = eed19811abfcd90ad49620808b5670a198a991f22337efa5cb7db7240e7518b67ffbb1
+
+Count = 192
+Adata = aad77595f87a27f2c7995fc7149317f4cbebcece8336db2068380070784a4283
+Payload = 08c43bbfa706512aa39e2bfa5c365aca11e22e
+CT = 9a9daed67bdc4cfd9c2b0fcf06019ec9de623140bac6094528f02eeda093312fcf716f
+
+Count = 193
+Adata = bdb1b82ba864893c2ee8f7426c7b9a8460b00a50f164fc8f2ff2ae9cddab8657
+Payload = a531c0ed8840b2fcf08d76eca71036153b6e11
+CT = 37685584549aaf2bcf3852d9fd27f216f4ee0e0c041d86dd483c1d6da366e91bd826dd
+
+Count = 194
+Adata = 38b3b9f45041ceb743fc2655b409213fa081427e41c833a2321a09fbd566c80c
+Payload = 177946b4dc3b0b825a505f097a0a203eb21c00
+CT = 8520d3dd00e1165565e57b3c203de43d7d9c1ffde45ca2a83dec2f930bb652a6fcdc5f
+
+Count = 195
+Adata = ec9d8edff25645520801b6e8d14a2fc3b193db70d5e5e878742de83154a578da
+Payload = a2634ef20a2a418b2c3be64f0b5f79d7ea9b7b
+CT = 303adb9bd6f05c5c138ec27a5168bdd4251b648b89aa22cd7d0170a975565cd3a33dc1
+
+Count = 196
+Adata = 8f6c1de4efdc5ac2d6e5452b5b4f58416d618da672f521332fd297ede8350134
+Payload = 40e52edaad5acf2d4eedfb3f9ac2908112e9b1
+CT = d2bcbbb37180d2fa7158df0ac0f55482dd69aed960b33c3df5cd38a82980dc0950ada4
+
+Count = 197
+Adata = b0f1dc85fe223bcf29cdfa9319866bacd0a0a79c554e24d1f10889279e31c0af
+Payload = bf97780f498c23adcf1c49f60873780a235969
+CT = 2dceed6695563e7af0a96dc35244bc09ecd97638fa273c4102b5ca050b23044ac2064f
+
+Count = 198
+Adata = 7d02a323aa769a8201549bf48a520d940bf6f69ed6106f1ce68856c22a594216
+Payload = 58bfe1eb2d38d91f80b3467db94fdcb84ff5f3
+CT = cae67482f1e2c4c8bf066248e37818bb8075ecc15438af1bafac3eac61e1c24ed00ab7
+
+Count = 199
+Adata = d4b90ef8abad08c552c8c3b080b8c37df314d514049d45e27ec4527cb06cdf85
+Payload = a206a1eb70a9d24bb5e72f314e7d91de074f59
+CT = 305f3482ac73cf9c8a520b04144a55ddc8cf464422d9e2f4f84fde49e9701296294d5a
+
+[Plen = 20]
+
+Key = 78c46e3249ca28e1ef0531d80fd37c12
+Nonce = 5de41a86ce3f3fb1b685b3ca4d
+
+Count = 200
+Adata = e98a77f2a941b36232589486b05f4278275588665a06d98aec98915cc5607e06
+Payload = 4802422c9b3b4459ba26e7863ad87b0c172cfe4b
+CT = daea2234ea433533bf0716abe1aa3844b6d3c51e9d5ca3d8ec5065630d2de0717cdeb7d5
+
+Count = 201
+Adata = 5970a836de1f1e91d94d7eef79742cbbd46a759c413715eb0224fd6a27145333
+Payload = 796a69ad0e9379173ef6b66f44f5c84fa70a0e28
+CT = eb8209b57feb087d3bd747429f878b0706f5357d0ff0648ddb07f42f815b38bfc95688b1
+
+Count = 202
+Adata = e3f08834c4894f6fa66a55a280c0e677a79e97c1ef9488b21384e74e57b1b51f
+Payload = 98e1f8cf250183b13ad418024dc40c1a6a7ee8ac
+CT = 0a0998d75479f2db3ff5e92f96b64f52cb81d3f93ddd9a6977ea8e7adf5c5234346e560f
+
+Count = 203
+Adata = 18349be2894d49290339b97f4db28c92b3e112ffac77100abbf9c093935b1a46
+Payload = 4a856d9b50a5b40d6566b38eae6a53ed0c192805
+CT = d86d0d8321ddc567604742a3751810a5ade61350bdee05328a7ea8cc6c2e42bf3faeeda0
+
+Count = 204
+Adata = 7355e34ad13880de17a1d66b02672ea5c9f51774019f64ecbe36747ffcd9b671
+Payload = ad048eb2ad75266b43b59d9d1f073c44e4cbf25e
+CT = 3feceeaadc0d570146946cb0c4757f0c4534c90bafb1435cf929db35ec5986aabaf4a7d1
+
+Count = 205
+Adata = 4be21ba2eb26234ddcbb6aac6b4c3be7ef644af64edf51b7c29ffc3ddd80036b
+Payload = 5b527ac6cc6d1b4c3c56f8315bc96dae91632df9
+CT = c9ba1adebd156a263977091c80bb2ee6309c16ac736be6563cf9f5bce97486b7cc6f1c18
+
+Count = 206
+Adata = 266e0e3365e06d3b1e864c6e5897145df7bdde90eb744013a7b36632d4cf6580
+Payload = cee059cb0fe91a39faccc2914340baeab4b644ce
+CT = 5c0839d37e916b53ffed33bc9832f9a215497f9b2e90335fcea56b969b4fce65442768dd
+
+Count = 207
+Adata = 55a723883a340877d85ad1a5f264f2c834d824c7bbf207cdd8500c9d11ef9225
+Payload = 85321fef6a2b7d31cbd079c4bf2bfbbc979df90b
+CT = 17da7ff71b530c5bcef188e96459b8f43662c25eacd6afdb3578ebc75e8a408d32758931
+
+Count = 208
+Adata = 773864475a1a60a778468a66cbe13dfe3458094e62abb593f50c8495e3a8b81e
+Payload = e227b8d44320bd3ce9d3f7d688f3de887947b1e9
+CT = 70cfd8cc3258cc56ecf206fb53819dc0d8b88abca19fb73fc0488d9f29a09c1b47e3e066
+
+Count = 209
+Adata = f64f3b00c9117aed3c486aa4c8d574b44d679be4069e1078bb7100af38cdb190
+Payload = 206e9eb2bc3f8534d844a38debf1306df808744a
+CT = b286feaacd47f45edd6552a03083732559f74f1fce2c5ef8cdce76b358739e2a1b173fb3
+
+[Plen = 21]
+
+Key = 8883002bf13b3a94b2467225970df938
+Nonce = 818a702d5c8ee973b34e9acda1
+
+Count = 210
+Adata = 545aeac737c0ca2a3d5e1fd966840c3a0d71e0301abbe99c7af18d24cc7e9633
+Payload = d516bbff452e7706c91c7ace3e9baa76d65ff7050f
+CT = b85242fdc06344f2bd9a97b408902ebcd22aece3d42f2da4dd4d817c9fa2d44bc02163a0a9
+
+Count = 211
+Adata = f032db01da60ca078d35c3fb5d05d6750fce1c01911a0422e827e8976946e4dc
+Payload = 590d1aa655fed50ca2e402299f2da6fe20eed56071
+CT = 3449e3a4d0b3e6f8d662ef53a9262234249bce86aa180f41bccbcd47c8b7890754c032269b
+
+Count = 212
+Adata = 71ecb4252518997b53491cf42a3e0fe1496a2af2329a16f9fcd9c4f249900341
+Payload = ecd86cdb7d78d310dca5b477cd9da2612f5a05ab39
+CT = 819c95d9f835e0e4a823590dfb9626ab2b2f1e4de21d6ba58cc2eb474401851bf9502c3413
+
+Count = 213
+Adata = ec7abed9bda4a52fdf1bf278b6bdd6b0a27d4688deb9ff5ca9c8c865a4d2f730
+Payload = 0024b14c283df032cf80c22ad8d2c96289ee229092
+CT = 6d60484ead70c3c6bb062f50eed94da88d9b3976499b94d4b7a2044696c72322e850537b6d
+
+Count = 214
+Adata = c2c77d7ad7b27d7c0f976a1e28881ea4ec7ad03b63a4e67f47280a40b8f58086
+Payload = bc6965d8f62d066d118c14044c1fd2a224b9d95110
+CT = d12d9cda73603599650af97e7a14566820ccc2b7cb9d8da8e718570caf8bed7909fbff3ec6
+
+Count = 215
+Adata = 28929286bd1391468ac75f5c03689f74780ddd7585fc16f9a9bf7b00357a72e5
+Payload = da4a630cabaff0728a1cc3e6a79721a7176b708f1d
+CT = b70e9a0e2ee2c386fe9a2e9c919ca56d131e6b69c6e671012690c61fe3c9abd50a78eb4736
+
+Count = 216
+Adata = ed360d22081b019dc979420a3a45c21c8903c59daedd9f1b4ef2bfdedff0ec1d
+Payload = a95058f8e1f6bc0f143a9ca7e4425a2a63eb2f7e33
+CT = c414a1fa64bb8ffb60bc71ddd249dee0679e3498e8e657e2250427130acef7032454cde7b6
+
+Count = 217
+Adata = 2b4022d0b951fe48635d04fb3e2fa032c07c855fdd73f45670953bb9ddc77cb4
+Payload = fcbbc7f9d1ace60e830ca56ec84814fbd2579993d4
+CT = 91ff3efb54e1d5faf78a4814fe439031d62282750faac6ff0a264b8199550d93c1f06063da
+
+Count = 218
+Adata = 48e553a87a7d3c1bd68af39f96aca67583da86e06701d5e4c4ed404dc66d70f3
+Payload = b95d298d391c6b893c6cad66f9780534516e71455e
+CT = d419d08fbc51587d48ea401ccf7381fe551b6aa3857e68bf636e81c332f72063dc0d6fc2b6
+
+Count = 219
+Adata = e8e2835e47144365a2f218d4c95d7522e824fb43b66d4727ee570f8303dd6dd3
+Payload = bc79d444dff9d9e722effab07b068cb7723ae8fae0
+CT = d13d2d465ab4ea13566917ca4d0d087d764ff31c3bdf3af9e9c4e04bad261dc17cf00a00dd
+
+[Plen = 22]
+
+Key = 5cea00ee44cfb9cfbb598d3812e380ef
+Nonce = 948788a9c8188cb988430a7ebd
+
+Count = 220
+Adata = 50422c5e6a0fb8231b3bb6e2f89607019be6ad92a4dae8e0fe3f9e486476004b
+Payload = 33bfd0713f30fcac8f7f95920ac6d9b803ddd5480dd8
+CT = b168747dea3ae0fbede4402af9a3dc3185d6d162f859d828101682de32923788c70262b84814
+
+Count = 221
+Adata = bb0036b34b0c20094d335a8c74f6b3dea42eeccf4145192eada64ae00c726b2e
+Payload = 5576d94b577ed26820fb13c00ab0e2d1a1c3589bfdc4
+CT = d7a17d478274ce3f4260c678f9d5e75827c85cb10845bafc4ae4d31907def6f648b081174e2a
+
+Count = 222
+Adata = 5140324aa758dbbb5391b5e6edb8a2310c94a4ae51d4fba8a7458d7cc8488baa
+Payload = 13303e14068205cbfa992d4ccb6a265804ea64a15d7f
+CT = 91e79a18d388199c9802f8f4380f23d182e1608ba8fe314e378e9ed6e725a14c07632b02bdbd
+
+Count = 223
+Adata = 74da07d324060e590356988f27d9879fa3a3ade0fe71e2a0e49054211cfa1fe1
+Payload = 567e6d14b446add630d53ea86a537c0938537c4604a8
+CT = d4a9c918614cb181524eeb1099367980be58786cf1295bc2f2f9331536f7f70be09c41bda0ad
+
+Count = 224
+Adata = 0e403cff47adee3ec5bb6b178dabfc7d53b60a04eaad33a2fedd9db705358a4c
+Payload = 9f3d165d44cf1c5770346d211d4ff34ca2ecd6b28549
+CT = 1deab25191c5000012afb899ee2af6c524e7d29870c86b59cc9c3c008bc5876ef86327859cbe
+
+Count = 225
+Adata = 211e6ce3d0c3abdef069e6e4fa35015797bd8a9d64bc9b75f20b028b12cca04a
+Payload = d726e599db6a6d40629bc4bda5e3fa2e5aeda229cea4
+CT = 55f141950e607117000011055686ffa7dce6a6033b25135e6d59a5385a78658d60d254f99962
+
+Count = 226
+Adata = 3c5c67b083322115e1b3112c2b6968efc050094e23e646dce982eac9d6e67d10
+Payload = 42646cfb8a99e48a35cee3f5f9b3e6175695973f6de0
+CT = c0b3c8f75f93f8dd5755364d0ad6e39ed09e93159861e234e83d9a0570dbf2b2fa59ce3cdbd9
+
+Count = 227
+Adata = 37a931f1dd05755b376d1a164aa36b8de802e39f8108a0453c1114754665fe46
+Payload = e814c7b5c72d973a9bc7ccd463f107325ffa3321783b
+CT = 6ac363b912278b6df95c196c909402bbd9f1370b8dba2084e352b1b157267228576dd056c1a3
+
+Count = 228
+Adata = f1ddc2c49da7363526ba36c600c589b4c3121fbb8c5b9a8aa0de0e7453b30568
+Payload = 4f7a5618870945b89f194e31b1aa802c5350326dc691
+CT = cdadf214520359effd829b8942cf85a5d55b36473310bf88ad35ee338e489e55bb49732447cf
+
+Count = 229
+Adata = d14b3d3803df432488b5d66704abef6a500d397e855bc2c2574df746a515cf70
+Payload = f555216840a1f40b411d44128e567617e2694caf1621
+CT = 7782856495abe85c238691aa7d33739e64624885e3a07ab67f9397a81371ef6ebc775cb7007b
+
+[Plen = 23]
+
+Key = cb83f77751e72711401cbbf4f61aa0ed
+Nonce = c0b461b2e15b8b116ef9281704
+
+Count = 230
+Adata = 2bd112231f903fa0dff085db48a2e2a96ec0199249b005d5ab4c2eab753f9ad0
+Payload = eede01b08f9a303cdf14c99d7a45732972c6eff2a1db06
+CT = feb114b7bd3b43497b62454a675a632c3546d2802462c6af57647efda119c59862cd5dd3904efc
+
+Count = 231
+Adata = 864e0e728aea856fae6c6daa6357d1542cef7177f441ba21a563f6c4f6fdc1dd
+Payload = 8a56588fe5e125237b6cdc30f940b8d88b2863ec501a0c
+CT = 9a394d88d7405656df1a50e7e45fa8ddcca85e9ed5a3cc2af4027ca5824b41c7bb238d3e8eeebf
+
+Count = 232
+Adata = dac7f3cba0b5a47f67f85b226b66df695a8ae2501355e36aad105375bb95f732
+Payload = 66e34540d7accf377877aa2d3e6d2db0cfafc608a1eb3d
+CT = 768c5047e50dbc42dc0126fa23723db5882ffb7a2452fdf7fbd7044ce1d7b266bdf545247a3c2b
+
+Count = 233
+Adata = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c930905aadd156b1dd56e
+Payload = a9ebd04fba7155c39b5c29c5571b5354c9ae228f5e5b13
+CT = b984c54888d026b63f2aa5124a0443518e2e1ffddbe2d3afabc559b552cf7c7730c7dca25bc3ed
+
+Count = 234
+Adata = 2d24e79abd157af2c21b60932947fd9f9d6478f09ec56fffd341ea04a17b8e5f
+Payload = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381
+CT = e116203ddd955c7acd6a23c8d69e0e3a2284dc3fe82a41488ca99e0f85ac388f981ce25560b8f9
+
+Count = 235
+Adata = fea280f710379e4665b5ed3d1620729a7bc164899dc83e6aee3612d538fa20db
+Payload = 6c19a18eab544acc883c5886eaa89f54d61ae5f1f1368c
+CT = 7c76b48999f539b92c4ad451f7b78f51919ad883748f4c9156faae3d8860bed216e8d497a75962
+
+Count = 236
+Adata = 18f2e3457127c35f2e0cff2d821af8178028fcc7803bc795c49f4a435b37abeb
+Payload = d0df1bdf1df6203241722fb9c9c1cf7405017497ae1545
+CT = c0b00ed82f575347e504a36ed4dedf71428149e52bac8588cd7791c544d1098b2de49d04b1e0c1
+
+Count = 237
+Adata = 35221f0efcb109cb93c38a62c58b5ab8b236437e171e8507cf417a569af1767c
+Payload = 479526b33c42c240b9a4549ca70cbfb691f16ae3be8888
+CT = 57fa33b40ee3b1351dd2d84bba13afb3d67157913b3148c523fd8a2524717f63dac75c22268fa6
+
+Count = 238
+Adata = 95f2ab02af01aeacce86b02cf846f9fbd516963d06e350e8b7f6df2778765a01
+Payload = aa6761148b254a2ff202b620c2ec2c5e623bf61f05e483
+CT = ba087413b984395a56743af7dff33c5b25bbcb6d805d4392904f05dc2397596543df73de5aa708
+
+Count = 239
+Adata = 3746a36154e42dd600049d506f5ce4d034864263b1a65cecd24c8e25fb9c82e1
+Payload = 2f298f106703b8a994cbb20acf47f9442e44f6b5e82c38
+CT = 3f469a1755a2cbdc30bd3eddd258e94169c4cbc76d95f8c3cbfecfa3f75fb111ef0011222b7948
+
+[Plen = 24]
+
+Key = 43c1142877d9f450e12d7b6db47a85ba
+Nonce = 76becd9d27ca8a026215f32712
+
+Count = 240
+Adata = 6a59aacadd416e465264c15e1a1e9bfa084687492710f9bda832e2571e468224
+Payload = b506a6ba900c1147c806775324b36eb376aa01d4c3eef6f5
+CT = 14b14fe5b317411392861638ec383ae40ba95fefe34255dc2ec067887114bc370281de6f00836ce4
+
+Count = 241
+Adata = e82fc3ffd276218a82aede65fe5abf4fd35c7059a26923f8dbb97a59c903a7f4
+Payload = eab8cef576816a82ed036f158e5036f5987b195e60582a6f
+CT = 4b0f27aa559a3ad6b7830e7e46db62a2e578476540f489460d2d30268e9f1ce0e7c762993297d828
+
+Count = 242
+Adata = 776aae7f62225556b6da522c0c9432ac70fe72ac6f3f361071ef3deb4a6715e8
+Payload = 566ef9ce1d397be2547c385639507a9e7d6f9eed9a3b1055
+CT = f7d910913e222bb60efc593df1db2ec9006cc0d6ba97b37c0939e56f0b7200d1b1409f3f8e8179cc
+
+Count = 243
+Adata = d9aef0955922f89747ba4a8ddcdb8c1c7579aefd3c2eb8ad0589c66576a8504c
+Payload = 8c28b6d93b23f1ea031d5020aa92f6608c3d3df0ee24a895
+CT = 2d9f5f861838a1be599d314b6219a237f13e63cbce880bbc138e3b817023993608be06fe92efca8b
+
+Count = 244
+Adata = 13c222a65ce30570ecac85a185a2a0922a8c96d633339a1ca067ce57ae426e1d
+Payload = f0c1cd60f5fa8d1efd5e2e1ab37c4f7e6aef76d15e8d6ac8
+CT = 5176243fd6e1dd4aa7de4f717bf71b2917ec28ea7e21c9e1f3ca13b4ab7fd0d4badf158972570c06
+
+Count = 245
+Adata = ce40fb0cbfdf07676ed55b040ae6be5db8f0a0f28816ae8ea71da3cbd71661d8
+Payload = 570d5f79aa8db14b1ac99ee567cc105ae9e238e482b52628
+CT = f6bab6268996e11f4049ff8eaf47440d94e166dfa21985010a79fa4e8b27a31ff360a1b6c05ff844
+
+Count = 246
+Adata = 446b01d09cbc41b6393ef81ca65ab7e099018187d5f9d22f5074dfc491e72077
+Payload = 7c267223047af946b06f6a45ffde4a5ec49c28b81ca22da4
+CT = dd919b7c2761a912eaef0b2e37551e09b99f76833c0e8e8d5d34ef0ca0b47d6a2ec7442cbb739504
+
+Count = 247
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2398e86ac3fe48bc7
+CT = 6a46fbbbd89e7738148905f4f56971e5448dd8971f4828ee8f607d154393e35fd1efc1ae8cb244e4
+
+Count = 248
+Adata = 5032b818d202872f3fe2b08fc7940696df02cf393a6d6247f5c6f5f2125cb08b
+Payload = 4324a89788e8ddae5d560cf937df701743cbbc3bf980558c
+CT = e29341c8abf38dfa07d66d92ff5424403ec8e200d92cf6a5617d9cebea38591a00c9fba4ef9c8e71
+
+Count = 249
+Adata = 27b661861717f00a3ae22ead78f4dc3f32b40e8fcb8ed58167a31a61f2becd77
+Payload = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad1
+CT = 7ac530d240e740f8a5fdaf87c6adc5ff73cdbb312e39d9f897062a1ec759a515b938780f902fa7c2
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp
new file mode 100644
index 0000000000..abf1775dd1
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT192.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = 086e2967cde99e90faaea8a94e168bf0e066c503a849a9f3
+Nonce = 929542cd690f1babcf1696cb03
+
+Count = 0
+Adata = 58f70bab24e0a6137e5cd3eb18656f2b5ccddc3f538a0000c65190e4a3668e71
+Payload = 00
+CT = 3bf9d93af6ffac9ac84cd3202d4e0cc8
+
+Count = 1
+Adata = 760d065275e345900a7bbab451cc9309fb161e6cfec526538b98800e4102e14d
+Payload = 00
+CT = b0078a769ab68db44e723993da382abc
+
+Count = 2
+Adata = ffedc67efd355ea404fcbcb3993d3bae81386ded86230270771deb747163bf44
+Payload = 00
+CT = 31fbff2d715a2eb9af54e8320a8e42e1
+
+Count = 3
+Adata = 55153ff5e4d208d2e647794f382c788e0e36f293e63e7290ba9ff2657ae0f167
+Payload = 00
+CT = 945839d62c9d1b899f6dcd0ca9517e68
+
+Count = 4
+Adata = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe6ffbad084f639915
+Payload = 00
+CT = 903f90d23321a6882d6c4c1955b14847
+
+Count = 5
+Adata = 7b95cd827ab93507f1819ae76627d6e2a31d29890c092e5c300f0e2f9e4ef4d2
+Payload = 00
+CT = 652ec5ab43088eb568186d0d9887b30f
+
+Count = 6
+Adata = bd144c9bb974729aaa1188ceefdf85e1d9fddc0b0c8afe8828ba204aa9293feb
+Payload = 00
+CT = e6c1455d1117eec49338c96f51007309
+
+Count = 7
+Adata = 92b911cdc3137a6f7f32651b788eb82975660aea52b2c03b4759755a6da4a0f8
+Payload = 00
+CT = 1cf3c32fb229dac209523eaa517bb59a
+
+Count = 8
+Adata = a8200dbbfe4086015cdbdec2fc8e4934d0d663527430c424627ed44065ade091
+Payload = 00
+CT = ee10bfeb1cf9b3cd5a0faebd4d8f3fe1
+
+Count = 9
+Adata = 3b7f37b6b8e3c1390a99d59c47f7c102cf659d361a132ef8b4e70b9585bafebb
+Payload = 00
+CT = c51ed994253adb9bb5b9a8c34a27f225
+
+[Plen = 1]
+
+Key = 992d38768b11a236945bd4b327c3728fac24c091238b6553
+Nonce = b248a90b84b0122a5ad8e12760
+
+Count = 10
+Adata = 27cabc40da0e1eda0ea5f8abbb7c179e30776250a7b30d711b0e106c5ee9d84a
+Payload = 1c
+CT = 1a96f58c3f38c44d1a345f3e2da6679f20
+
+Count = 11
+Adata = dc2e28d5ae726c1beadb1e7e92ae7d14f5546320deb81a910bf170cbe0210eaa
+Payload = e9
+CT = ef0579aee7c17482691f3f832d867ffea7
+
+Count = 12
+Adata = c579f912ac1b45d5aa8cf20f78f0a1ace32abd3dc7fd0b3f3a7182a008795c7f
+Payload = 97
+CT = 913452d8ece38ffa1d4107d6a053acd8c8
+
+Count = 13
+Adata = 69ea953dbb910ec589372d797c7379d3f3b9e9fd48894c9b55e6e8eb360a6211
+Payload = f4
+CT = f20d760b9fe29530738157db0ba2d253f0
+
+Count = 14
+Adata = 622835dea57b2c70cca8f7548d6210714070b55b36adde7a4c547269c07aba9c
+Payload = 9f
+CT = 996fc21f24dee7b52f51d69eea30819f4a
+
+Count = 15
+Adata = 67ebda0a3573a9a58751d4169e10c7e8663febb3a8cf769d81bc872113f0720f
+Payload = 43
+CT = 4594c5b8db0064426a77dc536814c56147
+
+Count = 16
+Adata = 255412e380e9a28cbcd345be172c40f72dec3e8a10adfd8a9ab147e9022524e1
+Payload = c1
+CT = c76d36c0b0d699a22da3116dfb8f453181
+
+Count = 17
+Adata = c7c8e7151eb6844a954d091b460f83add0f0a634aa5ac213b774f2451aa497fb
+Payload = 31
+CT = 370c3a1690acc3f0eb09c9cfd3396c7fa9
+
+Count = 18
+Adata = 63f00b2488809fdc49ca5f05d54e98468906308115f7e702da05ddfd970b5537
+Payload = a7
+CT = a1ad45070fe4c61270c13cc52247fee411
+
+Count = 19
+Adata = 8e2c5e55c0bf70014e9897b6f6940e4e738b1e84e8269b6382f0b1fe59b0e162
+Payload = 40
+CT = 46b2a2a8b283ff7eeff5c2670f77b8809d
+
+[Plen = 2]
+
+Key = 5012db40ff6ae23c1e1ce43768c5936c4400b0e79ae77f30
+Nonce = b67e500b35d60ad7264240027c
+
+Count = 20
+Adata = 40affd355416200191ba64edec8d7d27ead235a7b2e01a12662273deb36379b8
+Payload = 0c6c
+CT = c996ef3d6ef9f981557506ecc8797bbaaaa7
+
+Count = 21
+Adata = c5e12e17e02bcc12b3a4c14cf837250e2886db3ee1c717d28bd11e8a3b764ddf
+Payload = 23df
+CT = e6254405257a837c5343b59d5689d6de5269
+
+Count = 22
+Adata = 213b5b6015d472bd593be5acf85ebba6d6a09f3a962be302ba83c6d70c61f241
+Payload = 0dc2
+CT = c838e93e67d37d2367bb1f27f71b54b29317
+
+Count = 23
+Adata = fc1b6e152fe232b6c10b5d89900961c445f4c46833df242c826678b68c869811
+Payload = dc88
+CT = 1972ca3744a4ab375af9060621a9dc4f4c32
+
+Count = 24
+Adata = 5b2eb1a6fa585d61d1fb3da68f5b93829c8e2d5e4fe03782617553d7a130ecf1
+Payload = 8179
+CT = 4483172626e930d24052bc056d8609c4175f
+
+Count = 25
+Adata = e2b3c3bf33cf847660929e48cce51d9d9289945169651aaecb1e939756e93105
+Payload = 01fd
+CT = c407852310207be8d3417de800b372700da2
+
+Count = 26
+Adata = 6051f12cd8aae68b4023aaf7178fd086aa582b8d8821e36637abc97025f5e858
+Payload = ca18
+CT = 0fe228553bc037954dbf4ce5db99792c2c7a
+
+Count = 27
+Adata = 2d3555faf285caaddfe95c010c2a7f233e09c2fc0cd30d644035269280527ad7
+Payload = a855
+CT = 6daf904725668634d6345bd8f90a3831b452
+
+Count = 28
+Adata = 4fca820dc545bf93bdffed33a04b67eb45384e696f092c2197e5d79cecd09913
+Payload = 5555
+CT = 90afdf6098cb3135c3045a54ffce88efaceb
+
+Count = 29
+Adata = 1789ae403e183d2225f431f001d475b53bccdec66572bb027340ae592839ba8b
+Payload = 11dd
+CT = d4278568e8c08ff5ee5ea0a608589c2fc029
+
+[Plen = 3]
+
+Key = fa15cc7f0de294d7341b1fd79326c8be78e67822343c1992
+Nonce = e5257aed2bda0495aa44591db4
+
+Count = 30
+Adata = 31a0338c3839931fa1dd5131cb796c4c6cfde9fb336d8a80ac35dec463be7a94
+Payload = bcb898
+CT = 68f08298d9a2147776dca9c1a42382bce323b2
+
+Count = 31
+Adata = 4863dd810ee70ef0f5da81f60c5ce550abb96454619032322e34657af25207de
+Payload = d1da2e
+CT = 059234a9a77755b324f3a557217752ade14ed7
+
+Count = 32
+Adata = 173594fc26b167f044aeaf9bfe920cab99a27eb2b01827d61f7553cb2018b5fe
+Payload = 394f31
+CT = ed072ba4441a79a90e228a28069fe109d5d876
+
+Count = 33
+Adata = 71cdd16eca9255aeedc23bd623513918ea97da21485074415fe75bcc42f454c0
+Payload = 868bda
+CT = 52c3c065f272f44c5210b5bcc571e819580910
+
+Count = 34
+Adata = e84418d332d16d2298e69e7ff3c37bc7b6e030cc822e73b3f4a0029bc2ea4d80
+Payload = 52d6bf
+CT = 869ea559c5f7f73a1b5f419c9f63ca401894a8
+
+Count = 35
+Adata = 42d962109bea1d50be0f3d83b4c2a6033d53b3d7112591866b1ae52dc84cb5d0
+Payload = 6f8d58
+CT = bbc542220b828cf5365137fb3f1df67cc8d2a1
+
+Count = 36
+Adata = 943b4327b5c70dba63c82f27e0412b3ada012bc0f7dd39ebb13db2f864daf80e
+Payload = fda286
+CT = 29ea9c422b0f41075ac79a0afa2d1047cbbfb5
+
+Count = 37
+Adata = 6076b94caabfa476ab7e6482e4fda9b29f2e2b2883efe44d668c7c74628505bb
+Payload = 8651fb
+CT = 5219e1ae68cd6d6815ecbfd01293d160d4d38a
+
+Count = 38
+Adata = 3e4bb5781f84b4bbd23583e3dae561c6ff4af8eff35e2a4f35b50d2f360d3469
+Payload = c3e179
+CT = 17a963fbaa81cfdbcaee476860cd5102f556e4
+
+Count = 39
+Adata = 364008acbad330d0b8d574641a97b0682c49279cfdc80ff309b7514514d18a44
+Payload = 4a97d5
+CT = 9edfcf7ad1520564b68824a3a939371c21a336
+
+[Plen = 4]
+
+Key = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf
+Nonce = 2ef29d62b40d8643848797cde8
+
+Count = 40
+Adata = 1225b036e6044df52314016760e92750de0936120395de750a2c54a7fa0cea82
+Payload = b46b343e
+CT = c2c39d6f9344e2de064f269d065a2a6108605916
+
+Count = 41
+Adata = aaa6257d6783936a4445833c2ac3bea8cb7334f22ade9c035d515bbc91d6a78a
+Payload = cb216301
+CT = bd89ca50693d90b8297b90bc41c231d08b0204fb
+
+Count = 42
+Adata = 1c1915fab09348b9a5536495c70d1a040305708c1124797e564b63e008e7b8ab
+Payload = 697a8696
+CT = 1fd22fc79d0146fe373437c529fb2eeb169e4bd7
+
+Count = 43
+Adata = 864d0f786497c7ce283762ca0959ec9c825ed445a5dbe5b4b2e5772fe88ce7f5
+Payload = 6bee3db9
+CT = 1d4694e8e389c549bfc4ede936d7896e544b23ad
+
+Count = 44
+Adata = d5388b0b548c58886dcd335dff2b1ed23ce3eebbb708fb5bbd831c83e959d3fa
+Payload = 85d95855
+CT = f371f10495177a9fe6d9329a585c8737c92a4d29
+
+Count = 45
+Adata = 83cddd189736f224cad6a29efba45e43c75450a14f1541713b7fb926ffc768c6
+Payload = e8b23340
+CT = 9e1a9a113914431a10b1f94a2b99b9e442f3dca4
+
+Count = 46
+Adata = 8fccbd1fc5240691cf24e8807bf3416c1b2d87fc86dbf3955fa2e52b9a3a8457
+Payload = 595c4d7c
+CT = 2ff4e42d383d8dc98b22010dd93cd0cbb396d9e3
+
+Count = 47
+Adata = 513d45f6f37f3f051667dc743215059e06e4fdc8945789b16d50556a2e839368
+Payload = 314e0c7d
+CT = 47e6a52c40c513bfc92d1a7db5ed7cab2d8212b0
+
+Count = 48
+Adata = 70828be102e554f0d4b07641fa3254bc8db06eefaf5b85a7c97e01c217fc8f3f
+Payload = 35753e32
+CT = 43dd9763ea98f4ac6b3eabd483f1e6ab92f3b83c
+
+Count = 49
+Adata = 343d5a4ad39acf81adcf24e9807618932abcb3bc076734f179174c77c8cb89e9
+Payload = a531c0ed
+CT = d39969bcf99fb67b1e2aba2d232db2445e6aec2a
+
+[Plen = 5]
+
+Key = 30419145ae966591b408c29e5fd14d9112542909be5363f7
+Nonce = 27e6b2a482bbc6f13702005708
+
+Count = 50
+Adata = e04e81e860daf9696098c723085d8023c240ebe7a643131e35359ab04bd650fe
+Payload = 8ceaeb89fd
+CT = ec9d5ed36243ddf77b33d8cf2963ba76fd4e19f3c5
+
+Count = 51
+Adata = 6217cd581d4b3b2f7bcf1b8dad9ad6430e2e3a0063cad52260e0a1cd6fc9e73a
+Payload = 7e51d6f870
+CT = 1e2663a2ef6b73fe9e638e205b27f78ed1bb9b0ed0
+
+Count = 52
+Adata = 8aa7847e496f5e9f1f87851442de844f27a21c1b48f82fe525f0dd5a88b8ec38
+Payload = e0023b674d
+CT = 80758e3dd25936115e23158aff1916edec241fad56
+
+Count = 53
+Adata = 3612abc865a4d8d7b86a84109388584df6526525adb1006ec6c8d00048d725bc
+Payload = e2b5b6f36e
+CT = 82c203a9f1f15aae4b70dbee244be1daa74475d7e2
+
+Count = 54
+Adata = 849a99c6f1cae0ad4bcde4bd0811e87ca5ed7b913de1a8285a206e980b4b7043
+Payload = 9a17e4a22a
+CT = fa6051f8b5bbff424487848385f8501ab5a77f327c
+
+Count = 55
+Adata = 9066367c784de0a4d1116bbe95ce55ded85edddb6273c2049ee24e0fb3429352
+Payload = d4e765fc78
+CT = b490d0a6e772d8d5da6f593a8d9956731b42645aa9
+
+Count = 56
+Adata = e7aa9f767fa8920f96f91c41d9e86755faaedaeda596a444b65f99b7a9e23e85
+Payload = 1074349e10
+CT = 700381c48fe3eca12b835dcfd08166ac8831585626
+
+Count = 57
+Adata = bc0db1ebf910b6f4dcad5401401d6bc2272e23130947dc236ca664d5b5ed6d66
+Payload = a46dd7fb58
+CT = c41a62a1c72bcce66018e9e552d2c8a229301361df
+
+Count = 58
+Adata = fcbeba2d0d73239d05f691a52b08152c9dd871f8dc76c2c18b8a638a74460d31
+Payload = 2e0ca09221
+CT = 4e7b15c8be3e41a50a28ea3be14baadf12964a37c4
+
+Count = 59
+Adata = dcdefce64ae4339f46c0759a4a10b29d59daaaf1e5dbf75cf11b4e4f73c5025f
+Payload = 2e108ce0fa
+CT = 4e6739ba65bee2ab25bfafa76dc3e54832b2f76864
+
+[Plen = 6]
+
+Key = 748ad503388a34041a7bdae6361d57894357c333bacf02ca
+Nonce = 518b79d194579b19f2d8845b70
+
+Count = 60
+Adata = 691dd98f61fd213b0840ec5a6f06ef9a1420be0d59bde5e43546347a2a865a94
+Payload = 24d6880aed7e
+CT = 270120f9634ec15536e21d961c675070ec4cff9037bc
+
+Count = 61
+Adata = d1fd047cdb18463766841abb1fcd25257f1458b595bfcf24066ff9385232fa97
+Payload = 2298028d0213
+CT = 214faa7e8c239b303af0b098f902dc24e66fe56adc6e
+
+Count = 62
+Adata = 65a480d120a0459dab69e8f23094801e10092666cc56f9fb2549662982bda6d0
+Payload = f248e5225e3d
+CT = f19f4dd1d00d1b657925a9740d6828bd85cd12205764
+
+Count = 63
+Adata = b738a53fbc9689dd49f68f97f5a99665258cd52e74dc653b594cffec045508aa
+Payload = 611dade00cec
+CT = 62ca051382dc395a1c49129ef6cce0ad5f6ef378aa1c
+
+Count = 64
+Adata = 7006f54184f0ff0ab215ca408d46325b86c1cbae6da7838435b1826ff81f55dd
+Payload = 5871a8300471
+CT = 5ba600c38a415e68468d1b2b516be3d688567d84ab80
+
+Count = 65
+Adata = 9e6e6675d4c6b1e0f3894aac071f4c99a364708edea12f319cbc27b40fabc0f1
+Payload = 3ca8a7520e94
+CT = 3f7f0fa180a40ba1af163049d16817021665d183bc9e
+
+Count = 66
+Adata = 10ceef716f54b74d7c8a435d6aa38a10ff23939ca29e2de7b6c3e0a8269a23c9
+Payload = 9c2a0070fbba
+CT = 9ffda883758a670f35869da9821b6ff1fab3e6062ad4
+
+Count = 67
+Adata = 3ee0865f29be50160273b4a94ec078932b9cd10a858e31838d5b607867e1ce69
+Payload = 436179c74fd2
+CT = 40b6d134c1e208f395250fd79087c858b83755411114
+
+Count = 68
+Adata = ec2b8bfe1ccd491b02aa4a9178fd6f099556963e39e2ca5fe6ecb6b5d2a46085
+Payload = ecfa41c614c5
+CT = ef2de9359af5afcbd9af2d584a0f638d066f2496d9be
+
+Count = 69
+Adata = 5b6f6369643d83b1db33d75257d7dea761e574e6e1f1ecead64e5e354a2f4235
+Payload = b48c10105dbc
+CT = b75bb8e3d38c17861882b8930296fd51d969a1e9489e
+
+[Plen = 7]
+
+Key = b930cca30a3fd230c237c8f3cc6792d0c4084dff5c18d775
+Nonce = 7574802fd82fe96c05431acd40
+
+Count = 70
+Adata = 1cf83928b6a9e525fe578c5c0f40c322be71b3092239bff954dd6883738d6d71
+Payload = 2a755e362373ef
+CT = f06238b0450fd1f4b6cab1383adb420c4724aa7bdfefb7
+
+Count = 71
+Adata = bb5450f66273f63b2f79dce177381ce846584ce4f7a0ad5a0171a56e149370bb
+Payload = fab43224bf8989
+CT = 20a354a2d9f5b7a1f99175d3dff5a73f0053a95c36fd8d
+
+Count = 72
+Adata = 3e5e1037bd2922eb20c34200c470b76e537baf7e7f1d8dd2f7a184a593c66554
+Payload = e3aed6715aa429
+CT = 39b9b0f73cd81734b4ad0e41117940abf530093dac648e
+
+Count = 73
+Adata = 3cc88a096a1a440827f5b7da675389e50b5cce35fa2cc36674d6bfc5a3a966b2
+Payload = e78db0f83997cb
+CT = 3d9ad67e5febf5663a8324014550430c7eaeffbd8568f7
+
+Count = 74
+Adata = 2cca33a10b9da7ba99a6b552d1405f2df3fdfd15358d8fdab5e15296b38f9135
+Payload = 726557906845b1
+CT = a87231160e398f34ab635c4eb5b38b86e71da8af3840ae
+
+Count = 75
+Adata = 2fe5dd58b17914187e29029c53cfe5b015ca74cab750d8f95e05f818c3cdf947
+Payload = 043a759b578be4
+CT = de2d131d31f7dabd9961766e03eaa7e8888227c98d1f42
+
+Count = 76
+Adata = 8b8e3d7c88fa16d70130cee290b7e2eecf0ce711118cd9265093b11467e63554
+Payload = f31f2fb4b3fd80
+CT = 29084932d581be637842d96d13c4aab97e296458745a9d
+
+Count = 77
+Adata = 6341370e126097f9721a13c977eb4875cf1286e15c3adfa4e7597e0e13d93b6a
+Payload = 7e3c8224104669
+CT = a42be4a2763a57a51ac46611366c666cab6bfd3d1baaa5
+
+Count = 78
+Adata = 227926b62f7cdd90e4d3b0cb5457e71fb087d329671f0fa891ec06eb8edeb58a
+Payload = 26a0528ae6f9c1
+CT = fcb7340c8085ff8c7d7e5aec14845f844ad38544a2f11d
+
+Count = 79
+Adata = 05b50c40b02e79b74b94d726a7ce8b2b7216ef8af6e7a42d041d2a692a58ad83
+Payload = 61dcf53d1a184e
+CT = bbcb93bb7c6470f1605ab8a2332012b759ccd2eedbed24
+
+[Plen = 8]
+
+Key = 314c136999e41d137bd7ba17201a9fa406025868334e39b3
+Nonce = 65f7a0f4c0f5bba9d26f7e0ddb
+
+Count = 80
+Adata = 5c7ce4819b30b975ae6ce58dcc1bfa29a8b6dda8f4b76c7e23516487745e829c
+Payload = 4d54d8b06b204445
+CT = 2baf90c490b11f9607482362ab3f157c42d0e9c6c5cffcf0
+
+Count = 81
+Adata = 90257ed88679197b8219bc4c2434a71a4e3664d5859c4ffb9a075654898ffedf
+Payload = b2a35df881cd63a2
+CT = d458158c7a5c38715389509b5b6f2df1faf7e8c39203970f
+
+Count = 82
+Adata = dff8ad83525d8235eacdccc91abeb80795e6b5f463fd28af35c46199f646ceb8
+Payload = e98f5e5a20d02c80
+CT = 8f74162edb41775395328747ca544e987df28883d0377b35
+
+Count = 83
+Adata = cde159c5343cd9d98001cd719d3e9ea25e47e1ff13fc87055d4a53b741f59285
+Payload = 90c3e48313cd4fe4
+CT = f638acf7e85c1437a4ba841883a0d7aeda398c043161966f
+
+Count = 84
+Adata = fa88cf5a08be4fb0c1a7960f45726c303eb559861fa60d17aa8dfe8bb5795382
+Payload = 8ad6d5a28ec075e6
+CT = ec2d9dd675512e3509195efe66c5faf413e0f68df8cb647d
+
+Count = 85
+Adata = fe9e93a9370b43efa1560aeb017ff04fca7f207191e6f707c1c35b2e90c44eb2
+Payload = eb83928f0d5f7aa3
+CT = 8d78dafbf6ce2170b51af067ad69ad96009e50ead3d03f02
+
+Count = 86
+Adata = 35792c854fdf1c8cf7f3f8ed2b8ec4f31fe17bf8d4ba49caec03f954bd8bb17a
+Payload = 4cd74ed2fd083011
+CT = 2a2c06a606996bc26b1cb03ee76587f84364825f7c1fcbe9
+
+Count = 87
+Adata = c084108f9c0a74cbf70f614dceae592546865006930db0401828a0eecff98671
+Payload = 52365f94579e0646
+CT = 34cd17e0ac0f5d958fa70c5e195f1f955d64892f532b7683
+
+Count = 88
+Adata = e8045949de61c5c18a63e628330a4d1d12782379a8f9187755409d1825f453c5
+Payload = 8fb85c857a3e38e7
+CT = e94314f181af63342ddf297bdad58083645a052815d29a83
+
+Count = 89
+Adata = 53cfdfd66d63c2924bd583487b90b1dd9ec199f90d660cb9c3a763a4776abfe1
+Payload = 43d2828e86f7856b
+CT = 2529cafa7d66deb81ad3b2be41dbc39df4c0145dcbae3e76
+
+[Plen = 9]
+
+Key = a19f6be062ec0aaf33046bd52734f3336c85d8368bef86ab
+Nonce = 7f2d07f8169c5672b4df7f6cac
+
+Count = 90
+Adata = d68d5f763db6111c5d6324d694cb0236beab877daae8115ecb75d60530777b58
+Payload = 13511ae5ff6c6860a1
+CT = b3859b757802ebd048467fd8e139eb9ee8fcdca45ed87dc1c8
+
+Count = 91
+Adata = f6e219b29884dab9ea9bad34d9ef8a50ae389c9a908de7154a1f2e894f27141f
+Payload = 7e7e33e1a07d4e8fde
+CT = deaab2712713cd3f3789d0ee8323ea2ee7a68aaaa9c49b98df
+
+Count = 92
+Adata = bcca002d69d9d1044c40ae741ea33ce6b8463f5a28d0514e044fdae2fe7d3c3b
+Payload = cc88980c73e6c5f0cd
+CT = 6c5c199cf48846402437c9fe3d9feb0485e6d7c04423b77a53
+
+Count = 93
+Adata = 39cac8f0825ffdb0668455933ad1581263a23b9e5f1305340528f0320d4b1269
+Payload = 34cb528f50d073cfdc
+CT = 941fd31fd7bef07f35b87e90a71ffe6c30bee1771078a701ab
+
+Count = 94
+Adata = 510a02a44d142c8e975d1d933f828fd7e47d28b88223f1698cf009dc3b079be6
+Payload = cbce3df86438a61065
+CT = 6b1abc68e35625a08c9e9c5be0657649448c38692e8d703d30
+
+Count = 95
+Adata = 40e0418cd52f74d78a8e18ed86210e3661a86d8574aedcee540340d8996d9852
+Payload = 80a2b835f8b0729a4b
+CT = 207639a57fdef12aa213e5f2bfd33101597cfae7cf334a8528
+
+Count = 96
+Adata = 1f2938b3bde19e1af91299c08638061dc3c1ea3284c259d415e996477cb37b0e
+Payload = dd04794e65ce34127a
+CT = 7dd0f8dee2a0b7a293516a7310fbd4ceb90d8db9a86cb6311b
+
+Count = 97
+Adata = cbae5b46e35fa2a279dcaa4c724b923805d4707412a84252b64228c91cedd019
+Payload = 00c4101052f54462d5
+CT = a0109180d59bc7d23cef6165af65f3522dfbfed0293db39ecd
+
+Count = 98
+Adata = d0f27c7f42892f3ad4c0029c5b698abb1d035ba5869a665b1de8861db6c055e8
+Payload = d0865445d3b26b6f49
+CT = 7052d5d554dce8dfa00726434c1349e3e874a2d6bf598d05fc
+
+Count = 99
+Adata = ab0f5a829a9319a74d5d5179aa0a410a0fcf52f344a7a896aeb1f7a6c5d398ea
+Payload = 7c7c8580b944ed3fd3
+CT = dca804103e2a6e8f3aab491e60fc97b3cb5248291e4866dcab
+
+[Plen = 10]
+
+Key = de1c8263345081d2dfa9afdf37675971135e178df554a4d8
+Nonce = a301bb82f91a582db01355c388
+
+Count = 100
+Adata = 9ad52c041390d0d4aaf65a4667c3239c95e7eae6178acc23fb4e70a852d483c6
+Payload = f777aba1fa70f94e6de9
+CT = 9d8bff6d2dcde77104ac6aba025abc01416a7ca9f096ab2529cb
+
+Count = 101
+Adata = b49c7e7b47870c1cc339c7c09aaacfd6115fa8a0f04990367eea10cfacb9d23c
+Payload = 349feebfbe58f93ea3c3
+CT = 5e63ba7369e5e701ca864acb200e85a0d4753a8ba226aca72f98
+
+Count = 102
+Adata = e61ca7310172eec16745a73e34516f65844eecd0dbc5566ac5213626b9096ef1
+Payload = 678a40b4c2c7df0e4c9d
+CT = 0d761478157ac13125d87869784e3321183d8c044657a020e9b9
+
+Count = 103
+Adata = 690f5e5d8da6cdb0f492e80449e152ffe88fea9742564d8383c79cef739a7f74
+Payload = 2b81e0533313664bf615
+CT = 417db49fe4ae78749f5070634d00b1facf0e9e9979ca257a71e2
+
+Count = 104
+Adata = 78e34b0a1d61ccd411cbfd306ea2ef3ce89c0b085deb4cfbaec2ab72ce16daa9
+Payload = 1ac63aa38a206d8e7d68
+CT = 703a6e6f5d9d73b1142d994630ed92e2973b22773f229b45bdad
+
+Count = 105
+Adata = 51bacfcf87ea11da34b76acba8c444792ec3db3c8ee6e600d69679975a682a54
+Payload = 027a7fd7897808ec7a56
+CT = 68862b1b5ec516d3131304571b015bb6b4651f1eb9f6fb3a7b74
+
+Count = 106
+Adata = 5159357a133e4743f903d05bd641da369a3675337760fcd2424a99221ba70b78
+Payload = 1086953d352e94a51a6d
+CT = 7a7ac1f1e2938a9a7328bb0e11ac4608081fd0702a137da0aea3
+
+Count = 107
+Adata = f567820865340314d46a17f520ff315efb6b33bdeda590ca9c4fad604c2d8e8d
+Payload = b8b148aafec4a035e9a7
+CT = d24d1c662979be0a80e252c9ec1317ce30dffeb4c9bf3fd0bbdd
+
+Count = 108
+Adata = 0cfec933831644b468724e808bb3d25fe8f15850ce513fc341da46089c845208
+Payload = 884242a87779d3921f8e
+CT = e2be1664a0c4cdad76cb691e32be3cdd9721a13aabad26dba58c
+
+Count = 109
+Adata = 8edc2b85d44297ac66bdd90d05d8df38124033d6a583bb8dda18a2246ba096e8
+Payload = 25c32770a299020d8500
+CT = 4f3f73bc75241c32ec45333a381be77800654aac335bf9220ac9
+
+[Plen = 11]
+
+Key = 248d36bd15f58e47fcf1c948272355821f8492e6e69f3661
+Nonce = 9e8d492c304cf6ad59102bca0e
+
+Count = 110
+Adata = 9ec08c7ed6b70823d819e9ab019e9929249f966fdb2069311a0ddc680ac468f5
+Payload = 33709d9c7906e2f82dd9e2
+CT = 9114d36b79b1918b2720f40cddce66df9b4802f737bea4bd8f5378
+
+Count = 111
+Adata = ba13974d95f2eeb367b63850609c53dc66c2710f682f10bef0142d48f851b430
+Payload = 84172985e7d194ba28a87c
+CT = 26736772e766e7c922516a12c94615be2bd81bd598f3022f5775a4
+
+Count = 112
+Adata = 5f16180bfac9b7483774cb0e1d57a43e9bf3cf03bf6fe758293aadcbbef25b80
+Payload = 9a34d32070c71d7de8f512
+CT = 38509dd770706e0ee20c042758e936750e335702542bc598e211c4
+
+Count = 113
+Adata = 4352057bdd1735a85dc0fc4dbeedc73279c27eb24a97641236f03f11cdafb8c0
+Payload = 2054a268b1f6fae4f15d91
+CT = 8230ec9fb1418997fba4870762bb2a7d04ba2ad251d595d0619dc4
+
+Count = 114
+Adata = ddf118ae403b2509e75eb7a26d17e73e527acbacfbe49a56fa3210169030144b
+Payload = f71afe9a60f08a0ef694aa
+CT = 557eb06d6047f97dfc6dbc27d85594da3fd35bd8498d7e389ee7cd
+
+Count = 115
+Adata = 973904409e8154132439926f0dc45c0d81bbbd5793f7f81e20eb818bfa374d58
+Payload = cdf5b47ff73306aa55c496
+CT = 6f91fa88f78475d95f3d80055936db383a8ad10b152046d721d3f7
+
+Count = 116
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f3
+CT = 3cdbdd9338e3992f9d5de5d57e228369e24fe955fd8924526af6e5
+
+Count = 117
+Adata = 8321f65baf9dc856ac1c24f3fee5c74d697eb0b50470d59d8f4a14b506e86c53
+Payload = 685116faa5cc527ac8bfa1
+CT = ca35580da57b2109c246b76c23abfb3b4eb39deb8da2064390dfa8
+
+Count = 118
+Adata = a4e7738038a5116592bb9d92d6d4ed191ab774310f6409e4e45fe907674c006f
+Payload = 9e8c4f1292e8d7e5179b34
+CT = 3ce801e5925fa4961d6222b4272c0639e8e6a1d356fb4fea86762c
+
+Count = 119
+Adata = 0df202431ee7f251a38aaf6aa8cd313782bd293af9114005adfe9faab253b572
+Payload = 3ecc2ba566c723462eb0ea
+CT = 9ca86552667050352449fc0633a0f9cdc9490231ec2dd69f6e35db
+
+[Plen = 12]
+
+Key = 77a67fb504b961028633321111aac2c30eb6d71a8cf72056
+Nonce = acadc0330194906f8c75ac287f
+
+Count = 120
+Adata = 8c18486d52571f70f2ba6a747aaa3d4b3ebc2e481ee1b70907dddb94bdfa0ca6
+Payload = 10554c062d269ff6dcd98493
+CT = 7f8b0cad79b545e5addf0b04ff4b0f2b2a5067283210aba8630d0306
+
+Count = 121
+Adata = 4e0b4771c7f6c66f9577c430611fdeec5702296ee3691b6bb8c6a81217edabe4
+Payload = 1c9e7875cf02129ac52daeb0
+CT = 734038de9b91c889b42b21275b16dbdf0b9be3c8c82ac652992d630d
+
+Count = 122
+Adata = 4a687e1d0a95ed2efb95b4c6b040999fcd35136811cd665f934d10224b6064c2
+Payload = 34575694dde459d195b7357a
+CT = 5b89163f897783c2e4b1baede629274d654ef5a4480e24f6bef3bc8c
+
+Count = 123
+Adata = b5330a8447d74a7987fb718cfae246b5c7e057991064eeaf823641a12bfce9f5
+Payload = ab20c8e8aab1aac1e4f64206
+CT = c4fe8843fe2270d295f0cd9142ab5407a08b648ce24e9955e28fe47e
+
+Count = 124
+Adata = 4f19bbc3135d7a216465b4c1df2616e8bfc3cc64af0bf52bdc42543f4d2448d4
+Payload = e556ca05bcd1991d2c9836a9
+CT = 8a888aaee842430e5d9eb93e151e94d311c7cd2c1b9048575076ceac
+
+Count = 125
+Adata = b6ffc7387b19786282bda7caad52eb37fbe7e557afcb80faaf57767e2a0f178a
+Payload = e5b665600a2aa413e117c538
+CT = 8a6825cb5eb97e0090114aaf61b71330d72506050368186a5619f180
+
+Count = 126
+Adata = 6a493c5ef3769ccc4101dbb2eb36e1e5bbc577a057ce0731203ba3f25b52497b
+Payload = 870864a611aa0475d120bc40
+CT = e8d6240d4539de66a02633d7ea21e36f99e5aab6ffa85994d13d5bb0
+
+Count = 127
+Adata = 8215753d9efc51325f182199e39f9082cc3fe524400f2a7434c68df7eb2b06d4
+Payload = 71afe8d00c6f2ea8c8b050d4
+CT = 1e71a87b58fcf4bbb9b6df437cc93a50dea11c5e0b19f14b9c8f16bd
+
+Count = 128
+Adata = eb8f198da6ee92a03913c6575343f6c749d2377a09430eb751b13c041e6edbea
+Payload = 7021f18b8f398a5999fcdcd1
+CT = 1fffb120dbaa504ae8fa534699cbfd1beafa2d2942f6812b8dfc88e6
+
+Count = 129
+Adata = de2ee30359e390db72f682c2ca0f14b72b60ff9bccd8c6fbd19a512b12add794
+Payload = affca856eb412f0b3276ae6e
+CT = c022e8fdbfd2f518437021f9337405235dce6161441caa25cc6007c6
+
+[Plen = 13]
+
+Key = 0d423519e4110c06063061323f8c7c95387776b6ee4e4b6e
+Nonce = 39abe53826d9b8e300fe747533
+
+Count = 130
+Adata = cdd9bf1b4f865e922c678ec4947ea0cb02e78bd5c1538f33aeb818ad3f47e519
+Payload = 4021ff104ff1dbd91e46db249f
+CT = 7953d3cd66d093785d123f65ba37f16761dd6aedbfc789ad96edf1490d
+
+Count = 131
+Adata = 342de5fe61e05c2e58ac2978a871fbdf186a7294ec5f85c4631c21b584231211
+Payload = 95050ca1d494bdb561d4840f8a
+CT = ac77207cfdb5f5142280604eaf8f8e855ae975a1fc64bcce3e7492e9d6
+
+Count = 132
+Adata = 7871482948d8d09d0a7491d915543082cb5fc7d6c1e82ee2218279f54c15c154
+Payload = c45823203b20821a48502f9c67
+CT = fd2a0ffd1201cabb0b04cbdd42017a6515156691b3161b747576078da4
+
+Count = 133
+Adata = 65781d018f27ca0c72a9fa9ab4648ed369646dd3ce45d7ad3a54f6b051f1b6e9
+Payload = e901661b7d47c9918244ee1077
+CT = d0734ac654668130c1100a515225cec7d2566a07cd78181ae94577befe
+
+Count = 134
+Adata = 05556b04dae5cde8525633d1862aa200c54af534e302d2cbd34ddc2b78532a60
+Payload = 5556f799d6a6cffb343f28c1a9
+CT = 6c24db44ff87875a776bcc808c133f51dac00f973fd42e0948fab70ea9
+
+Count = 135
+Adata = 151304e3e4f3c2d4d3227e035d849e0d3841ba00cf6cab1cf2e3e4d6cc760623
+Payload = 56bf26be81c7b55ef898e23981
+CT = 6fcd0a63a8e6fdffbbcc0678a4fe78bdeaa8d408ffe8fe64811aa87742
+
+Count = 136
+Adata = f870cc1fe67d6169279f905b0fe5fd9a0436c36498e4b7c6f584f00f7efe8784
+Payload = 36b304a72dbf4acfffa1d7d624
+CT = 0fc1287a049e026ebcf533970197228d155dda2bc814ff33ebeb9a7ffd
+
+Count = 137
+Adata = 5692c9d452ea1c067e62fdc554ddd2b18c8433d59067f971316797fd9853ae6a
+Payload = fb529eb5ae79a0830474ffbc98
+CT = c220b2688758e82247201bfdbde7ba03e144e34a4ab34791a372a2b8ab
+
+Count = 138
+Adata = dcf7fe16b7ca9e27ec3291103398eaa2e77c7b770b67f8858c215af4c523822d
+Payload = 6218c778955d9a56360f06c704
+CT = 5b6aeba5bc7cd2f7755be2862103c2eb5ef0657306d12b753a0694efcc
+
+Count = 139
+Adata = b0f1e2668611dca86e8d0f58c2a4cf4a9472d81ba013e271800b75841fe5ffde
+Payload = bf6b143fb713a81c965c5a9d8d
+CT = 861938e29e32e0bdd508bedca87cc6119151393461ecf65bfe06e0163b
+
+[Plen = 14]
+
+Key = a60cf7ceb62bf3118532bc61daa25ce946991047f951b536
+Nonce = 7499494faa44a7576f9ed5580d
+
+Count = 140
+Adata = baa482c64eefd09118549a8968f44cfea7a436913a428e30aa4ab44802a4ba35
+Payload = d64f9426febce6a84c954dd5ded5
+CT = f7580f17266d68237747bf57c7ed8242ac1a1979c5a9e7bc67d7698c7efa
+
+Count = 141
+Adata = 2ad8ecc5ac9437ace079419f17e6018625b10490120fbe2f12b41e64b73b653c
+Payload = fcd9b67717bcadeceddea336c671
+CT = ddce2d46cf6d2367d60c51b4df4918abced491c063d8bfd0e7341febddc3
+
+Count = 142
+Adata = 7585ee95e74d7a869bdc0b59ca9939dd57e7b09afab179079d467bfe0668416c
+Payload = 18232d7c792fb80e6ca1c8f2c3cc
+CT = 3934b64da1fe368557733a70daf4659ecbb3dbfbcdb0f913abedf8afab05
+
+Count = 143
+Adata = 41be6ca6188f34da1ce83fb8c27652848dc2a71e32bd3631fb9b33ae69e5d879
+Payload = 764dbefb42644d18d23e5e456868
+CT = 575a25ca9ab5c393e9ecacc77150a220d5ec0b5397d6b4e323b5dc7d1b63
+
+Count = 144
+Adata = 197cee3b15320d57996191dd13106fbd4546a5cc3d2bcf0c886af52ea3d9a855
+Payload = 8003586af34bdd0acae4f5547394
+CT = a114c35b2b9a5381f13607d66aac3a5f713f5d0793b732c6e114805cc9b3
+
+Count = 145
+Adata = ee0b647a47656a6e9e09c2d64f734a2cc3fd45b7ee52fea51c24af59ee22a006
+Payload = da143266516a4145cde92c93f961
+CT = fb03a95789bbcfcef63bde11e059ed90e8650bc16f590789dcc625b9e63d
+
+Count = 146
+Adata = 9f5bfffa01f1425d95465723735b49fc1dffbad06cf37a00ca4b59efa21739c1
+Payload = 3842b033f3ca31a6f8e5a638b39e
+CT = 19552b022b1bbf2dc33754baaaa6bda183dda1aef021d92210e27cdd7c5e
+
+Count = 147
+Adata = 64e92ba2748d07f602808f7c5ded15cb0e43140400d37107e59a01e7d45b4c9c
+Payload = cedf60b17185fc71b957cb759260
+CT = efc8fb80a95472fa828539f78b585e4087fb314f893937e95383e66745c0
+
+Count = 148
+Adata = 6ebcaeb4bd44ff4c990305ac64264dfe2ada5f7cd4b294eb9f492865cd28905c
+Payload = 035f449bb28f43365f4a0556096a
+CT = 2248dfaa6a5ecdbd6498f7d410520a71ce5813c578532b742d704fa92276
+
+Count = 149
+Adata = db617207dccd1f6baea5f2242d5e577adb8d69af3bb1707a7a53a8b75452455c
+Payload = 9a2a45424f4965a71270e77cc403
+CT = bb3dde739798eb2c29a215fedd3bb7fc45d15d6939668065d2282fc589c7
+
+[Plen = 15]
+
+Key = 82d4bc9aac298b09112073277205e1bf42176d1e6339b76c
+Nonce = 70325ef19e581b743095cd5eb1
+
+Count = 150
+Adata = 6d14bb2635c5d0ae83687f1824279cf141173527e1b32d1baf8a27f7fe34a542
+Payload = 25a53fd3e476dc0860eeeea25fcb0c
+CT = 4a1cfd0023557a184b929965b0a445cb3993ca35acf354cb2b4254ff672e7f
+
+Count = 151
+Adata = 9f8a56fecf32fa7d50f033b2524c3d798e254bc87245cce57e38edd6ee5d5f1a
+Payload = 797dca47597947c057789433309b67
+CT = 16c408949e5ae1d07c04e3f4dff42ea25b5eb103bac224cad66ec0f100875c
+
+Count = 152
+Adata = 86f15b8b677b7655f358a2c7fd5785bc84d31e079ed859b6af88e198debd36fc
+Payload = e61f9a663d3a2b50ea2f9475971270
+CT = 89a658b5fa198d40c153e3b2787d39b598cc6ec2295c586e7ae270a01846d1
+
+Count = 153
+Adata = 4de6bd43c28143ea5d40919cb5330a7e674f5bd8aeb7b178343a2851281c8668
+Payload = df990c42a268950677c433555319b3
+CT = b020ce91654b33165cb84492bc76fa97ff732093f7d0a96b30d8cdfd1bd583
+
+Count = 154
+Adata = a5c3a480dea1b2a1e3a0ce416148b04f60104217c9d24a5b267b4aa6aa07a4dd
+Payload = a7e72fb4bec3768594a2f6f5b4379e
+CT = c85eed6779e0d095bfde81325b58d7ad98e32a9156e125ff021ef6951b0c40
+
+Count = 155
+Adata = 51b041f1666c59045d333fe63d43457107e1adad34fcbf965e0d191f3e414776
+Payload = d3d1550047cf90eceaea7000d8e280
+CT = bc6897d380ec36fcc19607c7378dc9390f10df08a84c21031626861b201fbd
+
+Count = 156
+Adata = 22f8a3c9d85b2d53ffd92078d3c94373f855ecd01a8ac521d1abd0f2c7cba9ff
+Payload = 756412c4ee6416f2f4e0342011cde2
+CT = 1addd0172947b0e2df9c43e7fea2abdd5d840bb8c4348a9a548482e6b93043
+
+Count = 157
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 666e4a4b3f6cf598aa763cdada4109
+CT = 09d78898f84f5388810a4b1d352e403f0d49927cd6103e3705ba201e8f73c6
+
+Count = 158
+Adata = 2db3ded385ef9c82fd39ea5782d9befe66e8a070066269b2aa7c4bbfac3711c3
+Payload = eb9013a74352b0677a88bd73052477
+CT = 8429d1748471167751f4cab4ea4b3e2d97f7c2b3b42bf570cce79bf30ccc50
+
+Count = 159
+Adata = 194c9e1eaa8e376f9c41bf33823efa28ee60a9213438665b7002cf0fcad7e644
+Payload = e3126400e3c571a4d39b37bc938a22
+CT = 8caba6d324e6d7b4f8e7407b7ce56bd3c2a4fc45d014a0c54edab2930a5bdc
+
+[Plen = 16]
+
+Key = 6873f1c6c30975aff6f08470264321130a6e5984ade324e9
+Nonce = 7c4d2f7cec04361f187f0726d5
+
+Count = 160
+Adata = 77743b5d83a00d2c8d5f7e10781531b496e09f3bc9295d7ae9799e64668ef8c5
+Payload = 5051a0b0b6766cd6ea29a672769d40fe
+CT = 0ce5ac8d6b256fb7580bf6acc76426af40bce58fd4cd6548df90a0337c842004
+
+Count = 161
+Adata = e883dd42e9ddf7bc64f460ba019c28597587d06e57c3b7242f84d5e7d124ab81
+Payload = b31dfa833b0cda20eaa84d2ecd18f49a
+CT = efa9f6bee65fd941588a1df07ce192cb8707b1a4d9ce3def33703e19eaab6dda
+
+Count = 162
+Adata = 409401eb49cd96b1aad2525c5124c509766ff86f88b2011c67a1d501d3485e31
+Payload = 24bc8dc1e2354667b79ba4d7061448ff
+CT = 780881fc3f66450605b9f409b7ed2eaefd9041ddce37d88e79fba28e385b2327
+
+Count = 163
+Adata = 83bf5c063bf1febf71688a832d615e09d6f14badedeaeb6ffbfe343fc7274e78
+Payload = d41d95a1d2326e12cba636910ddfca53
+CT = 88a9999c0f616d737984664fbc26ac0291d971893543868bd8c69078fc2bdb24
+
+Count = 164
+Adata = 8cdd70524e24318c64d681aa27752d4c86c5348c05c9e48f06ed41594785a6e6
+Payload = e8a4b80e081919f1912542d3136764f2
+CT = b410b433d54a1a902307120da29e02a3866b23e4c991f4007e56a1ee9265c6cf
+
+Count = 165
+Adata = 615985f63571c0f94ffcd4df77326abd41e84f388f061d97573a181da7ee5695
+Payload = 7fca7388058d6d1438b6eee0292131cb
+CT = 237e7fb5d8de6e758a94be3e98d8579a2abbea637996b954027efa9464ced6b9
+
+Count = 166
+Adata = 17aa90f2bff0419011b01dee62be31354431cbc89f22332704b096143d4743f4
+Payload = aa540554ee80dbffa475f702d862d6b6
+CT = f6e0096933d3d89e1657a7dc699bb0e757bc8d48d82ebefc76f17323c518ecc2
+
+Count = 167
+Adata = 85288b2be612e42335c144fb058a7dcd567c382fbcee3962bd5be4cc7a7000a8
+Payload = 6d745581831edba437e70ea89cad217d
+CT = 31c059bc5e4dd8c585c55e762d54472c65470c81e487a26cdc26830f2b51bd1c
+
+Count = 168
+Adata = 288f9f52824b54b608dd7226a0a89d43ae8c05107dbae761e1c756911a003b74
+Payload = 811a61869c7a6b2aa9ac0fcc523ef784
+CT = ddae6dbb4129684b1b8e5f12e3c791d5a3043722be9448c3ef144f2288066f75
+
+Count = 169
+Adata = 51dbaba180d4746edbb3420461919b5b735797bf7dd19f84d80475f5efc2748d
+Payload = 378a4e39817f308ed1e639f943b694c4
+CT = 6b3e42045c2c33ef63c46927f24ff29549aba95e04e11cf18ddf73773d395c1a
+
+[Plen = 17]
+
+Key = 3cf8da27d5be1af024158985f725fd7a6242cbe0041f2c17
+Nonce = 07f77f114d7264a122a7e9db4f
+
+Count = 170
+Adata = 30457e99616f0247f1339b101974ea231904d0ef7bd0d5ee9b57c6c16761a282
+Payload = f6dd2c64bf597e63263ccae1c54e0805fe
+CT = ce3031c3a70600e9340b2ddfe56aa72cffdc5e53e68c51ee55b276eb3f85d2cf63
+
+Count = 171
+Adata = 42370f115bbd4b31bb99fe82cca273b3c93072f96b2e09bdc6718d926d48db69
+Payload = f45fee3e086c28a7c590ec0cc05b972664
+CT = ccb2f3991033562dd7a70b32e07f380f65c6328a7476db2c10ec7bca3f6bd3df42
+
+Count = 172
+Adata = e2d692c5678124998a7862b8e87276b0a19e293a609103c99583b36305bcb2b0
+Payload = 4ad69a8ab433ed8909825c71f6081f64a7
+CT = 723b872dac6c93031bb5bb4fd62cb04da68080f0d51d3b8841683eff361984f7e4
+
+Count = 173
+Adata = b5b38791160959dd2836ec1ad25286c1ba410d7212347a95b5738a3d725bb651
+Payload = 3d47071c13f994cb42fb2887e5c6e53a54
+CT = 05aa1abb0ba6ea4150cccfb9c5e24a1355c1428ef5d40bc9e363817f219af2ed56
+
+Count = 174
+Adata = 02691171795a77d1e3bdad513b6fab5b50d1def81bcc1df15012de3433a6aa78
+Payload = e8a4b80e081919f1912542d3136764f264
+CT = d049a5a91046677b8312a5ed3343cbdb65fdfb37dfd1236198035c8461b304152b
+
+Count = 175
+Adata = 7371d8ae79e628f53ffede174eb068db2318c05e2f6d94ad2233a59369b16db0
+Payload = 549aa84bb182312dd016e3107f3b1f9c5b
+CT = 6c77b5eca9dd4fa7c221042e5f1fb0b55acefde0e84a3ce0cb702ceb73ca1dd9a5
+
+Count = 176
+Adata = bb1e1f51082e470f7245458ec902098e1e41d0ed28efa31be71d21ce86527ff7
+Payload = 31a12ca6d69db2e6e252474d7d59ed6552
+CT = 094c3101cec2cc6cf065a0735d7d424c53f8441d46dc5456a587b765e1a820c11c
+
+Count = 177
+Adata = 7584f57b49e95bbf5a67153e18b9b8c4722644e8f611613c39cbe8c679aba5b4
+Payload = 5bb121e70452a954f420a56aca8cd5c059
+CT = 635c3c401c0dd7dee6174254eaa87ae958d0daddcfcc92349ef059149c54a25cd0
+
+Count = 178
+Adata = 505687182c06e6f4effe7fe03c1f436199a9015380ff21d0b2aa9453cfa10b1d
+Payload = 5b80d1cf745b14cb71cbc8dfe0bc7c7358
+CT = 636dcc686c046a4163fc2fe1c098d35a5948c1242b89490c6ee69dedc1e91286ee
+
+Count = 179
+Adata = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee451bd1429cbb33fc1
+Payload = 79ac204a26b9fee1132370c20f8c5bcada
+CT = 41413ded3ee6806b011497fc2fa8f4e3dba2ddd54e509bca0a45dcf2fd514e1496
+
+[Plen = 18]
+
+Key = b46a3a24c66eb846ca6413c001153dc6998970c12e7acd5a
+Nonce = b79c33c96a0a90030694163e2a
+
+Count = 180
+Adata = ea9405d6a46cac9783a7b48ac2e25cc9a3a519c4658b2a8770a37240d41587fb
+Payload = 56d18d3e2e496440d0a5c9e1bcb464faf5bc
+CT = 01baba2e0d5b49d600d03a7ed84ee878926c0ca478f40a6fbde01f584d938a1c91bf
+
+Count = 181
+Adata = 72340d595f3dbd23b46513f8f2b73b6249328c705e7968084bcb647fe734a967
+Payload = 7a76eac44486afdb112fc4aab939e4d1eedb
+CT = 2d1dddd46794824dc15a3735ddc36853890be4646492b6f4cb169383c075756073b6
+
+Count = 182
+Adata = d5c87c649579da3f632ba95cb0a07c924095e4bdd4e0376e06bb90e07460172e
+Payload = 48348c5ec996f7a97ef0ba2cd6885572fe64
+CT = 1f5fbb4eea84da3fae8549b3b272d9f099b4f584289f560cbf76606942fe1a92dd63
+
+Count = 183
+Adata = ffa6277395d31d5db13034d362228a87610e441c98ca3038e252a9db12bdbcef
+Payload = d5c58f10e1a03d8a2501d1eaf5fcdfff3ae5
+CT = 82aeb800c2b2101cf57422759106537d5d355964f5f5532d7cddd7207f0e9a6aace9
+
+Count = 184
+Adata = daf83d02a9bd992ea58c23e7ad18d41796314bae20e864e729f40ccc215454fc
+Payload = da2a863ab1c58ddde320ecadeecac9c5d2d8
+CT = 8d41b12a92d7a04b33551f328a304547b50890ae047e35aecfc38ffdc07e7d8f5705
+
+Count = 185
+Adata = 21ddad5f550044dc5cb123ade17eeef549c4e0173b216bcc602c1e736764cca8
+Payload = 4573969afa831c244817230406fe51183091
+CT = 1218a18ad99131b29862d09b6204dd9a5741b2bdf539ceaa35015712dd15265ca476
+
+Count = 186
+Adata = 9228265ae5c3daf1485ff8011738da508bf2a73731396c5d9aa56fc554e0c00b
+Payload = edf5557e15473b747a819398c9ac1459ffdb
+CT = ba9e626e365516e2aaf46007ad5698db980b241412124ae20b84c13b0c3671d305c9
+
+Count = 187
+Adata = c0a2ff0de21b3ba961e06015ccd71374856a65a4c57cf8cde0a1643aca8ed868
+Payload = e139263478900df806a0f3446bd6600c1aeb
+CT = b65211245b82206ed6d500db0f2cec8e7d3bee9803747bf9fa63412bfc4e10aea89e
+
+Count = 188
+Adata = b54378f031a31cf3985f573829c9ffca14616742e0a7e03b0a2d7f05eff0219e
+Payload = 660eaff0f113eaa2f5f7ad4b62bb849a3a25
+CT = 316598e0d201c73425825ed4064108185df55afdf430b57845dcf622d4f25cdeb2a3
+
+Count = 189
+Adata = e67f35c18a9336469eae23040f98f52338ca8d0cab269ac32fe6bc7605d3ea56
+Payload = 0f89897271f5d0349d57399005ea60c0cadc
+CT = 58e2be6252e7fda24d22ca0f6110ec42ad0c7ed4c04c4b4dd585891ecfddeab8cc87
+
+[Plen = 19]
+
+Key = 7b71045ccef735bd0c5bea3cf3b7e16e58d9c62061a204e0
+Nonce = 2b9ecfd179242c295fe6c6fa55
+
+Count = 190
+Adata = b89166f97deb9cc7fdeb63639eeafb145895b307749ec1a293b27115f3aa8232
+Payload = 890d05420d57e3b3d8dbef117fe60c3fa6a095
+CT = f842ff6662684de8785af275fa2d82d587de0687ebe35e883cbd53b82f2a4624c03894
+
+Count = 191
+Adata = 4392c3043287dd096b43b4a37ea7f5dc1d298b0623ccbf4fd650a49569a5b27b
+Payload = 6b425cdcdf8304e7fbb70b2973d55e6940025b
+CT = 1a0da6f8b0bcaabc5b36164df61ed083617cc807d4824f0a98db2d87365a42ca3b80e1
+
+Count = 192
+Adata = 9b4fc98fcdcf485205e7054bc9d1e02d0d8584420537e20d3821de2fd6824787
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2
+CT = b9f0ee7ba0c4018d6d9b513fe92670eaabd221404e631735c544edeeb4c0105c55bf0b
+
+Count = 193
+Adata = 45622e1472542be2f63f463d253617eafd4f2ad609f9020884905dd5c22fba53
+Payload = 12b5a76faedf6f855e328c2cb87be8aea78c5e
+CT = 63fa5d4bc1e0c1defeb391483db0664486f2cdc16a4cf37e8e96eed1217d21133e83d1
+
+Count = 194
+Adata = 958689aea3c6cd19020eff9d635ef44ee0793424df38fdf13a238b969d429777
+Payload = f0927c3cb0a876d7877466507da8bfa0bd9a16
+CT = 81dd8618df97d88c27f57b34f863314a9ce4859facf81a636351f6e67d6ec12636ae0b
+
+Count = 195
+Adata = c22911efc36fa739048af0c951ef2449bb3605c52f65120c4d71fe5976026032
+Payload = d2c5d4e2362f19c99de66da7bd9c495c03d9a1
+CT = a38a2ec65910b7923d6770c33857c7b622a7327ce73a7e2db69d30441f89a03fd0e84e
+
+Count = 196
+Adata = 799da61e2c10ebb4783f618b8f69da7704a1b2b925cebc228af57d7ceebb9825
+Payload = 1c9d7f5b329ef4d384b8b7955a20f8a3fc15cd
+CT = 6dd2857f5da15a882439aaf1dfeb7649dd6b5e8d787a9d06b8533ca96fb1db8aecc8e5
+
+Count = 197
+Adata = 14a8e18afe0b9fe18ddfd754219a7e18ed36f419f8262d91678e10daffb31c81
+Payload = 3a64414c3588d7c26871d7d054ac6c8420d491
+CT = 4b2bbb685ab77999c8f0cab4d167e26e01aa028ff5f819d552c08054b5ac02063e102a
+
+Count = 198
+Adata = 7294a8b4ad97c81969e4a2876a3dc0ee322d554726997dc9ed98c5601985ee5b
+Payload = 545dd71bea9967e07a89f84a2027aacd132187
+CT = 25122d3f85a6c9bbda08e52ea5ec2427325f141cde5af8fada67c47cbb5787a6b2d9c9
+
+Count = 199
+Adata = 99294b22d73805805630fb416d20d4fca67419ab660ff45cd19a3729e81b9f69
+Payload = ec1b17b885c018272652453f47fa6e9ed972b9
+CT = 9d54ed9ceaffb67c86d3585bc231e074f80c2a7412640b179bd3e8a417dc38462c16e8
+
+[Plen = 20]
+
+Key = dc7c67715f2709e150cceff020aaacf88a1e7568191acbcf
+Nonce = da56ea046990c70fa216e5e6c4
+
+Count = 200
+Adata = f799818d91be7bab555a2e39f1f45810a94d07179f94fe1151d95ab963c47611
+Payload = f383bd3e6270876b74abbb5d35e7d4f11d83412c
+CT = 377b5df263c5c74f63603692cbb61ea37b6d686c743f71e15490ca41d245768988719ede
+
+Count = 201
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d27ad5132d507504898f61e
+CT = a5a59286e8ff1d8b9aec209ecc84cd022e76df5ea9bc8cfaf2a1734a792076618c4b9690
+
+Count = 202
+Adata = 4586f73a1f162b2cdb65f6e798a60b5f48938d40b4612d84c1f39244f14efdce
+Payload = 6e923e1f404002aa5cf8f8aaf1b9772da425e21c
+CT = aa6aded341f5428e4b3375650fe8bd7fc2cbcb5cc5122df904b052e4d5580fdeddf5297c
+
+Count = 203
+Adata = 9f7ae892e5662803408d4d062265846441a43c1fa202da59f640ae722a692671
+Payload = 68115771505daa18bb3ce90054bfb7d077e1f37c
+CT = ace9b7bd51e8ea3cacf764cfaaee7d82110fda3ce0ba1bb1af18e15ade3316c21d6b41fb
+
+Count = 204
+Adata = 1f0769a7ae82bd985661e031c4a892c15d3ef37bdcfb45243d02f40fdb51d34b
+Payload = 681fd2a324b3fea4cfebed567ae4546ba373c8f1
+CT = ace7326f2506be80d820609984b59e39c59de1b1dc71e342fbc44289ef7e53e28edf3839
+
+Count = 205
+Adata = bf957ef5ab2805e58ea752da5793f7f23d98fce1b2b67738929e5de8a15f9801
+Payload = a7b9d2d069941e8b943706a02d2847ea713bb103
+CT = 6341321c68215eaf83fc8b6fd3798db817d59843ced1fb4a2a3e349aa590aabbfc3d13bc
+
+Count = 206
+Adata = 833264c1bebb597043b4158087cb651960915d9023189c9509c0d2aed84e7fe4
+Payload = 9b946e8198ce69d2173e970f4e0c103a47ee4160
+CT = 5f6c8e4d997b29f600f51ac0b05dda68210068205079f6c2739e2b789b6e3d3c60389374
+
+Count = 207
+Adata = 94c8414cbbec52e2d73bb8f02ef687c91432495c0c744666317d02e6d46706d2
+Payload = 81ac4618f3db6bcf9bbf67220b7671be4bb4f8a2
+CT = 4554a6d4f26e2beb8c74eaedf527bbec2d5ad1e22a02f287db7217148317d897f65f6a0c
+
+Count = 208
+Adata = fced1131dab3dabdc1a16d3409fa09a90ffe02f0e2c814a63f77f771c08c3389
+Payload = 90851933d4d3257137984cdb9cba2ca737322dac
+CT = 547df9ffd56665552053c11462ebe6f551dc04ec362df9f8b41b1dd4821f8f14e9e633d7
+
+Count = 209
+Adata = 495dfcf91f4735ab35c6bc4deef8468bd988e4099cd291a32b4707f93e13d82b
+Payload = c14ce6d57f0fe7367331c9fe159ae1fb8f1ccb2c
+CT = 05b406197ebaa71264fa4431ebcb2ba9e9f2e26cf61ffb51e56497ca9f39c6665fcbdfa8
+
+[Plen = 21]
+
+Key = f41e369a1599627e76983e9a4fc2e963dab4960b09ebe390
+Nonce = 68ef8285b90f28bcd3cb1bacea
+
+Count = 210
+Adata = dbe3e82e49624d968f5463ceb8af189fb3ad8b3b4122142b110d848a286dae71
+Payload = 81ad3f386bedcbf656ff535c63580d1f87e3c72326
+CT = 9f6028153e06d14d30b862a99a35413413c04a49dc6f68a03a11cf00d58f062a7b36465d13
+
+Count = 211
+Adata = d9acfd611e5bbb08c5d05d56791b8aebabf8d69734ec89153c91a1f65b2e1adb
+Payload = 35f6bb3f6a388f3a5a039b0a495b676d0b928aeb19
+CT = 2b3bac123fd395813c44aaffb0362b469fb10781e3ca1fb470b666523a19f83481f16481ed
+
+Count = 212
+Adata = 6003b771afe4e99e1ef1ed4a31b10540d95f4ac49885f0c8e5cdcb63d213127e
+Payload = 6aa7e3802b5a29d4f9ca88eb59f94af783d1054466
+CT = 746af4ad7eb1336f9f8db91ea09406dc17f2882e9c53cb05bfcd64da2b45c2e9a89a380b49
+
+Count = 213
+Adata = c371644275a6290821e7d308714bec2bf62d36c30f7fa77a0d60b28894f1c82a
+Payload = 13332b67ba5ba18137c306bd860dc3eb0a9a0b871a
+CT = 0dfe3c4aefb0bb3a518437487f608fc09eb986ede048f70fbc680cf7092b3dd90b943fc6e5
+
+Count = 214
+Adata = 8eceb15300ec4220510ed5b7deb3429de6ae5f618e1c222c28990a9ab4b4bac8
+Payload = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4
+CT = 1b550aef3ff6a8638484e9ab50c99df7a01154873ee386f33c0b8da8d0c5934e617dd618e5
+
+Count = 215
+Adata = 96d1cf3690c48c77a155ce13e67bbd62e6f03d88c893c1f7c30a6435d5ab36e0
+Payload = 60249343a8cd4d33c6edc583ea7e5c221ef3064787
+CT = 7ee9846efd265788a0aaf476131310098ad08b2d7d3d2db1360fb1121893f4d197731bce4f
+
+Count = 216
+Adata = 379bbc9f919dc2a8687f2a86cc9c3291804240a9b566c58519956848102e6155
+Payload = 79003a8d3d20d412f468f11712cec4d37cee847440
+CT = 67cd2da068cbcea9922fc0e2eba388f8e8cd091eba335ce1bfafc0948f2523e75f2aad86f9
+
+Count = 217
+Adata = 9bff9c9a8f94cd77e7016748da31f86d1b9c68465cbf954511c93a4776981524
+Payload = 7d078a8b200514a00628756250d410f7a0f8a769e6
+CT = 63ca9da675ee0e1b606f4497a9b95cdc34db2a031c7dc265e281307f0f4c38cddc556ac725
+
+Count = 218
+Adata = 25125a4668c31dc2e8a68b6c4c95ad7cf9322852e371b415a357d09acb01b587
+Payload = d9b0eaaff786165f882f41a98dbc0c355b3a1aaf40
+CT = c77dfd82a26d0ce4ee68705c74d1401ecf1997c5ba61c78a2f85a447c3e62b6197d65b9065
+
+Count = 219
+Adata = ad34d8f0902a5b79fb145b8206bb4d3b77e0bd8ae2d0964815389eacb33b4007
+Payload = 17b517ef577f588da374340d2522cc9ea642c8d8ae
+CT = 097800c202944236c53305f8dc4f80b5326145b2540312d067c08a9b4400e1df8bb7ed671a
+
+[Plen = 22]
+
+Key = 3289e59e3a7b29bf4a309afc253030bba4b9bdd64f0722f9
+Nonce = 30259ce106e9bd7a8bacbaf212
+
+Count = 220
+Adata = 2870bd9a26c510e9a256920899bbc77a4eb9b53f927045a943d5ed6b13638cf3
+Payload = 53911a67b65738f87fc7c20d6db8044bde1af95838d1
+CT = 70cf37d4b6f7e707376b1574ce17c040b5143da47abb2fe9afafc2fccd98ccf63b0fdec30eac
+
+Count = 221
+Adata = 611032a95ee87f89ad6be7c0fed8bd245c5f81076087b3bda4cde5587b8d14b6
+Payload = 46917e38b8a542296d290d065b0aa7c8aaa38950c386
+CT = 65cf538bb8059dd62585da7ff8a563c3c1ad4dac81ec102dfd8c231d6a355f079c213ce6858e
+
+Count = 222
+Adata = 2e7ea26d1cceaca3b7862a7a8469e366b52ec27ca127e3317222ee651d8da4a0
+Payload = b527828c89f674dc6f024f8cdd80c694bb3ebd57b2d9
+CT = 9679af3f8956ab2327ae98f57e2f029fd03079abf0b36df11febe34dd568da12c374674b9ac4
+
+Count = 223
+Adata = 0bf4413010daec585de34142224d1cad3072f9720f91ac664ad152820e838741
+Payload = 78230f73f9c0150f630eca4cd679818551d449db82e6
+CT = 5b7d22c0f960caf02ba21d3575d6458e3ada8d27c08cb2916540d9439b832aa44236a7e187ac
+
+Count = 224
+Adata = 2e7cae3306582eb5bad148247aa6c6ec943f8748e84b8a069ca9488b11844716
+Payload = 847bb12e0e56fa07a086eeda5907ae148148fa4107d2
+CT = a7259c9d0ef625f8e82a39a3faa86a1fea463ebd45b80d0768a18dead55700901408aa3f901a
+
+Count = 225
+Adata = 63036dc4ad13aee5dc1832e867f7538da108188fec7b08262af440d07579c451
+Payload = ec59e208c4bb429a371f1b3ffdf07fce5dea8a05f0ce
+CT = cf07cfbbc41b9d657fb3cc465e5fbbc536e44ef9b2a45f2073605d2a441805b6ff89d8beb68c
+
+Count = 226
+Adata = f9ec5ce4b63156d57e451eb67ab6d7a59cc397f43f6d26dc07d1036f0fb4a8cf
+Payload = fb12d94bd21b5748b23132a03065c78dae65a0bd2cfb
+CT = d84cf4f8d2bb88b7fa9de5d993ca0386c56b64416e91dcabef6907811c6b7df4e74c7a63d83b
+
+Count = 227
+Adata = e13a204e16f42bbf4716e95f1cb7e125ffac66a87f591c8ef2c7b8485ff707fd
+Payload = 239fa31d4a65de0318bfc5b60a06d706c129dcf255ac
+CT = 00c18eae4ac501fc501312cfa9a9130daa27180e17c626aa8aa37e858cd990f5593d9ef35f2a
+
+Count = 228
+Adata = c4591c3ad984a1e189c526b719212f8248289eeb277827272b8205d78191eb2d
+Payload = 57caadbb1a56cc5b8a5cf9584552e17e7af9542ba13e
+CT = 749480081af613a4c2f02e21e6fd257511f790d7e354d81e424d6b4528901ae46fb35f8b3106
+
+Count = 229
+Adata = cf4795bc7f43c30d3c3a8fd1b8a9d77d69bf59eb8b59d0f464315f40cb52335d
+Payload = a68c74e05f0a44d4a0372c0e5915b83d8e6729efacbb
+CT = 85d259535faa9b2be89bfb77faba7c36e569ed13eed1f25a4bfda35e1390f3f16f638dcd4047
+
+[Plen = 23]
+
+Key = 40f1aff2e44d05f12126097a0f07ac0359ba1a609356a4e6
+Nonce = 0df3fc6396f851785fca9aa5ff
+
+Count = 230
+Adata = e9699b20b0574fce8b5cbc4ef792eb96e2c1cce36b1b1f06ea2a95fe300633cc
+Payload = 8d98c580fb366f330dbfda20f91d99a0878b47efd14c6d
+CT = 579cdf9da62a2df471e03450516adb4ce99ae0f70b1776a39c3b429a1f922fac0b59e29a122e43
+
+Count = 231
+Adata = bd94c9ad6253c25dc417f87b6e52e03621ccf4b3bff5b402677aeb51e216335f
+Payload = 7391ba60fabe2c632bbaca16af9a235b2c7dae61691c0b
+CT = a995a07da7a26ea457e5246607ed61b7426c0979b3471067bf538e40f9366adf8758968f06ce8a
+
+Count = 232
+Adata = 4f263cda4a50b0e5379ec2fb546b326a07943527c1d175c029455a917753883b
+Payload = 7e1e93a6ca35a2c0e4f08fdb2e7ee22b9f486f0ab919e2
+CT = a41a89bb9729e00798af61ab8609a0c7f159c8126342f964a1199251b54f419720a30de83161de
+
+Count = 233
+Adata = 4d43702be4f0530319555d7f1a3356160f6cae48051f12e22a153d7e405c1149
+Payload = f94ff053c7413f34f96eae41fd1ac101151069af5a9428
+CT = 234bea4e9a5d7df385314031556d83ed7b01ceb780cf33b417e4cceb8dcf45ef33cc0007755bbc
+
+Count = 234
+Adata = f4d7978fad36223623ccb5bb18a7373cba8a6e3b1c921259e319266042db8887
+Payload = ba0716355fffb8ef947d2a15eb58375a1ff1084c566990
+CT = 60030c2802e3fa28e822c465432f75b671e0af548c328bd35aed57f49dcfecf248cf9d246ac024
+
+Count = 235
+Adata = 12e4fe727b1f27a619dd67bb976ddc2b18b2ef8b7184290d9553494a500d933e
+Payload = 872940780a94680a791c937994ceafd2c8b7a22b5f4927
+CT = 5d2d5a6557882acd05437d093cb9ed3ea6a6053385123c97cda0e04d2ff65c2e06a8276bdf6f97
+
+Count = 236
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830
+CT = 0d1c7e9a22393a1c757245d27ed6bb18079b3b2db6232b3494dd2ee0a0fe5bfc9f69234c8142ed
+
+Count = 237
+Adata = cefc4f2fb796c2502329ca3d8f8af3200dd9edb8f164e15acec90536a15b6fdc
+Payload = cda681aa3109ebf5f21ee3a849098ea3a551e844fae4b4
+CT = 17a29bb76c15a9328e410dd8e17ecc4fcb404f5c20bfaf9008ead8e923997508eebf5e776198dc
+
+Count = 238
+Adata = 94fc7eb8febb832097ba6eecd2697da91b5a8a1f2248f67a7659e0ac55a09a0d
+Payload = d4f8d262870b5000a40b8fcce88f55c65c4d12e729975e
+CT = 0efcc87fda1712c7d85461bc40f8172a325cb5fff3cc45f136cc6ea1b0fdb554e0803053875b89
+
+Count = 239
+Adata = 459085184094e302b2e921cc04270b676e75bbcf0e4b53ed387df2bd0e75e0ac
+Payload = 732f211061c0a32c6ad124c58418d560ef5eab2602314c
+CT = a92b3b0d3cdce1eb168ecab52c6f978c814f0c3ed86a575da8ceccae093888daaf92c95817fc3d
+
+[Plen = 24]
+
+Key = 91f9d636a071c3aad1743137e0644a73de9e47bd76acd919
+Nonce = 1bf491ac320d660eb2dd45c6c3
+
+Count = 240
+Adata = 3bdfd7f18d2b6d0804d779f0679aaa2d7d32978c2df8015ae4b758d337be81dd
+Payload = 4eaf9384cad976f65f98042d561d760b5a787330dc658f6c
+CT = 635530cab14e3d0a135bb6eebb5829412676e6dd4995f99cb7e17f235bd660e7e17b2c65320e9fd4
+
+Count = 241
+Adata = 9de45b7e30bb67e88735b8fb7729d6f3de46c78921b228bad8f17cc9c709c387
+Payload = 59bee7d18fd4ba573f3e4f61076f5b9f6a3487e47d98c729
+CT = 7444449ff443f1ab73fdfda2ea2a04d5163a1209e868b1d99f40890c7d650afccda40fb2a4cd603b
+
+Count = 242
+Adata = 783477f981ef0551b5e7a714b640bbb38316c53756c96e30c898cdee3b72e6f4
+Payload = 4e7f3c86d846ff351db81dbe1d2e9ed73ec0450587ae681b
+CT = 63859fc8a3d1b4c9517baf7df06bc19d42ced0e8125e1eeb50236cf1a12a9e3542a4051788f9775a
+
+Count = 243
+Adata = 2851d40243512a43f70f9c25e9b18c122a1433f05c61e65017e197e88b129e43
+Payload = 2db7cb2739c839383b64c2c93c7d5c906d984756c3dedaa9
+CT = 004d6869425f72c477a7700ad13803da1196d2bb562eac59b1bbad9861192df356c6678b2f561ea3
+
+Count = 244
+Adata = 1cfa2d62cc1f6313fb0c6eb21803e09cdf61ee3ddb15192529560e5d8096cafb
+Payload = 2f2b82497c78369890809460d80a16be4f3330e8a0089165
+CT = 02d1210707ef7d64dc4326a3354f49f4333da50535f8e7951da4211d4c28d2d91568117fc99fd911
+
+Count = 245
+Adata = 5a14b556156191b2704936f64df0bf1dd2bd8d587418f4f85472338fcf86aa52
+Payload = 7cfefca725da1b6bb5d9545e3e50f5a624a8160bdb0e7d4e
+CT = 51045fe95e4d5097f91ae69dd315aaec58a683e64efe0bbeda99be0e054bb881a25a74b547d3ed5e
+
+Count = 246
+Adata = 148de640f3c11591a6f8c5c48632c5fb79d3b7e1cef9159c680d71fd1f9801fa
+Payload = 5205165c4e9612974dc92f60d1e328d68aa9466e27dbd499
+CT = 7fffb5123501596b010a9da33ca6779cf6a7d383b22ba2694c1fedb47fa30ff2ead6bf382431b2de
+
+Count = 247
+Adata = f852e38703097cc37c589b7860dbc333e091411462d5576dc9909a8cf6ac99d4
+Payload = f968f2833427abbc9fe1cab7e7a3f905a3b23a35802029ff
+CT = d49251cd4fb0e040d32278740ae6a64fdfbcafd815d05f0f338762a4e4299615c67130a28b56a383
+
+Count = 248
+Adata = 43df03a0e23c7ad0d13485150ca224c0b3f39d4e5f2d718db6308e003d3dc683
+Payload = 67da6ca42655188af0b8e389152b2a1b6e2c3ed88926afa5
+CT = 4a20cfea5dc25376bc7b514af86e75511222ab351cd6d9559dbdf61387294812f483aad76d48d899
+
+Count = 249
+Adata = b297dce04ada2ddebc7e94eff7c51b87eee2f98c410c5c0919d0652653ab7458
+Payload = 9777cf90dd7c7e863506686fc3ba6d3d05328f78b350f92f
+CT = ba8d6cdea6eb357a79c5daac2eff3277793c1a9526a08fdf078177541e19b11dfec995f40c99af70
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp
new file mode 100644
index 0000000000..e9cd7eefe9
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VPT256.rsp
@@ -0,0 +1,1383 @@
+# CAVS 11.0
+# "CCM-VPT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Nlen = 13
+Tlen = 16
+
+[Plen = 0]
+
+Key = c6c14c655e52c8a4c7e8d54e974d698e1f21ee3ba717a0adfa6136d02668c476
+Nonce = 291e91b19de518cd7806de44f6
+
+Count = 0
+Adata = b4f8326944a45d95f91887c2a6ac36b60eea5edef84c1c358146a666b6878335
+Payload = 00
+CT = ca482c674b599046cc7d7ee0d00eec1e
+
+Count = 1
+Adata = 36c17fd901169e5b144fdb2c4bea8cd65ad8acf7b4d3dd39acf2ad83da7b1971
+Payload = 00
+CT = 67747defe5da5fecc00b9bf3b249f434
+
+Count = 2
+Adata = 9a37c654ab8e5a0c6bdfff9793457197d206ed207d768cbc8318cfb39f077b89
+Payload = 00
+CT = c57ef5d0faf49149c311707493a4cfd4
+
+Count = 3
+Adata = 5ab80169184541393a6975f442ee583cd432d71a6d1568fa51159df7c5b8f959
+Payload = 00
+CT = bc2fb5571a7563bb90689a229d2f63a7
+
+Count = 4
+Adata = c78a22a667aafab0c94047e03837d51b11490693d5c57ea27b901ff80b6a38f9
+Payload = 00
+CT = 428888c6420c56806f465b415a66e65a
+
+Count = 5
+Adata = e11e30cbf63623816379f578788b0c8e6b59ee3c9c50aa6e1dcd749172d48fed
+Payload = 00
+CT = 9f1b7520025e1075731adc946b80121d
+
+Count = 6
+Adata = 05716168829276ff7ab23b7dd373db361e6d9e1f11d0028d374a0d3fe62be19f
+Payload = 00
+CT = bd36b053b6a90f19e3b6622cba93105d
+
+Count = 7
+Adata = 3e915389639435629fcc01e1b7022d3574e2848e9151261ad801d03387425dd7
+Payload = 00
+CT = 458595a3413b965b189de46703760aa0
+
+Count = 8
+Adata = 2f496be73a9a5d9db5927e622e166c6ec946150687b21c51c8ca7e680f9775ac
+Payload = 00
+CT = 8b259b84a6ee5669e175affca8ba3b1a
+
+Count = 9
+Adata = 0a8725bd8c8eab9ed52ca47835837b9f00a6c8d834ab17105b01eb4eb30402e7
+Payload = 00
+CT = c5f35fdf2b63e77a18d154f0ddcfedbf
+
+[Plen = 1]
+
+Key = cc49d4a397887cb57bc92c8a8c26a7aac205c653ef4011c1f48390ad35f5df14
+Nonce = 6df8c5c28d1728975a0b766cd7
+
+Count = 10
+Adata = 080f82469505118842e5fa70df5323de175a37609904ee5e76288f94ca84b3c5
+Payload = 1a
+CT = a5f24e87a11a95374d4c190945bf08ef2f
+
+Count = 11
+Adata = f6cfb81373f1cbb0574dda514747d0099635b48cb809c6f1fa30cbb671baa505
+Payload = 40
+CT = ffd43c5f39be92778fdce3c832d2d3a019
+
+Count = 12
+Adata = 5a88b14bada16b513d4aa349b11ce4a77d4cda6f6322ff4939ad77d8ecb63748
+Payload = 41
+CT = fe753b7b661f1aad57c24c889b1c4fe513
+
+Count = 13
+Adata = a92b95b997cf9efded9ff5e1bff2e49d32e65f6283552ded4b05485b011f853f
+Payload = 06
+CT = b91c5ac66e89bf2769ef5f38a3f1738b24
+
+Count = 14
+Adata = a206a1eb70a9d24bb5e72f314e7d91de074f59055653bdd24aab5f2bbe112436
+Payload = c8
+CT = 773fe64379cea1a8ae3627418dd3e489a2
+
+Count = 15
+Adata = d3029f384fd7859c287e38c61a9475d5ddbfd64af93746b1dc86b8842a8c194c
+Payload = e2
+CT = 5dabc529442ff93005551b7689bcb748f7
+
+Count = 16
+Adata = 51ca3d3b70b5e354451a5177d7acfd8e7b44eae55e29d88b5e8eb8fc1e5c62fc
+Payload = 1a
+CT = a5ee68e416617ac974b3d1af7320cd51f6
+
+Count = 17
+Adata = 8c6c6791f1ac957b18bf008e260a0af4a5b7bfdb1e0008d6eaaa227f45cf4f62
+Payload = dd
+CT = 6243883d93d7066991e0fac453400b4fbf
+
+Count = 18
+Adata = b0a1af969a95025385b251afd1e89f353426ed6e5d71019cd73366aa31d5b464
+Payload = 4c
+CT = f3b940d416f3435812f9d1b18f441b7721
+
+Count = 19
+Adata = 7e72b2ca698a18cb0bf625f5daddb0d40643009db938340a9e4fe164a052fee1
+Payload = 88
+CT = 371d27e9a32feea28a6a7e7da2d27e1cc4
+
+[Plen = 2]
+
+Key = 36b0175379e7ae19c277fe656a2252a82796309be0f0d4e1c07fdde88aca4510
+Nonce = 021bd8b551947be4c18cf1a455
+
+Count = 20
+Adata = b5c6e8313b9c68e6bb84bffd65fa4108d243f580eab99bb80563ed1050c8266b
+Payload = be80
+CT = ecacc3152e43d9efea26e16c1d1793e2a8c4
+
+Count = 21
+Adata = 38e5032c5949c2668191ef1af5bb17eddc28abdb4e5bb41eaffec2523b2525d6
+Payload = 82c9
+CT = d0e5d06bf4b50ccce0b2acfd16ce90a8854d
+
+Count = 22
+Adata = 0b50f5173249fb7118f80d25874d6745d88e4ce265fa0dd141ad67ae26c31122
+Payload = 8239
+CT = d0158d784f486c1dc4a2bafd5b02ca1e1c05
+
+Count = 23
+Adata = 0296743a3125b103a2b2a78a109e825ea10834bd684215ab2e85cc4172e37348
+Payload = 16c1
+CT = 44eda3377002a48f9fe306d157358e6df37d
+
+Count = 24
+Adata = a94e64becb803e211785ba51db7f3db042fbf44a7a821509156a6828b0f207e9
+Payload = 2801
+CT = 7a2df6c09bf1dcb1c82bd98c6e2c13a8d7a5
+
+Count = 25
+Adata = 105358cc17b12107e023a23d57b44c66a2c58d8db05100311575e1ea152fc350
+Payload = 65e7
+CT = 37cb2ea363c0d8864363056467570959ba03
+
+Count = 26
+Adata = 669f9a63cf638a202dca1965c4116273249813ce0b39703887d89bdf5b3b12d6
+Payload = 819d
+CT = d3b16519377e6d0252b5f80cdf3d0253eccf
+
+Count = 27
+Adata = e288590a3eba28ac6847a50b0294ab6bd0a548716ff5102c44a5b656b2d9ddd6
+Payload = 761e
+CT = 24329a4dee6ca2cde473f08f76f779856c3c
+
+Count = 28
+Adata = 5b222aae3c7786c3b9021ba672f9136190ec931cf055f84c85706127f74c6d5b
+Payload = 56de
+CT = 04f29e65c0f01e644e74092253b470cd5511
+
+Count = 29
+Adata = 2082f96c7e36b204ad076d8b2f796cccf5cbc80b8384b53a504e07706b07f596
+Payload = b275
+CT = e059809fa107f379957b52ac29fe0bc8a1e2
+
+[Plen = 3]
+
+Key = ddb739acda6c56ec9aefc4f4cbc258587f443da4e76ddfa85dbe0813a8784944
+Nonce = 0bddf342121b82f906368b0d7b
+
+Count = 30
+Adata = 887486fff7922768186363ef17eb78e5cf2fab8f47a4eb327de8b16d63b02acb
+Payload = db457c
+CT = 54473c3f65d6be431e79700378049ac06f2599
+
+Count = 31
+Adata = 0683c20e82d3c66787cb047f0b1eb1c58cdde9fb99ee4e4494bbf27eb62777d1
+Payload = 62a6c5
+CT = eda4853b186edc15c22ba24e470eb5a072da9f
+
+Count = 32
+Adata = 413074619b598f8bed34cab51ddf59941861ba0169ebe7570a5ed01d790c08e5
+Payload = cc67bc
+CT = 4365fc52a1fb5a58bd51931230c1a7dfb1a8c1
+
+Count = 33
+Adata = 2d65a5175c29a095dc082dab9cfcf4b895efbfa715c57614589d4db159543ce9
+Payload = 33800b
+CT = bc824b7d3810f59176cb108c7e969da51d4d79
+
+Count = 34
+Adata = 6a831b6059456be98e6fce608d8c71cb8efb04a96b45c2dfbdaeabf5420a1482
+Payload = b2c826
+CT = 3dca6646ffea832595c9c86e6517215541ddbd
+
+Count = 35
+Adata = 3a04a01160402bf36f33337c340883597207972728c5014213980cd7744e9e41
+Payload = d7e620
+CT = 58e460e89a6725f0fc35622d89d2f3e34be90a
+
+Count = 36
+Adata = 64d8bd3c646f76dc6ce89defd40777fe17316729e22ba90f6a2443ee03f6390b
+Payload = 795af4
+CT = f658b4b1bd7ad5d81686aeb44caa6025d488bd
+
+Count = 37
+Adata = 7bef8d35616108922aab78936967204980b8a4945b31602f5ef2feec9b144841
+Payload = 66efcd
+CT = e9ed8d0553c801f37c2b6f82861a3cd68a75e3
+
+Count = 38
+Adata = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe01ec1b66eee216341
+Payload = 78b00d
+CT = f7b24de3eeb8ea6c08b466baf246b3667feb3f
+
+Count = 39
+Adata = 71bf573cf63b0022d8143780fc2d9c7dbd0505ac31e9dce0ad68c2428b0878a0
+Payload = 9dd5e1
+CT = 12d7a11db811640c533794bfec6eeb977233ec
+
+[Plen = 4]
+
+Key = 62b82637e567ad27c3066d533ed76e314522ac5c53851a8c958ce6c64b82ffd0
+Nonce = 5bc2896d8b81999546f88232ab
+
+Count = 40
+Adata = fffb40b0d18cb23018aac109bf62d849adca42629d8a9ad1299b83fe274f9a63
+Payload = 87294078
+CT = 2bc22735ab21dfdcfe95bd83592fb6b4168d9a23
+
+Count = 41
+Adata = 75c3b3059e59032067e9cd94d872e66f168e503bcf46bc78d82a4d4a15a29f6e
+Payload = 0f28ee1c
+CT = a3c38951b5de3331078aa13bd3742b59df4f661a
+
+Count = 42
+Adata = 8fb9569f18a256aff71601d8412d22863e5a6e6f639214d180b095fa3b18d60e
+Payload = d41c9c87
+CT = 78f7fbcae52afe7326a12a9aaf22255a38d4bd0d
+
+Count = 43
+Adata = 8b62d9adf6819c46c870df8a1486f0a329672f7d137bb7d8659f419c361a466c
+Payload = 046bc0d8
+CT = a880a7957543692a72f0d599de48b5e5f5a9413f
+
+Count = 44
+Adata = fd98f8f39dfa46ea5926e0ffacbabbe8c34205aade08aa0df82e1d4eaaf95515
+Payload = 39bd4db8
+CT = 95562af530fc357f5482b9004d466bf858586acb
+
+Count = 45
+Adata = 09bf4f77a9883733590a3cc7ee97f3c9b70f4db255620e88cd5080badc73684c
+Payload = b43cdd3a
+CT = 18d7ba77a9e8db046fdd548b52d40375c1e9a448
+
+Count = 46
+Adata = 40326d765e0f6cf4b4deccb128bebf65a7b3c3e5bcf1d58f6158e1e9153b7e85
+Payload = e0052e9b
+CT = 4cee49d64efbdd4ad8d3e863172d9372fca07c20
+
+Count = 47
+Adata = aa5ae6dcdc21b5446489bdabf5c6747bdf3bbfdb3de2c03170efefe5ccb06d69
+Payload = 696825f6
+CT = c58342bb95bd661b32bc18025808f8b4035acad6
+
+Count = 48
+Adata = d3d34f140a856e55b29471fde4c0e5f7306b76d03faab26db79c10f95ffb3122
+Payload = 7eb07739
+CT = d25b1074ac05b072264e31a4b2801a6d790512d7
+
+Count = 49
+Adata = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671194646e0b0136432
+Payload = 9cad70b1
+CT = 304617fcc00514d260e1d211de361c254369e93a
+
+[Plen = 5]
+
+Key = bc29a16e19cfbe32bf4948e8e4484159bc819b7eec504e4441a1a98ca210e576
+Nonce = 4f18bcc8ee0bbb80de30a9e086
+
+Count = 50
+Adata = 574931ae4b24bdf7e9217eca6ce2a07287999e529f6e106e3721c42dacf00f5d
+Payload = 3e8c6d1b12
+CT = 45f3795fcf9c66e1a43103d9a18f5fba5fab83f994
+
+Count = 51
+Adata = 99cd9d15630a55e166114f04093bd1bb6dbb94ecaad126fe5c408dee5f012d9f
+Payload = 76fc98ec66
+CT = 0d838ca8bb6f3cd579294f706213ed0f0bf32f00c5
+
+Count = 52
+Adata = 1516fdf7a7a99f3c9acc7fff686203dec794c3e52272985449ddf5a268a47bc3
+Payload = 6564c247cc
+CT = 1e1bd603117d38e026f706c9273dbcb6dc982751d0
+
+Count = 53
+Adata = 0c9c35be98591bf6737fc8d5624dcdba1a3523c6029013363b9153f0de77725b
+Payload = c11b9c9d76
+CT = ba6488d9abc3e46166767c6ad2aeffb347168b1b55
+
+Count = 54
+Adata = e74afe3ba960e6409dba78ecb9457e2a4ce2e09792b1d2e3858f4c79f7ddba62
+Payload = 45a4e0d7dd
+CT = 3edbf4930033a7dca78bcbf4d75d651ee5fadff31b
+
+Count = 55
+Adata = 96cbe9cd193513599c81f5a520fabaff51ee8cbdb81063c8311b1a57a0b8c8fd
+Payload = e5861b2327
+CT = 9ef90f67fa11585167c83105ee16828a574c84ac86
+
+Count = 56
+Adata = 2e7ea84da4bc4d7cfb463e3f2c8647057afff3fbececa1d20024dac29e41e2cf
+Payload = f5b5bcc38e
+CT = 8ecaa88753ffaba456f78e431f4baa5665f14e1845
+
+Count = 57
+Adata = be125386f5be9532e36786d2e4011f1149abd227b9841150d1c00f7d0efbca4a
+Payload = b6cc89c75d
+CT = cdb39d838034714731f9503993df357954ecb19cd3
+
+Count = 58
+Adata = 3fa8628594b2645bc35530203dca640838037daeaf9cf8acaa0fb76abf27a733
+Payload = 3802f2aa9e
+CT = 437de6ee436c1b008b7572752f04362b2bfdc296bb
+
+Count = 59
+Adata = 642ae3466661ce1f51783deece86c38e986b8c0adea9e410e976f8a2fe0fe10f
+Payload = e082b8741c
+CT = 9bfdac30c1a3f7c3c29dc312c1f51a675400500e32
+
+[Plen = 6]
+
+Key = 5f4b4f97b6aa48adb3336c451aac377fde4adf47897fd9ccdf139f33be76b18c
+Nonce = 7a76eac44486afdb112fc4aab9
+
+Count = 60
+Adata = a66c980f6621e03ff93b55d5a148615c4ad36d6cbdd0b22b173b4b1479fb8ff7
+Payload = 1b62ad19dcac
+CT = 4ad1fcf57c12b14e0e659a6305b4aeffae82f8a66c94
+
+Count = 61
+Adata = c13f65bd491cb172a0f7bbc4a056c579484b62695e90383358d605307d5be0a5
+Payload = 3ef0faaa9b79
+CT = 6f43ab463bc779fa7932d365e2da9b05c00a7318384a
+
+Count = 62
+Adata = 59dcca8fc50740831f8f259eb55d4db11f763a83187d93758d78d166f4d73cd5
+Payload = 1a98ddbf35f1
+CT = 4b2b8c53954f813229912137b7a4945dc07cea24a974
+
+Count = 63
+Adata = 578509ca4f57aadb78056794bf18b0714090970db786e2e838105e672165761c
+Payload = f46a7b1c28ea
+CT = a5d92af088546e045f19f737a24c8addf832ed3f7a42
+
+Count = 64
+Adata = 696c0c6427273cf06be79f2206c43af9cbda0b884efaf04deba0c4bf0a25cb26
+Payload = e98f5e5a20d0
+CT = b83c0fb6806edaae8a7dcd3b0fbb59438f88743ec6e8
+
+Count = 65
+Adata = 95a66b60249ed086eecaeb9bc449afcee9de212619e87516ca947351b25120df
+Payload = 06319c0480e2
+CT = 5782cde8205cd9cb636ca6543c4e35964f47341f2814
+
+Count = 66
+Adata = 2b411bea57b51d10a4d2fb17ef0f204aa53cf112e1130c21d411cdf16a84176d
+Payload = f4c723433b7c
+CT = a57472af9bc2ec82eadf4eb1f055da1a92a82052ab8b
+
+Count = 67
+Adata = ff3bff3a26fc5a91252d795f7e1b06f352314eb676bff50dc9fbe881c446941e
+Payload = 02f809b01ce3
+CT = 534b585cbc5d01b10a7ae24a4ca2bfb07ea2a3b31a97
+
+Count = 68
+Adata = f6be4aad63d33a96c0b5e9c4be62323c9e2308b29961fff980ba0dbda0549274
+Payload = 2b6004823a29
+CT = 7ad3556e9a97231323a4b88af5d7d0b07c0e73ddce1d
+
+Count = 69
+Adata = c3706a28d7420b41e072dcecc06b6b13116cca110bde8faea8e51f5107352d71
+Payload = 236c60cba4fa
+CT = 72df31270444db30eb33d2ede33abbe22f37704fe68b
+
+[Plen = 7]
+
+Key = f7aaeff3a1dc0cc5ecf220c67ad9f6dda060b4f1be3cc609cb4f18b2342a88a2
+Nonce = d0d6871b9adc8623ac63faf00f
+
+Count = 70
+Adata = e97175c23c5b47da8ce67811c6d60a7499b3b7e1347ad860519285b67201fe38
+Payload = d48daa2919348d
+CT = eb32ab153a8e092fa325bafc176a07c31e6cc0a852d288
+
+Count = 71
+Adata = ba45e1859efae362a44a0116a14e488ba369da6c76c3913b6df8e69e5e1111fa
+Payload = f95b716bfe3475
+CT = c6e47057dd8ef1a24840f4f40a7963becde3a85968b29c
+
+Count = 72
+Adata = efcaa6f6cda3036b0b52ff9f36bc38ca74049c32c6b7cdfb8a46ca4144bacd64
+Payload = 4862e3677083f0
+CT = 77dde25b5339748f2a4a5c276727e0a210fc2efb5aeabe
+
+Count = 73
+Adata = 360bcb407603fe92f856bf677625b9882521e6dae8f35fdfc3dc737f9398f609
+Payload = 7f1ca0728f6d65
+CT = 40a3a14eacd7e1051734fc31232ab2ab63474020ab4dc9
+
+Count = 74
+Adata = f12ee9d37946cfd88516cbe4a046f08c9bbba76a3973ff1e2cb14493405bd384
+Payload = 67478ef73290fa
+CT = 58f88fcb112a7ec715244f307609ffa253e4e3659b0ece
+
+Count = 75
+Adata = 5833dde0c577b2be4eb4b3d01d7b0042fa8441ad7043ea462bbbbd56a59790ea
+Payload = 36bb9e511276c5
+CT = 09049f6d31cc41f11047da612d2987fa2e50ada5ae7f9d
+
+Count = 76
+Adata = 1e103c63d8ead36b985f921044cd32b8f9f04a2ba9fa154a09e676ffaa093970
+Payload = d68d6556c5a5b1
+CT = e932646ae61f35382f7648718127ebae7eb7443ebd2c2c
+
+Count = 77
+Adata = a1cfb61d45a140bdea6329ba0fe80429ff9aa4624a1d31bc752f7c97f1d390a0
+Payload = 0568cca4ff79dc
+CT = 3ad7cd98dcc358cc40a5e7fffb1fb9a5dd9d6ba91bede1
+
+Count = 78
+Adata = 116b5b015e44ceef0061b2d2e73fa0b386d5c1e187782beebdfc6efb5a1c6935
+Payload = bd93d08eea4263
+CT = 822cd1b2c9f8e7468d2b70c311732f11ed72b57d83e500
+
+Count = 79
+Adata = 3d55882e6f3f89309b6940a3b408e573458eedd10fc3d0e1f3170eb313367475
+Payload = 4fb62753024e92
+CT = 7009266f21f416b41a70f548e359add30c0e5746fbeb2b
+
+[Plen = 8]
+
+Key = 493e14623cd250058a7fc66a3fee0c24b6e363b966c2314aff53b276b6c2ea7b
+Nonce = fe2d8ae8da94a6df563f89ce00
+
+Count = 80
+Adata = 579a637e37a0974cd2fc3b735d9ed088e8e488ffe210f043e0f9d2079a015ad6
+Payload = e5653e512d8b0b70
+CT = 75d31f8d47bee5c4e2ba537355ae8ab25cc9ed3511ff5053
+
+Count = 81
+Adata = 1583138aa307401dddc40804ac0f414d338fc3ffb2946f09aaaa7079426fc1ee
+Payload = 2c4ba9ce52e01645
+CT = bcfd881238d5f8f1781a9e359804831f31a1efb1ae1cb71d
+
+Count = 82
+Adata = 78d3dda40e433bba7a330ca3e5bd5170f0895f2e3e438402344ced79fcb0c719
+Payload = 5eb2d054a0e58c62
+CT = ce04f188cad062d62dcc77c4e1fe2bafd477598977835f0c
+
+Count = 83
+Adata = dfc762466fa84c27326e0ee4320aa71103d1e9c8a5cf7d9fab5f27d79df94bd6
+Payload = bbbf7830d04ab907
+CT = 2b0959ecba7f57b308946723baf0dbf613359b6e040f9bd5
+
+Count = 84
+Adata = 7e8ea82d1137c1e233522da12626e90a5f66a988e70664cb014c12790d2ab520
+Payload = 10c654c78a9e3c06
+CT = 8070751be0abd2b2003bd62ca51f74088bbbd33e54ac9dd4
+
+Count = 85
+Adata = 873da112557935b3929f713d80744ed08b4b276b86331dbc386fba361726d565
+Payload = 668d32e322e1da3e
+CT = f63b133f48d4348a67e65e7f2cdedf6ef8cc0ee7a6dcfb02
+
+Count = 86
+Adata = cfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82
+Payload = e39f6225e8eab6cc
+CT = 732943f982df58780532f8c6639e5d6c7b755fcf516724e3
+
+Count = 87
+Adata = 01abcfee196f9d74fcaa7b69ae24a275485c25af93cc2306d56e41e1eb7f5702
+Payload = 6021a00f6d0610a4
+CT = f09781d30733fe107fd7a33828413ebc252dd9d015773524
+
+Count = 88
+Adata = ce1c31e7121c071d89afab5a9676c9e96cac3d89dcae83136bbb6f5ca8f81e5d
+Payload = bbaf0ac4e77ee78d
+CT = 2b192b188d4b0939d3d51368799325ad1c8233fa071bade0
+
+Count = 89
+Adata = bb210ca5bc07e3c5b06f1d0084a5a72125f177d3e56c151221115ae020177739
+Payload = 98a2336549a23a76
+CT = 081412b92397d4c25d1ea568637f773174a7f920a51b1fe1
+
+[Plen = 9]
+
+Key = b23255372455c69244a0210e6a9e13b155a5ec9d6d0900e54a8f4d9f7a255e3a
+Nonce = 274846196d78f0af2df5860231
+
+Count = 90
+Adata = 69adcae8a1e9a3f2fe9e62591f7b4c5b19d3b50e769521f67e7ea8d7b58d9fc8
+Payload = 615d724ae94a5daf8d
+CT = f019ae51063239287d896e7127f17d13f98013b420219eb877
+
+Count = 91
+Adata = 162d0033c9ea8d8334d485b29eef727302135a07a934eea5fee6041e9f1f47c1
+Payload = 0d9168eeab3b27ba69
+CT = 9cd5b4f54443433d997cc2cd61da9358b4045fef32f8192cbf
+
+Count = 92
+Adata = 3f4ab57efa32f51a4c00790280e77c0e55b85bbda4f854e242368e9a289b5a81
+Payload = 6287dcffdd5fb97885
+CT = f3c300e43227ddff75d280f0ffdd560fb8915978e3bd6205bb
+
+Count = 93
+Adata = 945d18134c148f164b39fd7c4aef0335045553f6ea690a3b1726418d86f0de00
+Payload = 6e5e01b3fd71d16b9c
+CT = ff1adda81209b5ec6c7dbf90420a1ff2e24bd6303b80cfc199
+
+Count = 94
+Adata = 23af12893431b07c2922ab623aed901c0eaaeb9a24efc55273e96aea4dab7038
+Payload = b51521e689b5247362
+CT = 2451fdfd66cd40f492d741f4329ae7cc77d42bf7e5f2ec5ab6
+
+Count = 95
+Adata = b15a118b3132c20c31e6c9d09acdee0e15fcc59d6f18306442682512d22eb10f
+Payload = 7f973617e710fb76fe
+CT = eed3ea0c08689ff10ec9ffdcc2f36edac14613b1d85baf25a9
+
+Count = 96
+Adata = dcfbeb6490f5fa7eaf917462473a6cec98bebf8f17493fe9b994119a6d5a5457
+Payload = 7e909b6727ac3fd02f
+CT = efd4477cc8d45b57df5a61a28bb10265b26043d7a8dd357713
+
+Count = 97
+Adata = 77e9317294f046f315a0d79e3423f29f7d9ebcd36d6eaa2a3fb2f4500309478c
+Payload = a5075638932b5632f8
+CT = 34438a237c5332b508d321c371ae1fd01bdf3b6c75a597da6e
+
+Count = 98
+Adata = 3aa8f204eb127b547e13873ed0238018394e13686c8734e49e3e629deb352c77
+Payload = c10f15a0de78db8aa3
+CT = 504bc9bb3100bf0d539393d1635bc40ac62405a39155406c47
+
+Count = 99
+Adata = 7f67e6f97c6c258f014d721a4edaaa0ddb3f9f09993276ab7b714ea9356c231d
+Payload = 8294f830cfca42cfbe
+CT = 13d0242b20b226484eff89641e1bd5ad6cc827441b17c45ecf
+
+[Plen = 10]
+
+Key = dbf06366f766e2811ecd5d4384d6d08336adc37e0824d620cf0d9e7fd1e7afa9
+Nonce = b3503ed4e277ed9769b20c10c0
+
+Count = 100
+Adata = 9ae5a04baa9d02c8854e609899c6240851cbc83f81f752bc04c71affa4eed385
+Payload = 2e3cf0af8c96c7b22719
+CT = e317df43ab46eb31be7e76f2730d771d56099a0c8d2703d7a24e
+
+Count = 101
+Adata = da77c6d5627a2aa34911bd1f7cc5f8aa68a2c6546adc96a186b9af8e5baac4cf
+Payload = e081c43a07450ce0dfa2
+CT = 2daaebd62095206346c5bcc7a8260ef361dc39fdb776d041f0d4
+
+Count = 102
+Adata = 134d2d9726400d09dd3521326f96fbef993ddc0c4088770057b0f8d70356456f
+Payload = c381d2ae5e72fc82324a
+CT = 0eaafd4279a2d001ab2d19f0cbb0899f221aac9762f2650f8058
+
+Count = 103
+Adata = 0d065dfde1de1f21784c7869eb566c977f807cfbd53578f4616995b51d7dc045
+Payload = 737f4d00c54ddca80eec
+CT = be5462ece29df02b978b3dc92a9bd26b9653e5917359c331fcff
+
+Count = 104
+Adata = 95c54d187f2415535451cbb9cb35869749b171f7043216ce6886dd77baeecf60
+Payload = 4e9e251ebbbbe5dbc8ff
+CT = 83b50af29c6bc958519891dda72c27d272561e00f7041845d998
+
+Count = 105
+Adata = 0f98039e6a9fe360373b48c7850ce113a0ff7b2ae5ce773dd4c67ca967cd691b
+Payload = 0db72b281ab4046d15a6
+CT = c09c04c43d6428ee8cc1928ac628758ad58fc1b5a768d4722848
+
+Count = 106
+Adata = ad840bc55654762e5eba0e4a9e7998992d990a06d70da1b1ca922ef193dab19a
+Payload = 4f7b4f38ff1ba4df5a59
+CT = 825060d4d8cb885cc33ed11dad4dc8b265a53cf0bdd85c5f15f4
+
+Count = 107
+Adata = 911e9876ea98e1bcf710d8fd05b5bf000ea317d926b41b6015998ee1462ab615
+Payload = 58ce55379ef24b72d6d6
+CT = 95e57adbb92267f14fb18eb659a5a7084be48d099467da4395df
+
+Count = 108
+Adata = 3f68a4fb4043bcf9b6d277c97e11365d949c705bd6679c6f0aaf52e62330ad79
+Payload = a219028a953ce1544835
+CT = 6f322d66b2eccdd7d1523b2b2583fd117cec47b1c84d3863159e
+
+Count = 109
+Adata = 02f32242cba6204319075ea8ce806a57845355ae73e6b875955df510096ebff9
+Payload = 83b0ee9a52252c456105
+CT = 4e9bc17675f500c6f8625456eb2b6a2d35c649a84051f843153c
+
+[Plen = 11]
+
+Key = 4dd555bd3a5253a90b68b5d4d46bd050340ee07ddad3a72048c657b5d76bb207
+Nonce = bdb1b82ba864893c2ee8f7426c
+
+Count = 110
+Adata = 9bcc5848e928ba0068f7a867e79e83a6f93593354a8bfcfc306aeeb9821c1da1
+Payload = 8015c0f07a7acd4b1cbdd2
+CT = 8e9f80c726980b3d42e43a6512a0481255b729a10f9edb5f07c60c
+
+Count = 111
+Adata = c2e75952ab49216f305e3776865791ce877cef8c0229ca97561787093fddf1d8
+Payload = c97b62a719720b44b7779c
+CT = c7f122904590cd32e92e748c514444f00ffdb80a4bb7e9eb651946
+
+Count = 112
+Adata = c76a3ff4e6d1f742dd845be2d74c1a9b08e418909b15077deb20373ef55caf91
+Payload = cb7c17ef62464ecc8008f6
+CT = c5f657d83ea488bade511edb609dfc1929ac1ba5753fc83bf945b7
+
+Count = 113
+Adata = bdb69f99f9a144b9ad88c6cfd8ffb8304c201de9b2818552ce6379e6042c1951
+Payload = 893a690cc5221de597d0e8
+CT = 87b0293b99c0db93c9890053b74283296d0fca83b262915289163c
+
+Count = 114
+Adata = 01815f599d6ba0d1c09f6f673bb6cca4c2a7a74f4e985be4c0f37842c7bbc5a4
+Payload = 80f3e4245c3eab16ef8bf0
+CT = 8e79a41300dc6d60b1d21888a34955893059d66549795b3ac2105c
+
+Count = 115
+Adata = a9db62e9ab53c4a805c43838ce36b587d29b75b43fb34c17a22d3981120f3bc5
+Payload = 641c6914920a79943dca39
+CT = 6a962923cee8bfe26393d1377c4e2f20aaa872a9a0b1d1d7f56df0
+
+Count = 116
+Adata = f0c2cc5a1b4c4cbe839338fa0d7a343514801302aef2403530605cf4f44d2811
+Payload = 2286a1eddd80737a724ca9
+CT = 2c0ce1da8162b50c2c15415545aa0c1dd11551891ae553d3a91908
+
+Count = 117
+Adata = 9842922499ad4d487488b3731f48765efe0b4eb59e7b491ba5f6636f09ed564d
+Payload = d8c63e7d7d332198249c0c
+CT = d64c7e4a21d1e7ee7ac5e4d9e07ec5806360843676ef27d811b246
+
+Count = 118
+Adata = 399b71ecb41f4590abda79045cdf6495f27daaa559c1b34f513b5c4ac105ec10
+Payload = 4b81804d777a59b6a107cf
+CT = 450bc07a2b989fc0ff5e27483b8727c5753ede25e1fab0d86963be
+
+Count = 119
+Adata = 2c186c5c3463a4a8bad771feb71e2973c4f6dede2529827707bf4fa40672660f
+Payload = dfc762466fa84c27326e0e
+CT = d14d2271334a8a516c37e64b5c3c1dc577ee8fcf6ef3ebc0783430
+
+[Plen = 12]
+
+Key = d3ad8cda9a0d91a205c4c05665728bb255d50a83403c9ab9243fcbbe95ae7906
+Nonce = 0b5f69697eb1af24e8e6fcb605
+
+Count = 120
+Adata = ea26ea68facdac3c75ba0cdf7b1ad703c9474af83b3fbfc58e548d776b2529b9
+Payload = a203aeb635e195bc33fd42fa
+CT = 62666297a809c982b50722bd56bc555899345e0404b2938edf33168e
+
+Count = 121
+Adata = 0b32069fc7e676f229f1037d3026c93eef199913e426efd786b524ce1dbde543
+Payload = aac414fbad945a49ae178103
+CT = 6aa1d8da307c067728ede1449b15447c904b671824c2ca24c4fc7ad4
+
+Count = 122
+Adata = 7a8658302e5181552292aa56e8209de63b5d86934167549b0d936202681757e1
+Payload = 7ee0ce371329192618e3cda0
+CT = be8502168ec145189e19ade7ea13850e99ef9300c65f5abc9419d13a
+
+Count = 123
+Adata = 4f05600950664d5190a2ebc29c9edb89c20079a4d3e6bc3b27d75e34e2fa3d02
+Payload = b0a1af969a95025385b251af
+CT = 70c463b7077d5e6d034831e8486c93c31bbedc9e5ffa2f4154bceea9
+
+Count = 124
+Adata = 4530e4dc6a4c3733b8ab7e77e384223cc1a8c179fb66818c08aca47e5c705d89
+Payload = 9f6c6d60110fd3782bdf49b0
+CT = 5f09a1418ce78f46ad2529f7f18b556e7da59fd2549dc57a17bf64f8
+
+Count = 125
+Adata = f179353aef342f0f691caf1fcb811e3f6504e14d6d9381c5439b098ff978b01b
+Payload = 90958d7f458d98c48cbb464c
+CT = 50f0415ed865c4fa0a41260b30aad3a838680cbd313004685a5510c5
+
+Count = 126
+Adata = f6df267e5cbc9d2a67b1c0fd762f891ee3b7c435884cb87d8228091b34aeddae
+Payload = 9f7ae892e5662803408d4d06
+CT = 5f1f24b3788e743dc6772d411d57b89ed0c91251aed37a6ca68a50c7
+
+Count = 127
+Adata = 4372e152b1afd99c7f87c8a51dbc3a5c14c49d04ea1c482a45dfbcda54972912
+Payload = 817074e351455f23cb67883d
+CT = 4115b8c2ccad031d4d9de87ad79a3b0feea16ff5fbca16211ea6fdd9
+
+Count = 128
+Adata = 82b6cd1c6618c42ba74e746075dc28700333578131ca6fde6971d2f0c6e31e6a
+Payload = 1b7da3835e074fdf62f1eb3c
+CT = db186fa2c3ef13e1e40b8b7b49f22737c4b2f9fa0a7e3dd4b067fbaa
+
+Count = 129
+Adata = a5422e53975e43168726677930f6d3e13281bdbd13c67c168340ed67e45d15b0
+Payload = 57473e7a105c806867379194
+CT = 9722f25b8db4dc56e1cdf1d3ef43a48dbea8c1547455ad0197af88a2
+
+[Plen = 13]
+
+Key = e300fc7a5b96806382c35af5b2c2e8e26382751b59010d4b1cfc90a4a9cb06df
+Nonce = 55b59eb434dd1ba3723ee0dc72
+
+Count = 130
+Adata = 9b1d85384cb6f47c0b13514a303d4e1d95af4c6442691f314a401135f07829ec
+Payload = 8714eb9ecf8bdb13e919de40f9
+CT = ba6063824d314aa3cbab14b8c54c6520dac0f073856d9b9010b7857736
+
+Count = 131
+Adata = fa17c693d0997140fbc521d39e042d8e08388106874207ca81c85f45c035d6e6
+Payload = a0837676e091213890dc6e0a34
+CT = 9df7fe6a622bb088b26ea4f20820a423dd30796b6016baff106aaef206
+
+Count = 132
+Adata = 27663597b389b78e96c785ca2f5510c8963a5561d2b0b24c4dcdf8e58562c12c
+Payload = b8a2ce7e051b8d094ec43f2a7f
+CT = 85d6466287a11cb96c76f5d2436032bc79c4aef1f74da25e92b0aa7f8a
+
+Count = 133
+Adata = d8f1a83371487d611ce704e0a6731f97a933c43569690022fce33cb5aecdc0a7
+Payload = 9e4103ab1dfb77ae3494507332
+CT = a3358bb79f41e61e16269a8b0e658123d2e5bb324c7ead8897f8e32b0a
+
+Count = 134
+Adata = 05c57aab99f94b315cf8bdd2d6b54440c097fe33c62a96b98b1568cdee4ce62c
+Payload = fb3e3d1b6394d2daebf121f8ac
+CT = c64ab507e12e436ac943eb0090270758ab09f93fa3ba7d7a2aa8eac789
+
+Count = 135
+Adata = 1c1b0933c508c6a8a20846ebd0d0377e24f4abc0c900d3a92bc409ba14ef1434
+Payload = 549ba26a299391538b56ce4bd7
+CT = 69ef2a76ab2900e3a9e404b3eb2293813f1bcb96564f772e9308e42b2d
+
+Count = 136
+Adata = 9f5cf9149f556124d6bb4e3e243cca1502c02682709392cc2ec7eb262fd4d479
+Payload = 287f31e69880823df7798c7970
+CT = 150bb9fa1a3a138dd5cb46814c81877380d5cf097c2fb5177750f8b53a
+
+Count = 137
+Adata = 1a49aaea6fc6fae01a57d2fc207ef9f623dfd0bc2cf736c4a70aaaa0af5dafd3
+Payload = 040d18b128ae4a1935f9509266
+CT = 397990adaa14dba9174b9a6a5acf42c75787edc62a180568c6ef56545d
+
+Count = 138
+Adata = f29a0b2c602ff2cacb587292db301182e6c76c5110b97ca8b706198f0e1dbc26
+Payload = 92441cbe8d70820870bb01ad63
+CT = af3094a20fca13b85209cb555f56d47a0631f2038103e3904b556ba7a5
+
+Count = 139
+Adata = 01fcf5fef50e36175b0510874ea50a4d2005ad5e40e5889b61417700d827251e
+Payload = f11d814df217de96333dee1cbf
+CT = cc69095170ad4f26118f24e4835be15b7ae24edccd0b0934e3af513ed3
+
+[Plen = 14]
+
+Key = 3ae5be5904bae62609ac525e2d1cad90133447573d7b608975a6a2b16cb2efc0
+Nonce = 61bf06b9fa5a450d094f3ddcb5
+
+Count = 140
+Adata = 0245484bcd987787fe97fda6c8ffb6e7058d7b8f7064f27514afaac4048767fd
+Payload = 959403e0771c21a416bd03f38983
+CT = 37a346bc4909965c5497838251826385a52c68914e9d1f63fd297ee6e7ed
+
+Count = 141
+Adata = 52f6a10a022e5ee57eda3fcf53dcf0d922e9a3785b39fad9498327744f2852e4
+Payload = 23fe445efa5bcb318cc85e2ad1ac
+CT = 81c90102c44e7cc9cee2de5b09ad364b603de6afbc2d96d00510894ccbe7
+
+Count = 142
+Adata = d236e3841b9556b32dbd02886724d053a9b8488c5ad1b466b06482a62b79ebb6
+Payload = 762fdc3e0c30c7ecf2ec8808bb79
+CT = d418996232257014b0c6087963781a4321c2ddbc35ce4864457d611219e9
+
+Count = 143
+Adata = 0d2739cfdac782b61f484fa1a423c478c414397ec420327963d79112b2d70a7e
+Payload = b6813d5fe8afa68d646c197337a2
+CT = 14b67803d6ba117526469902efa3296e55efebb17fe145cdca9b31ea7bcc
+
+Count = 144
+Adata = 7f291aa463c4babc76b4a6faf2e27e9401586b1ac83e4b06a4090e94b3ef5fd4
+Payload = 4ce8b6578537215224eb9398c011
+CT = eedff30bbb2296aa66c113e9181059270a0510e7cc1b599705853af2144d
+
+Count = 145
+Adata = 06bca7ef6f91355d19f90bf25590a44a24e5a782f92bc693c031e6de1e948008
+Payload = 9ebf93643854ea5c97a4f38f50bd
+CT = 3c88d63806415da4d58e73fe88bcb55847573bf21e946ce9bdc5f569e3ff
+
+Count = 146
+Adata = 5a44ff94f817c7c028a8f3db35a4d01364d2598432469f09ded86e5127d42d35
+Payload = da989cc7d375ed5fac4d7f938d74
+CT = 78afd99bed605aa7ee67ffe25575b8a61c5687ea02f0276824b8316b76f1
+
+Count = 147
+Adata = 2a755e362373ef27a911c4d93ca07bc97135645442ad7ad6a8ef98146c71e9d7
+Payload = 6fbab5a0f98e21e4d15904af5948
+CT = cd8df0fcc79b961c937384de8149a07ee02791011129fcacffcfb1bf4145
+
+Count = 148
+Adata = f7988873f45a5de314e5381d3f14d8f8c48c9b649bf3e745ed5dc882d507da58
+Payload = b610349e8b370a7c195598573637
+CT = 142771c2b522bd845b7f1826ee36d34204b1ce23f5f58a8eb7cf1fa8cfa7
+
+Count = 149
+Adata = 95d2c8502e28ab3ee2cac52e975c3e7bccb1a93acc33d9c32786f66d6268d198
+Payload = 1d969fd81dab5ced3e6ee70be3bf
+CT = bfa1da8423beeb157c44677a3bbe9c618bb88bbcefb008a5ea6bed4ff949
+
+[Plen = 15]
+
+Key = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Nonce = a5c1b146c82c34b2e6ebeceb58
+
+Count = 150
+Adata = 5e60b02b26e2d5f752eb55ea5f50bb354a6f01b800cea5c815ff0030b8c7d475
+Payload = 54be71705e453177b53c92bbf2ab13
+CT = 788db949697b8cd9abbc74ed9aa40cd6852dc829469368491149d6bb140071
+
+Count = 151
+Adata = 210c04632341fbfc185bfe3cbf6fe272bbe971104173bcb11419b35ab3aaf200
+Payload = 22197f9ad14591e7a6d5f8b18c969a
+CT = 0e2ab7a3e67b2c49b8551ee7e4998556940dc5a7e44bf10234806d00a012b5
+
+Count = 152
+Adata = d3a205dd017e79a67400a937a20ef049f4c40d73311731f03ab857a3f93bd458
+Payload = 096b2f530933c1273304a6ad423726
+CT = 2558e76a3e0d7c892d8440fb2a38390898f7dbde25b0b70d335df71a06987b
+
+Count = 153
+Adata = 0c9b3ba4faf5fc2f310ad1bab06c4ca13474b714feeffb6ad615c1b850bbd6a3
+Payload = d44fdfd9da3a63c1083afe574e91bf
+CT = f87c17e0ed04de6f16ba1801269ea02fd10d1f21b6b963c05aeda8eb09e272
+
+Count = 154
+Adata = d9bb71ad90152d5c1af358c8501fa89ebd4b17bf4ff43841528cccb79fd791b3
+Payload = 8d836acc13ed83c2b2c706415c9679
+CT = a1b0a2f524d33e6cac47e0173499664491d23d90ff55abca17e9d943b98c7f
+
+Count = 155
+Adata = 69dc21eb6f295b12ba493ee8fe6c40d78af946067ce772db316a3cbf00d3c521
+Payload = 2a68e3fe746f593c1b97cb637079c3
+CT = 065b2bc74351e49205172d351876dc9616886c6b2adc97db5a673846b6662c
+
+Count = 156
+Adata = 095eb52135dc6d9c1f56a2571c1389852482e7aa3edc245a3904a0449db24a70
+Payload = 39799b001ed2c334c269acb0f2328c
+CT = 154a533929ec7e9adce94ae69a3d932441dcae1760db90379bd354fa99164e
+
+Count = 157
+Adata = efd7270e0396392fde8b0ddaab00544cbbd504f4d97d4e90d749d1946de90dcb
+Payload = 42143a2b9e1d0b354df3264d08f7b6
+CT = 6e27f212a923b69b5373c01b60f8a9c7c7deb28bdcf84886ef843216b94449
+
+Count = 158
+Adata = 8bc181ce2e66294e803a8dc3834958b5f173bc2123c0726e31f3fca25b622ed6
+Payload = a3dcf26327059a4245b79a38bb8db6
+CT = 8fef3a5a103b27ec5b377c6ed382a935061ae3cd892ba63c44b809d6d29421
+
+Count = 159
+Adata = c39ec70c2c71633ae0dccc41477ac32e47638c885cf59f34ebd4a096d32f91f9
+Payload = 3d54883449ecca8f153436c25a0a01
+CT = 1167400d7ed277210bb4d09432051e3c9ae69a4c59ff8e251c2fe022d065a9
+
+[Plen = 16]
+
+Key = ee8ce187169779d13e443d6428e38b38b55dfb90f0228a8a4e62f8f535806e62
+Nonce = 121642c4218b391c98e6269c8a
+
+Count = 160
+Adata = 718d13e47522ac4cdf3f828063980b6d452fcdcd6e1a1904bf87f548a5fd5a05
+Payload = d15f98f2c6d670f55c78a06648332bc9
+CT = cc17bf8794c843457d899391898ed22a6f9d28fcb64234e1cd793c4144f1da50
+
+Count = 161
+Adata = a371ca29b92ed676bab5dfc4d78631bb6d9bb23a29f822907084a1f0fe17721f
+Payload = 60d55a8d5ab591a51e87fdf6aaa2ad25
+CT = 7d9d7df808aba2153f76ce016b1f54c68b55bbe42d8c97504b97c34a5f16e6a6
+
+Count = 162
+Adata = 01ec87920b42639d4ba22adb1fbe5138d2849db670a2960fd94a399c1532ed75
+Payload = cbf112e4fb85276c4e09649f3de225b2
+CT = d6b93591a99b14dc6ff85768fc5fdc51017d8706acd676ae99e93d5312a4113c
+
+Count = 163
+Adata = eebd2bbf1e9f6d817cd8062a6a9680e7f10464eefeb50b07cb46b14b9b3fcb2c
+Payload = 865b89aa38ee1b5a3ce56620307e8937
+CT = 9b13aedf6af028ea1d1455d7f1c370d45982f0fe5d951a8c62c87894657301e4
+
+Count = 164
+Adata = 72863362612f146699f6b2f6ec3688f2ca6cb1505af7a309c91c1933e34d516a
+Payload = a8efc37d1b8b51f2a47b21dd14da383d
+CT = b5a7e40849956242858a122ad567c1de5addfddbb59f4985947fb3a9ab56333e
+
+Count = 165
+Adata = 9c9efc6593f96207678db813608f2b8bc33ed1bef974ed77ed7b6e74b621b819
+Payload = d9b0eaaff786165f882f41a98dbc0c35
+CT = c4f8cddaa59825efa9de725e4c01f5d6b651053516673402a57538db1a9ce7e9
+
+Count = 166
+Adata = dc482a051b58d8a3904d3af37c37b51983f634a504451bbba6f77d71337f8e78
+Payload = df49d972b6ebbbb18ee975ac635d847e
+CT = c201fe07e4f58801af18465ba2e07d9d86d772b1a1991b7be6589bbccad36171
+
+Count = 167
+Adata = 51ef065a43caa23faf750b02a41ad6ba701aeb8058f6d8738d6f6b005bec7f60
+Payload = 78318aa5cd16699b77bdcea2fc9d1d20
+CT = 6579add09f085a2b564cfd553d20e4c3569387a1a6bcc826e94012670820576e
+
+Count = 168
+Adata = 88e2a74d2920c89c6a101f5f06d0624a6d5eabd9bdb51395ee3983934c55c73d
+Payload = 8e20d65d02dd9a64379f75b6d8328f2d
+CT = 9368f12850c3a9d4166e4641198f76cee9c788b4aae9b2c6caf0c44aa9bd2ed0
+
+Count = 169
+Adata = ada3ed7db2dabbfbc441ef68a5656e628d6d5bd6c1574369688497179a77601a
+Payload = 97e8d8513af41b97801de98cc4269096
+CT = 8aa0ff2468ea2827a1ecda7b059b6975f1df0f01944641a1b04d753e6ab8d3cc
+
+[Plen = 17]
+
+Key = 7da6ef35ad594a09cb74daf27e50a6b30d6b4160cf0de41ee32bbf2a208b911d
+Nonce = 98a32d7fe606583e2906420297
+
+Count = 170
+Adata = 217d130408a738e6a833931e69f8696960c817407301560bbe5fbd92361488b4
+Payload = b0053d1f490809794250d856062d0aaa92
+CT = a6341ee3d60eb34a8a8bc2806d50dd57a3f628ee49a8c2005c7d07d354bf80994d
+
+Count = 171
+Adata = 4ae414bc888a42141d3060c71c2dbbffd425b6a952806982271a8e756b3c9e24
+Payload = 51eb190c6a9f46e8ec1628b090795470c0
+CT = 47da3af0f599fcdb24cd3266fb04838df13c1c5755a5a240c33b2b890a486aac8b
+
+Count = 172
+Adata = 7b7f78ae1a5ee96fdc49dacd71be1a6ac09a6a162d44dea0172886eca5674e46
+Payload = 25144e807e389bb0e45b6dc25558caf61a
+CT = 33256d7ce13e21832c8077143e251d0b2b4cfca1c19abf447d7bc0898d61885144
+
+Count = 173
+Adata = 03f31c6143b77f6ad44749e2256306b8bf82242f2821fad4075b09b388ba81ca
+Payload = dbe1ee14abfe2ecf4edf6db206cf9886ce
+CT = cdd0cde834f894fc860477646db24f7bff229cc7a390867a245dcb7c434f1db347
+
+Count = 174
+Adata = 030390adb572f2bd2a6a4454fd68236cd1d465574328aa001d553375cc63f8a2
+Payload = db6df31f12bf552f81deff5fa2a373fc22
+CT = cd5cd0e38db9ef1c4905e589c9dea401135361b539f9fe0fb7842907c2326aef63
+
+Count = 175
+Adata = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a7b9bb2bd99392c8a
+Payload = ff2a97b49fcc6a50d4549c979d53ccc51f
+CT = e91bb44800cad0631c8f8641f62e1b382e8ed10943929e7d7bf798b2ae8371aae5
+
+Count = 176
+Adata = 4d1513478fc1fb0a18eb6d2a9324fefbd975ecd1b409025de826bc397462acc1
+Payload = 73ddfa0185200a890b7690a7e3986d8818
+CT = 65ecd9fd1a26b0bac3ad8a7188e5ba7529f92b9e49ab83f113f8949dc9e4a36e0d
+
+Count = 177
+Adata = b26a7ff61bfe94864249af7cc9b4a723627dd4463f5a22f0ca6063769522eab7
+Payload = 5c7604f9ac8fdf30ee5820e5aeb75b65d7
+CT = 4a4727053389650326833a33c5ca8c98e6d0e53223adff22a08e3dddf66fff23e3
+
+Count = 178
+Adata = 960f9a85cfbfb6eab223a4139c72ce926a680ea8e8ecc3088cf123de659ad310
+Payload = d44fdfd9da3a63c1083afe574e91bf01c9
+CT = c27efc25453cd9f2c0e1e48125ec68fcf833f49a42521a7a2367f91bfcc2180b7c
+
+Count = 179
+Adata = 3718467effb5d5dc009aaefce84d8cb4fe8f80eb608f4c678f5d0de02ea11e59
+Payload = bb515dc227abb9acad8fefaa14771bb77b
+CT = ad607e3eb8ad039f6554f57c7f0acc4a4ac08bd395c6807223311070659f550934
+
+[Plen = 18]
+
+Key = 0786706f680c27b792d054faa63f499a8e6b5ddb90502946235bf74c022d772c
+Nonce = f61ef1c8c10a863efeb4a1de86
+
+Count = 180
+Adata = 67874c808600a27fcab34d6f69cc5c730831ad4589075dd82479823cb9b41dc3
+Payload = 6a26677836d65bd0d35a027d278b2534e7df
+CT = d1c1f3c60603359c7d6a707f05ecb2296f8e52f2210b7a798ad5c778ee7cfd7fe6e0
+
+Count = 181
+Adata = e0c27cddf919d3092d9a34766c89a5ae6dcf39fe954d1e6f1a70ddf96805def4
+Payload = 4021ff104ff1dbd91e46db249fd82198b0a1
+CT = fbc66bae7f24b595b076a926bdbfb68538f00923bb5a347af13df12f234fca5f03ef
+
+Count = 182
+Adata = 7ae9eca03f616ab39ebb3be26b848842b4aa584e5c8e5695065ad5af34951175
+Payload = 6a681f164efce199a787bccff223b8ae1a98
+CT = d18f8ba87e298fd509b7cecdd0442fb392c9d03ed7bffac83e890caceb6903d9cab5
+
+Count = 183
+Adata = b47c9bc4eb01c74f5db2e6a293bef80db18c58cf06feef7ee0f8a7a9a51c22bb
+Payload = 7861dac338ba3f8274dca04c8c6f92b6d44c
+CT = c3864e7d086f51cedaecd24eae0805ab5c1d4dd8f30870025b2bd1e2a2511574d3e7
+
+Count = 184
+Adata = f6afd661f218c7426b92ee53e65d14898cd0c78a7e594fcc6ac0e3fb5cab1c9c
+Payload = a3f0473c620d2739d5ba4f7156f88d0fb669
+CT = 1817d38252d849757b8a3d73749f1a123e386046d17f337f3cb49884d94995edbdc9
+
+Count = 185
+Adata = d3802911e341577046cfc61d9043b4af059fb4bef3c6a2ff46ccdcb05670af37
+Payload = 07c535d9456a6ff1e41321150d16dae3f7a3
+CT = bc22a16775bf01bd4a2353172f714dfe7ff25fdc77b43bca254d6459263cdfed8fbb
+
+Count = 186
+Adata = db60720db67a60ca286fe744d46173c231fbcc7deb4c9b0d87d52a2247e06b74
+Payload = 5ee220720a896249efdab2ce418318bb5ebf
+CT = e505b4cc3a5c0c0541eac0cc63e48fa6d6eedd1a1d36c8164c55d55dbf0ff1e9517a
+
+Count = 187
+Adata = 57f70ba5493265b30491decc726354e2065e7971a2efd56db9cf0f79b1d76859
+Payload = 98e4eb0361c8bf40bcbe0539b0850e4c35ff
+CT = 23037fbd511dd10c128e773b92e29951bdaeb476e2ca48fd52bec0539b00744a8a07
+
+Count = 188
+Adata = 4a29b9ad548964942f87f28ba267ec0d0e8f72c73b3823ee57693dd63c2605c1
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72
+CT = c4e0d10096f1178ca63ebcc70c5056fea523fad68c62b81d62f2d490ae74f5bb1465
+
+Count = 189
+Adata = acbd2e9911b3218a230d9db5086d91dccac3fc93fc64b0f4a15d56954906b2b7
+Payload = e99ed2ac6c38e033061b5d85f3e77dd72518
+CT = 527946125ced8e7fa82b2f87d180eacaad4913b15d8000266c61ba5aec898eb35b52
+
+[Plen = 19]
+
+Key = bac55f9847d93325bf5071c220c0a3dfeb38f214292d47b4acb7b0a597fe056f
+Nonce = 05b50c458adbba16c55fcc454d
+
+Count = 190
+Adata = 89ad6ae1e550975eaa916a62615e6b6a66366a17a7e06380a95ea5cdcc1d3302
+Payload = c1a994dc198f5676ea85801cd27cc8f47267ec
+CT = 7c9b138177590edaafec4728c4663e77458ffbe3243faec177de4a2e4a293952073e43
+
+Count = 191
+Adata = dfddb719d00398bf48a6cefd27736389e654a93b8595cd5ac446af1996e0f161
+Payload = 791e232bfb42fb18197adc1967da1a83f70168
+CT = c42ca4769594a3b45c131b2d71c0ec00c0e97f8422f736fc435687634d42254b22fd99
+
+Count = 192
+Adata = 58ef310997dcaf067dd217274921504da6dbf0428a2b48a65fe8a02c616ac306
+Payload = 3d4127942459bb8682e662dfc862467582fa68
+CT = 8073a0c94a8fe32ac78fa5ebde78b0f6b5127f38a96e68ef7dbaef1b460cc0980eacd4
+
+Count = 193
+Adata = 511e5d5e100b595f6b20e791830bca37e23f7b785e482a58405bffe7a632a5b8
+Payload = 0e71863c2962244c7d1a28fc755f0c73e5cbd6
+CT = b343016147b47ce03873efc86345faf0d223c15c5c702a82d468929227502e4e35796f
+
+Count = 194
+Adata = e48dfaa53b6807ea6f01d8dca67960b9f321f7851f324459a9bf61fe0be73abb
+Payload = e0f1cd013e6aea4fa484fc3fa35d348b1a2399
+CT = 5dc34a5c50bcb2e3e1ed3b0bb547c2082dcb8e89188c0940182dd99a902d158c5b0810
+
+Count = 195
+Adata = c12c0423fe36e4c88775dd00b4af267b85b7dd2a37a742a3156923c8917c97a3
+Payload = b1cc1946b4fc1dbd033254cdf536f61e9f9cd7
+CT = 0cfe9e1bda2a4511465b93f9e32c009da874c015849acbb7af1892790300bb84fb0558
+
+Count = 196
+Adata = 4255f8af18df7237e0abe98421aec9634443561752d893aaffe76380e829ef32
+Payload = 87284658928208e3bddca83e3ceb13708d88d4
+CT = 3a1ac105fc54504ff8b56f0a2af1e5f3ba60c3e75aaf3077ac6dfb5454851ec3910de6
+
+Count = 197
+Adata = ab83567833d2f3461b5fbecc0e366694bb5ea00933b2b3e792ec3aefe20325df
+Payload = bdb79f931ef3035a33bdd1b032fd9de8f6b2ba
+CT = 008518ce70255bf676d4168424e76b6bc15aade70f42e3e1f2b5bb58433bd11f5dea1f
+
+Count = 198
+Adata = bd1446ba3185d1c16551730947c22142142caa8cc1c540e89ab734ec297401bc
+Payload = 1f9c3a8eb8bc59f3869e10f73883aa8f8990cb
+CT = a2aebdd3d66a015fc3f7d7c32e995c0cbe78dc564f6248cefe5fc7cfb547c90a558925
+
+Count = 199
+Adata = b87577755d2d9489194f6f7cfabf267dc3433a9c91954e81beb72c5e06870922
+Payload = 5f28809181f9a889894da8d6fe1fde6cce354a
+CT = e21a07ccef2ff025cc246fe2e80528eff9dd5db52249d812f7f235afa0732e984e91b2
+
+[Plen = 20]
+
+Key = 8beedeb85d42c2a7fa6f7237b05acb197dd8e1672471ac878064fe5319eab876
+Nonce = 8479bdfad28ebe781e9c01a3f6
+
+Count = 200
+Adata = 7aebdfd955d6e8a19a701d387447a4bdd59a9382156ab0c0dcd37b89419d6eff
+Payload = 7b125c3b9612a8b554913d0384f4795c90cd387c
+CT = 6cc611d816b18c6847b348e46a4119465104254a04e2dfeeeac9c3255f6227704848d5b2
+
+Count = 201
+Adata = d119f300fbd74e754a200ea2c3f9fabc1466d02078c84245db693eef3f5672a6
+Payload = 8b013f5782d5d1af8dbd451a4202866095dac975
+CT = 9cd572b40276f5729e9f30fdacb7e67a5413d44338d48329997c5981d678b5e24a6f01b0
+
+Count = 202
+Adata = d6204303b86acf62d5ab860ca70161288ede56e3cf017c08dca56fd2d6f8f6fe
+Payload = b2b1d82a5523b72ea366a680922ed3a4624536c4
+CT = a56595c9d58093f3b044d3677c9bb3bea38c2bf2a77e3ab68e0a73519591a33ed098b758
+
+Count = 203
+Adata = 8557e22eb4529b43f16b1f8ae47c714ac8a2c827c1408a47704778b4c5b52601
+Payload = f8c4eb4285d3d7744da52775bb44ca436a3154f7
+CT = ef10a6a10570f3a95e87529255f1aa59abf849c1cff6c24251c2fb7b8604dfa10c60ef4a
+
+Count = 204
+Adata = 8c1a4187efbb3d38332f608f2c8bbe64247d9afa2281ced56c586ecb4ab7a85e
+Payload = 6e7fe35fa39c937a0e6b3a8c072e218650f42b8d
+CT = 79abaebc233fb7a71d494f6be99b419c913d36bb6c3c39f915d081d34559179869b32d81
+
+Count = 205
+Adata = a41bb1f256228302cd0548ae2148ff42774d18c2d6d3e38b36bc4938da13bac3
+Payload = 917b467d841850fc6e648f1bc298a7f9f1ee38ca
+CT = 86af0b9e04bb74217d46fafc2c2dc7e3302725fc9389a6a6a74c6eb0e1f87562469f2082
+
+Count = 206
+Adata = b0b024e20c4f75a6dad54c21a9edbce846792e957878b1c8ed2d916c757e2b3c
+Payload = 2b4314fe1a6bfa786b7cfc13fbee861b348efbf6
+CT = 3c97591d9ac8dea5785e89f4155be601f547e6c03bed3a2f5dfdbfcc0d7ac26c88d1962c
+
+Count = 207
+Adata = 42153925c46fc9d5d328312d62f59bb99fdc4ac479a3386d5f88fefd4b32f577
+Payload = e19fa7f83c79920cbff45c41a9dee8fc99e97396
+CT = f64bea1bbcdab6d1acd629a6476b88e658206ea035ea1d99be344fa1467ee91c73bbca67
+
+Count = 208
+Adata = 37ab2a0b7b69942278e21032fc83eba6cdc34f5285a8b711a08da6acd42299fe
+Payload = 53e0475cf492b3d39dad600f5c58eb0bd0021554
+CT = 44340abf7431970e8e8f15e8b2ed8b1111cb08627936ec10a81b36768b606e9a38b2f4c5
+
+Count = 209
+Adata = 4a17522da707b4b2587a0ae367a2cd2831bb593a18ef442a7977eda6de045878
+Payload = c119a383d9a3d4bff4270a1d22076b346db5f61c
+CT = d6cdee605900f062e7057ffaccb20b2eac7ceb2a11575ae03ea8a57bbe4a67c060367b74
+
+[Plen = 21]
+
+Key = c3a0c126cad581012151c25cf85a44472c23f83b6095b6004f4f32cd60ec2db2
+Nonce = 94ab51ce75db8b046d6ab92830
+
+Count = 210
+Adata = 2a243246bfe5b5ab05f51bf5f401af52d5bbaa2549cf57a18e197597fe15dd8c
+Payload = 73b09d18554471309141aa33b687f9248b50fe3154
+CT = b7e8264ca70fd2a4fb76f20a8ad5da3c37f5893fb12abeeaef1187f815ca481ed8ddd3dd37
+
+Count = 211
+Adata = 0595306eb7441622a49800edee0134492d82320707fceba902af2e0c95fe634a
+Payload = b64d00f3a4df754fa4ee6376922fb67ccce0c6209f
+CT = 7215bba75694d6dbced93b4fae7d95647045b12e7accc2b55011dbe92ce7619e0ad48b4ccf
+
+Count = 212
+Adata = bd439dbefec589e120fb4f9825b315bf86523b85c61791cd4da4c8d474ba2714
+Payload = 2b11d1ac74ffe701ec733d32085b1054132726e622
+CT = ef496af886b444958644650b3409334caf8251e8c71e8b1f4d70d8f4c7df4f22847d36b394
+
+Count = 213
+Adata = cfebe1cf82267394065bcecfada6709c6c35a3ac835644f560d4c9a8c1848364
+Payload = a88f22424643a523aa3d7d88f4364f1290f49dd0a2
+CT = 6cd79916b40806b7c00a25b1c8646c0a2c51eade47a85e76a9d07b7b361ca56d53c34cda50
+
+Count = 214
+Adata = 7a37255b682766a0bfecf78e5162528885a339174c2a49325739d2bd8877e64f
+Payload = c81427bc84c6a3cfefd4c4cb210fe82212977e1947
+CT = 0c4c9ce8768d005b85e39cf21d5dcb3aae320917a2fddb010e7508ad03ad287068ecee6020
+
+Count = 215
+Adata = 619f2ae80070e278615466a3fd6c9acb7b510c5679bed7038889c77e78d8bd32
+Payload = 28c4d6de3e2ce51b849b135d9cfd3084f0e3155447
+CT = ec9c6d8acc67468feeac4b64a0af139c4c46625aa2ddea785e6c470c52c4fdf432fd78b66e
+
+Count = 216
+Adata = b2571e56f66a857daffbdc99370ceddd4a7bed3867d600cc797000a3b7b57a9d
+Payload = 4c88151cafef75832bacef43a06e862349d56b67ee
+CT = 88d0ae485da4d617419bb77a9c3ca53bf5701c690b91232cfbd7ffff252498b35274fb2995
+
+Count = 217
+Adata = db409636e3e3bcd606a91aeb7592009896f9ad2c4cc6b7f578e6ad59c0f8fa22
+Payload = 572855e22ce89bc2bcf09cb15a1765d99973449d61
+CT = 9370eeb6dea33856d6c7c488664546c125d633938472b2c50e5e391ad104f9ee33b94f2872
+
+Count = 218
+Adata = 62c89a835721207a182968c516dc8be45774ec846e8dcab9ab8611888f2a76a8
+Payload = 89ce46b3de3afaf2518d419b1a2ac24cabca269a96
+CT = 4d96fde72c7159663bba19a22678e154176f5194732d69c5d6db1b130102af3dae0690673b
+
+Count = 219
+Adata = 33f30ddd83002eea50fd4a8fae39d0980a04160a22ac88b755ac050f1d1f8639
+Payload = edf1682a626e9fbf3d57bb260e0876c6f92ba5b114
+CT = 29a9d37e90253c2b5760e31f325a55de458ed2bff1489903365970c2673c9fd457e1077aad
+
+[Plen = 22]
+
+Key = 9cdebaeee8690b68751070691f49593668a6de12d3a948b38ddbd3f75218b2d4
+Nonce = af1a97d43151f5ea9c48ad36a3
+
+Count = 220
+Adata = f5353fb6bfc8f09d556158132d6cbb97d9045eacdc71f782bcef62d258b1950a
+Payload = 3cbb08f133270e4454bcaaa0f20f6d63c38b6572e766
+CT = 3966930a2ae8fdd8f40e7007f3fde0bd6eb48a46e6d26eef83da9f6384b1a2bda10790dadb3f
+
+Count = 221
+Adata = e3a1555ffe5f34bb43c4a2dae9019b19f1e44a45fb577d495d2a57097612448d
+Payload = 946e86795c332031e2d1ee09d3d4a101fb6800d00911
+CT = 91b31d8245fcd3ad426334aed2262cdf5657efe408a5587bdd120a7d08cd3841cb117af444fb
+
+Count = 222
+Adata = 9c5d43c1a1269cde199509a1eff67cc83a1759b71c9e7a6ee99f76b98c6e23a6
+Payload = b76ce2ab0065ba1c0a754494991c8c452cb416f18ab1
+CT = b2b1795019aa4980aac79e3398ee019b818bf9c58b0545b32f81dcf03e2bcc2aaf62ad366e97
+
+Count = 223
+Adata = b07452a7900a289b91b2771dfdd5108852536659aa259def7b41e38f80bd03ab
+Payload = a3e0d8d0784155bfc45769c52711d4fa68e8bc390c20
+CT = a63d432b618ea62364e5b36226e35924c5d7530d0d94fea17d78533bc9e022dbfb460afdf499
+
+Count = 224
+Adata = 6b30f55c3101540523a92380390f3f84632f42962061b2724cde78ac39809397
+Payload = 6e6a88abbb52a709b47365ad6aa8016fa9a03a9bd834
+CT = 6bb71350a29d549514c1bf0a6b5a8cb1049fd5afd98056defc6dcaeec80b1c639350ab6f1fde
+
+Count = 225
+Adata = 9fc62d14f8b7a6026509275cff80312ff1ade2b5d9c274cb72a506a571439fc1
+Payload = eba1810d537041821121aeff8e0914ac26a550072c8c
+CT = ee7c1af64abfb21eb19374588ffb99728b9abf332d389d37b7251fb8c0ef2b37c36d51219d0f
+
+Count = 226
+Adata = 6b9389cc42113d639fd2b40cbc732ae0dc7c14513b88b36b45a6ea5a06fe4d2b
+Payload = dfc6692cd2442e5ff1f918c8812a27f81d107d16a12f
+CT = da1bf2d7cb8bddc3514bc26f80d8aa26b02f9222a09bd279d9da4437c8a2a252436508134c56
+
+Count = 227
+Adata = db72d98d63fc10acff7dceec0e2691a80ecee50a0e957ad166c77952a50318bd
+Payload = 9ad338cbfd1b52e6ae4178f05e00062274f8b0b25eae
+CT = 9f0ea330e4d4a17a0ef3a2575ff28bfcd9c75f865f1a63943543bc1c5f5991ecc5964a288f79
+
+Count = 228
+Adata = e98b710c47a4d12a73cd8aa2613fc2910c16f4195ea7f15650132493521d19be
+Payload = 9f5a05db89e0e336da066ce81b79ad9be1d0ec4fb7b8
+CT = 9a879e20902f10aa7ab4b64f1a8b20454cef037bb60c0a49ee2b7ceddcbd28abb24b77d5edee
+
+Count = 229
+Adata = 527817316fc48b105f8ab178dd2db1fefa09c50461aa9d8bdf3c03482343bbf9
+Payload = 58f31e5770070a5d4031fb795dc2d298561d3559960d
+CT = 5d2e85ac69c8f9c1e08321de5c305f46fb22da6d97b9b099a68cfa3572d974e03232e09f37fb
+
+[Plen = 23]
+
+Key = d34264a12c35cdd67ac105e2826b071e46f8131d1e325f8e0ae80a6447375135
+Nonce = 3891e308b9f44c5b5a8b59004a
+
+Count = 230
+Adata = 0cda000ed754456a844c9ed61843deea9dadf5e723ea1448057712996d660f8c
+Payload = 79ac1a6a9eca5e07ce635bfd666ef72b16f3f2e140d56c
+CT = 1abcc9b1649deaa0bfa7dcd23508282d9c50ca7fee72486950608d7bcb39dcf03a2cab01587f61
+
+Count = 231
+Adata = 3fb6ddb76809b8e6d703347664ef00a365955124c603900d5c8d4ff476138252
+Payload = 76d12e3c4c5d990bf563c60aa4999e52998d887f97477f
+CT = 15c1fde7b60a2dac84a74125f7ff4154132eb0e139e05b1c4fb40e5c8bc37152a173d4bbb18c3e
+
+Count = 232
+Adata = d9fc295082e8f48569eb073ac1b9566246728fc62ccaab4a5667c472c98b2626
+Payload = a027c28fbe22111fd4c8a226cfe8531c16d7790d561eca
+CT = c33711544475a5b8a50c25099c8e8c1a9c744193f8b9ee019c359008adae3070b5a543ead0effb
+
+Count = 233
+Adata = 7a459aadb48f1a528edae71fcf698b84ed64dc0e18cc23f27ab47eeabeaf833f
+Payload = fa597e37c26c38694abdcf450f9edc529160fa0d651979
+CT = 9949adec383b8cce3b79486a5cf803541bc3c293cbbe5dbd099ab134756b90746762a92a4a9f7f
+
+Count = 234
+Adata = 484207909dec4c35929ebe82fcacf20d2af6d850bd69364ebac9557adeadfbd4
+Payload = 9e4c8aa9b58a8eabc5586892f5541000b43f17d9a051a0
+CT = fd5c59724fdd3a0cb49cefbda632cf063e9c2f470ef684fa4f6adfec85d055310107ba89198afa
+
+Count = 235
+Adata = 88b5448372548e6aab1b262630a28a471d285514703f1bdb10c695850e18fe6d
+Payload = 7d9582cf9e3bb9ee34dce965f56b08e716589486b0641c
+CT = 1e855114646c0d4945186e4aa60dd7e19cfbac181ec338915d23eb2e952afcc89fbddb567d9d75
+
+Count = 236
+Adata = 0e71863c2962244c7d1a28fc755f0c73e5cbd630a8dbdeb38842d7795d830d2e
+Payload = 5a387e7cc22491fc556fe6a0c060b4911d01f0c11f801e
+CT = 3928ada73873255b24ab618f93066b9797a2c85fb1273aaad6c31828314e24198f005955ca8f5e
+
+Count = 237
+Adata = 2aa7a28da38c42fda2e578d9d6340cd8e80b9b32047c3db296d0640d517b0872
+Payload = 87946e910059cbaf48df63b220f397049c65ca10cd1920
+CT = e484bd4afa0e7f08391be49d7395480216c6f28e63be04e531ebbadccfe47182b41904bbfebcfe
+
+Count = 238
+Adata = 3382051c268891da04e6ca73adcead4029f6a1593be4acfe3968e7351a6a2fb5
+Payload = c62f67d208f1c8ffd5d57df9de15ef54f97fbc07d1630a
+CT = a53fb409f2a67c58a411fad68d73305273dc84997fc42e7c582414154236c09ee704cf4a5de411
+
+Count = 239
+Adata = c352828b1920e53bbb60f2ea6a5f15639659e6f3243405c26f6e48628d5519a9
+Payload = 697e73eaaf562d31bdbf7ce9e78c7426fe1c87e421def9
+CT = 0a6ea03155019996cc7bfbc6b4eaab2074bfbf7a8f79dd57c9990029c89d1b37988745fa5737a3
+
+[Plen = 24]
+
+Key = 4ad98dbef0fb2a188b6c49a859c920967214b998435a00b93d931b5acecaf976
+Nonce = 00d772b07788536b688ff2b84a
+
+Count = 240
+Adata = 5f8b1400920891e8057639618183c9c847821c1aae79f2a90d75f114db21e975
+Payload = 9cea3b061e5c402d48497ea4948d75b8af7746d4e570c848
+CT = f28ec535c2d834963c85814ec4173c0b8983dff8dc4a2d4e0f73bfb28ad42aa8f75f549a93594dd4
+
+Count = 241
+Adata = 1ae8108f216defea65d9426da8f8746a3ae408e563d62203063d49bf7e0d6bdf
+Payload = 2b223932fb2fd8433e4b1af9e8234a824569a141f6c96a69
+CT = 4546c70127abacf84a87e513b8b90331639d386dcff38f6f4de907a59c5e4d3f21e1348d7cdf92b6
+
+Count = 242
+Adata = 460f08114b1015fe8b7a9b5dd1b9e6a3d28367c4bd15f29b13c02a8cb9a53968
+Payload = 4d57cbe4a7e780d4ed17267d5ebc91750c2f0209e0444bd2
+CT = 233335d77b63f46f99dbd9970e26d8c62adb9b25d97eaed4ff4239544e2f354d6c6837cd9c23b884
+
+Count = 243
+Adata = 860f4428259d9c5b17698cc95363db6cfee603258582e3a3e8feb886599d4ac4
+Payload = fda8665f87c618646a89c7abdca275fd10c31453ad4b9c99
+CT = 93cc986c5b426cdf1e4538418c383c4e36378d7f9471799f3f6c6f7cc494201069344e2d6d41bd9b
+
+Count = 244
+Adata = 1b43c482f83780c21583f88e5afcf6938edd20f21b74d895161b60c27a6a42f0
+Payload = 98104fd3f3413ad1f57ef4912cb50097dca379a58c47b0d2
+CT = f674b1e02fc54e6a81b20b7b7c2f4924fa57e089b57d55d43787a15352cfceb028202c8730beaa7a
+
+Count = 245
+Adata = b082ccd964617c27a5607b7324faad237ee53acfc18c35502dbf7c1937a9dfcb
+Payload = b46b343e64d2d70e0bd909dbb3f6bedf7e4adc74321be526
+CT = da0fca0db856a3b57f15f631e36cf76c58be45580b210020f3a0ca3da647eb31893e867956097983
+
+Count = 246
+Adata = b8539ba93ef17254ec1d8d62e8f4eae4d41ee1e75345bf90c9cbb26c63bce501
+Payload = 8e12620bb575e6b167b085255b2b5631ff28e04cbef8826d
+CT = e0769c3869f1920a137c7acf0bb11f82d9dc796087c2676be663fbbebbc251b9f1760afa49e89e71
+
+Count = 247
+Adata = b6b09463b5ef5ead1f17f4021693a0d8452e98dcbb8e7590f9fde6394970a6f8
+Payload = 792aaa23b923d1b53173fe19853b9aa402a301d48529873e
+CT = 174e541065a7a50e45bf01f3d5a1d317245798f8bc136238da90cd87e9d9ca5d85430a150e682752
+
+Count = 248
+Adata = 390f6de14d5e1f2f78dbe757c00b89209d0cf8bc48cbbea035779f93de357905
+Payload = ddc5b4e48970ebd72869be6998e9103c014475e8ae6ea29c
+CT = b3a14ad755f49f6c5ca54183c873598f27b0ecc49754479afc0cc4601afb61efa7059cfe49ec9dde
+
+Count = 249
+Adata = 1d75c9e7acb09932db332498d30f82e4009025cb1827047c59a8f97812b568a4
+Payload = d2b66096c475a77648c27235e6972ba8f18761330d3c6adf
+CT = bcd29ea518f1d3cd3c0e8ddfb60d621bd773f81f34068fd9cf7474962c3602dcfcb50039f43e3d6f
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp
new file mode 100644
index 0000000000..a05492b485
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT128.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 128
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 43b1a6bc8d0d22d6d1ca95c18593cca5
+Nonce = 9882578e750b9682c6ca7f8f86
+
+Count = 0
+Adata = 2084f3861c9ad0ccee7c63a7e05aece5db8b34bd8724cc06b4ca99a7f9c4914f
+Payload = a2b381c7d1545c408fe29817a21dc435a154c87256346b05
+CT = cc69ed76985e0ed4c8365a72775e5a19bfccc71aeb116c85a8c74677
+
+Count = 1
+Adata = 79db716e6b0b1627890d378c4560eba7871883d94527be3454dc3c257ea93556
+Payload = 47f4cdd574264f48716d02d616cf27c759fdf787cdcd43b1
+CT = 292ea1643d2c1ddc36b9c0b3c38cb9eb4765f8ef70e84431676e2df1
+
+Count = 2
+Adata = 0d02778f90a164a4f9ada9dc7fd24eeb941069621418ef32c3f9ca6bf6fb2c4a
+Payload = 5eadeaec29561244ede706b6eb30a1c371d74450a105c3f9
+CT = 3077865d605c40d0aa33c4d33e733fef6f4f4b381c20c479eb1321a1
+
+Count = 3
+Adata = 02e5a1306f612bdec098458cff3e691d93f050ba11ba627355dc7029d2cea5ab
+Payload = aac9fb69fed114c62db65090947096a2f5c85c271c6a6d53
+CT = c41397d8b7db46526a6292f54133088eeb50534fa14f6ad3dd8cb4ca
+
+Count = 4
+Adata = 25144e807e389bb0e45b6dc25558caf61a2263869c4d0e4079d07674d7091110
+Payload = fb6e8d38ce38a8c1e710f3a33c682e6dabf055fb33fe75f8
+CT = 95b4e1898732fa55a0c431c6e92bb041b5685a938edb7278b659a844
+
+Count = 5
+Adata = be303c1ed9327ad88dae7cb5930b5a786d4f5477ef9370a9fdb56501964cb8fa
+Payload = 87d81389a6062e8ed501ea964c2fe35b2d3de9fd676c04f7
+CT = e9027f38ef0c7c1a92d528f3996c7d7733a5e695da490377e9e5e005
+
+Count = 6
+Adata = 46dfb8f3e06c3f168e5ac9b341e7710d7b9c6a19b32389eafb58036de0a27756
+Payload = e1bd9095fa9bb811e4054643feea3eac13fb57b43a0502a0
+CT = 8f67fc24b391ea85a3d184262ba9a0800d6358dc87200520c9fc48e0
+
+Count = 7
+Adata = 19eb03c35c352b79e8c32fa40bb9759b0565e04a6c18519ace346e2e9987a250
+Payload = 92f7dc22dcbbe6420aca303bd586e5a24f4c3ed923a6ebe0
+CT = fc2db09395b1b4d64d1ef25e00c57b8e51d431b19e83ec60ac73022c
+
+Count = 8
+Adata = efa6ddd6fb8e4480a0f64414694e5f9e7f2e9b97cbe9cd145b65173d072ab001
+Payload = cecdf831c4044c8fe149e4cd579a1aecf222bf8e9dadba09
+CT = a01794808d0e1e1ba69d26a882d984c0ecbab0e62088bd895dc8d581
+
+Count = 9
+Adata = 1b156d7e2bf7c9a25ad91cff7b0b02161cb78ff9162286b0622fccda2e251c97
+Payload = 7cfb0973ea13dedc33ef6728db90f47559273ea6d3cd4db6
+CT = 122165c2a3198c48743ba54d0ed36a5947bf31ce6ee84a36b941b65b
+
+[Tlen = 6]
+
+Key = 44e89189b815b4649c4e9b38c4275a5a
+Nonce = 374c83e94384061ac01963f88d
+
+Count = 10
+Adata = cd149d17dba7ec50000b8c5390d114697fafb61025301f4e3eaa9f4535718a08
+Payload = 8db6ae1eb959963931d1c5224f29ef50019d2b0db7f5f76f
+CT = df952dce0f843374d33da94c969eff07b7bc2418ca9ee01e32bc2ffa8600
+
+Count = 11
+Adata = 463c65fa7becae5605af80d1feca59075ee88c0abfc72cb463312b3c772ec308
+Payload = bde3fc83287ddd1227bdab4305102c94d885412eb332bf6b
+CT = efc07f539ea0785fc551c72ddca73cc36ea44e3bce59a81a8b847d3a0c98
+
+Count = 12
+Adata = ab153b0a8933f2eb0d721621c86de0cfe100d13e09654824b09d54277912c79d
+Payload = 82176e573c6070faa08d18b5957f119bb1ff51d744b04240
+CT = d034ed878abdd5b7426174db4cc801cc07de5ec239db5531fb4f9d559a8e
+
+Count = 13
+Adata = b22aba8d3e9f4b4bf006e26062de15daf94597731a6009129bfd12957877b1ce
+Payload = bcfc4485eaf225d945146374b737cdf5301c7738ea9f142a
+CT = eedfc7555c2f8094a7f80f1a6e80dda2863d782d97f4035b1e09ff3d6a6c
+
+Count = 14
+Adata = eb80a43c5986deee6925d7c6d53cbdcbe11194843ea133f72d3590d8e8363efa
+Payload = aa182e3ec4fb2f7a905c03582b2ee100ab81a9a311a778bc
+CT = f83badee72268a3772b06f36f299f1571da0a6b66ccc6fcdb60ba1175f1b
+
+Count = 15
+Adata = 3ee186594f110fb788a8bf8aa8be5d4ad52d6e3bd5f406f080d9df0d7553a851
+Payload = 8ad6db8216af16bfda3261a220d078cc98c8ad134e4a80ca
+CT = d8f55852a072b3f238de0dccf967689b2ee9a206332197bb4a75860f3dd6
+
+Count = 16
+Adata = d36fc18b5b12662ff5f6ea55af7c7a82d25d386220e399a85a590b1505c0dcd5
+Payload = a65d24bd1ab92d8d294d654423412860e113c976f12ed76b
+CT = f47ea76dac6488c0cba1092afaf638375732c6638c45c01a00cf106d70a4
+
+Count = 17
+Adata = f0028503e7cd54474c56dc8b2416fe41f416eed73c63ddd141bdd51a0f8fe49c
+Payload = 6e9dc61dd9cf19a6eebc10c9b51c13970636de2c9ea33592
+CT = 3cbe45cd6f12bceb0c507ca76cab03c0b017d139e3c822e3c0193a87ddfb
+
+Count = 18
+Adata = 9a58a226a578bda012dbd7d04b11c879179aaaa36c6145418586cb103360c6c2
+Payload = b526896c11e514b5b4c26351859e2a33800fefd6fd9e6d1a
+CT = e7050abca738b1f8562e0f3f5c293a64362ee0c380f57a6b444d9b63ffab
+
+Count = 19
+Adata = c015fb08540755a8a8adc387d60553478667158964202eb2d25e28efd94c8c76
+Payload = 88907b639f3fd07f40bf6b9b6334b11b2852557975721bf3
+CT = dab3f8b329e27532a25307f5ba83a14c9e735a6c08190c82c339ba21fcf7
+
+[Tlen = 8]
+
+Key = 368f35a1f80eaaacd6bb136609389727
+Nonce = 842a8445847502ea77363a16b6
+
+Count = 20
+Adata = 34396dfcfa6f742aea7040976bd596497a7a6fa4fb85ee8e4ca394d02095b7bf
+Payload = 1cccd55825316a94c5979e049310d1d717cdfb7624289dac
+CT = 1a58094f0e8c6035a5584bfa8d1009c5f78fd2ca487ff222f6d1d897d6051618
+
+Count = 21
+Adata = 25865c1b89f1973bfa680d8458df35a56993a7e81e407e061794004068e481ab
+Payload = 36004342dd74e7966692a848b2c11e1fc311eac9d9cef616
+CT = 30949f55f6c9ed37065d7db6acc1c60d2353c375b5999998ceca422687f41550
+
+Count = 22
+Adata = e6209480da9e49172ba58a9048f2f1b0349030e8e7a79dcdf295eecd613f401a
+Payload = e81f4fb360bcae372d8be3f32655a29bc10a2f31876173cc
+CT = ee8b93a44b01a4964d44360d38557a892148068deb361c42d2b981fc741f2591
+
+Count = 23
+Adata = 112c969882e685b4ae1ee6b67f680e6a1d9d840e627d12118f991c1a3d71314c
+Payload = 27d6443e729d35d7a0690fcb7fe0b20892875f60b5d8763a
+CT = 2142982959203f76c0a6da3561e06a1a72c576dcd98f19b4a1fd47cd41fcf013
+
+Count = 24
+Adata = 73ef62870c50faca5d4e6c6ec45fa7b54bf79ed229fcf1fc8c79c9c09596039b
+Payload = 6c17ad5496dfccde8b877630e1e582dab52aaabe385a321f
+CT = 6a837143bd62c67feb48a3ceffe55ac855688302540d5d9143eb86ffa6958d71
+
+Count = 25
+Adata = b537f0f2981405f6069b401966656461b3516a32d181777121a60cea537e7cef
+Payload = dc4a1e39561f14321238272adff8b74a4e770c0a0c864a52
+CT = dadec22e7da21e9372f7f2d4c1f86f58ae3525b660d125dc1dfc38975c948d29
+
+Count = 26
+Adata = 96bd747ccdcd5fa6cd920514a2f38203e82ee9c7ec6e88080e9f6e2a6a812b0d
+Payload = c51958d7d7d39906b14d4ebb574db881355ec3e6b41838dd
+CT = c38d84c0fc6e93a7d1829b45494d6093d51cea5ad84f575320a48ee3845d9e7a
+
+Count = 27
+Adata = 690d6a2377314fc2f7dd06ae401e3585c79faf648a7af358ae4ef615669222eb
+Payload = 9eaf24f84e8818e286410de321d65ffbf25d1a14073c60da
+CT = 983bf8ef65351243e68ed81d3fd687e9121f33a86b6b0f54884188f946c9a317
+
+Count = 28
+Adata = 748dc83299a43033239ad2fef2dc3d72b76a38ca127607cef72de94a56d5e5c0
+Payload = 71c8eb0079559a306e236c49b7ce1b6cfe26c7888733eb7e
+CT = 775c371752e890910eecb9b7a9cec37e1e64ee34eb6484f00ae2dd33327f8459
+
+Count = 29
+Adata = 35a49535684637f67573fb0b4fdc1bdd8a57650a1d8f29b866fa552a6e0cdf91
+Payload = f09569906381138cc49e3fc2384c5d33c34abd3d617c487b
+CT = f601b587483c192da451ea3c264c8521230894810d2b27f5c50821a48b93d0ca
+
+[Tlen = 10]
+
+Key = 996a09a652fa6c82eae8be7886d7e75e
+Nonce = a8b3eb68f205a46d8f632c3367
+
+Count = 30
+Adata = c71620d0477c8137b77ec5c72ced4df3a1e987fd9af6b5b10853f0526d876cd5
+Payload = 84cdd7380f47524b86168ed95386faa402831f22045183d0
+CT = a7fbf9dd1b099ed3acf6bcbd0b6f7cae57bee99f9d084f826d86e69c07f053d1a607
+
+Count = 31
+Adata = 7b40b3443d00a0348a060db109e8882157612c43084ac5c3e9c5350c88bc165d
+Payload = 7ebb051741145a3bad87131553375c6debcbcecee9b79ee4
+CT = 5d8d2bf2555a96a3876721710bdeda67bef6387370ee52b694af9359a96acfb31a4a
+
+Count = 32
+Adata = 5cab3b84687070956916c11cab0ceea61adb6ea1f909be63d73df96fbfa3a9f4
+Payload = 35a29c1bcbe2182f34fe05f09dfb9ac4a496f95819ef11ec
+CT = 1694b2fedfacd4b71e1e3794c5121ccef1ab0fe580b6ddbe36d3920d1012bf093a5c
+
+Count = 33
+Adata = 6d440b44a069a6967f8750c3b4f8118798fe32d2eaa696ccc7f24e16d6366753
+Payload = a0e21d971876ae4048a61b43a3ac07c685005a20bccbe6ec
+CT = 83d433720c3862d862462927fb4581ccd03dac9d25922abec23025c1776811647f99
+
+Count = 34
+Adata = 06904325b8c6fc2b5a0412ba8062cd48d3af51beacb5ced9e2bdf8d0e056b738
+Payload = 8d333ed7d4b208e794e1673f6df692caee4e3a00fc49115e
+CT = ae051032c0fcc47fbe01555b351f14c0bb73ccbd6510dd0c6efeeaed29e65f1a8908
+
+Count = 35
+Adata = e5049e1c32f0a000024882e4fca9b77adb6c87fdbad96d0c8e97bdb8f46789dc
+Payload = 4189351b5caea375a0299e81c621bf434b6b97da68ad44be
+CT = 62bf1bfe48e06fed8ac9ace59ec839491e566167f1f488ec70d42f84a5411dfa43f9
+
+Count = 36
+Adata = 6f0be1905d1b5b607574ad93a1e7b4a536020fc6798acae862253916a0562707
+Payload = 5a063a24410b3d265c9a32a027cb2382a52bb8e35db15b98
+CT = 793014c15545f1be767a00c47f22a588f0164e5ec4e897caadd2256112d1f7d04934
+
+Count = 37
+Adata = a90f9f55ef22f5e6c542ed3573a9ab67d9c3b6775587fc2be70817479347ce00
+Payload = 0b72cb09a444be2d7b34cf9997fc5b885851d7e6092008b4
+CT = 2844e5ecb00a72b551d4fdfdcf15dd820d6c215b9079c4e6e187f5f37e8a5029ca4e
+
+Count = 38
+Adata = 4dd64fd7d8b571704cddabef854c51691ace4c30de74bfecad42eaed65284ebf
+Payload = ce2d996c9a4cf85edb888822773e03179feeb9e4b0928d6a
+CT = ed1bb7898e0234c6f168ba462fd7851dcad34f5929cb4138fbbb92009435f9ab6691
+
+Count = 39
+Adata = 75f4031d2e5098a9ea3eaa20c2423fbc1705ea18289efb96e311f3fefc153b67
+Payload = aa182e3ec4fb2f7a905c03582b2ee100ab81a9a311a778bc
+CT = 892e00dbd0b5e3e2babc313c73c7670afebc5f1e88feb4ee3cae38db7cc9d577b0ed
+
+[Tlen = 12]
+
+Key = 3ee186594f110fb788a8bf8aa8be5d4a
+Nonce = 44f705d52acf27b7f17196aa9b
+
+Count = 40
+Adata = 2c16724296ff85e079627be3053ea95adf35722c21886baba343bd6c79b5cb57
+Payload = d71864877f2578db092daba2d6a1f9f4698a9c356c7830a1
+CT = b4dd74e7a0cc51aea45dfb401a41d5822c96901a83247ea0d6965f5aa6e31302a9cc2b36
+
+Count = 41
+Adata = 78230f73f9c0150f630eca4cd679818551d449db82e665d8dc25fc53ebc11293
+Payload = 048ba28abb191ded5449dfe9dc7d19f9b132a2a9fd779aab
+CT = 674eb2ea64f03498f9398f0b109d358ff42eae86122bd4aa6356e2548a22e7cbee3b89d4
+
+Count = 42
+Adata = c09191a7d2fca98fca486f8843f275a78d57b8c9a6d330d5652ba641f928c6d8
+Payload = adf51386b3cc133ea9d18e679fe4bbf10ea780b7bed57d6a
+CT = ce3003e66c253a4b04a1de85530497874bbb8c985189336b35516f170a2aada38d1d94eb
+
+Count = 43
+Adata = ea46cc1a7ba5afaa6176f8dedc049283d2ac38fa74ef37ea1fc575328033b222
+Payload = f660a28551416b2f8e21466ba99daee280a91740d98219cf
+CT = 95a5b2e58ea8425a23511689657d8294c5b51b6f36de57ceea2d3237788a02ff15258351
+
+Count = 44
+Adata = 3093b74eb088bdd59999629d59509920938f4feabbd29df8e0b44364c8b55244
+Payload = b9a96f0e4c6dea8861e888bdd693b300017718da958aaa00
+CT = da6c7f6e9384c3fdcc98d85f1a739f76446b14f57ad6e40165fb6719509987930d350890
+
+Count = 45
+Adata = 5580672e52aacb9d714a34c31c33fc221e13e8f90849adbad3f6b3bec8571838
+Payload = cc4acdbd34ec9b7cbc3e23a53e0627c2a7c63206f3e0298d
+CT = af8fddddeb05b209114e7347f2e60bb4e2da3e291cbc678c8ecdf173444c334cfda5b22b
+
+Count = 46
+Adata = c7acf1b17609dc336df1006ffac6497777cdfd497c8c91525377c130accce0bc
+Payload = ed75d28be4794ad81bbc0f26a11c5466f23c0270d2d7b8f8
+CT = 8eb0c2eb3b9063adb6cc5fc46dfc7810b7200e5f3d8bf6f92221c860022d92b0f961c3e6
+
+Count = 47
+Adata = ac1adca686e1d129142c49f26b52941d037d8052b8a27d5215b7ffcfd2202481
+Payload = b8234b8bd34d9c6ceffebbb85722764e7d37e43c495256e0
+CT = dbe65beb0ca4b519428eeb5a9bc25a38382be813a60e18e11c73d6a695afc704228ed7a1
+
+Count = 48
+Adata = 472bf7946bce1d3c6f168f4475e5bb3a67d5df2fa01e64bce8bb6e43a6c8b177
+Payload = 790134a8db83f2da35dde832c3ae45ec62aff0274495d6e7
+CT = 1ac424c8046adbaf98adb8d00f4e699a27b3fc08abc998e6bf1e81950e44c63183a679d7
+
+Count = 49
+Adata = 1340ac7ff04dd7450afc13f8fa52df6d526c744a2dc2f76b0aadf284da270508
+Payload = 21ea2f778cf37aa02fea30e855c20a77909548da4ee7eb61
+CT = 422f3f17531a53d5829a600a99222601d58944f5a1bba560c2c3a1876e49a47a9b44b737
+
+[Tlen = 14]
+
+Key = 7b2d52a5186d912cf6b83ace7740ceda
+Nonce = f47be3a2b019d1beededf5b80c
+
+Count = 50
+Adata = 76cf3522aff97a44b4edd0eef3b81e3ab3cd1ccc93a767a133afd508315f05ed
+Payload = ea384b081f60bb450808e0c20dc2914ae14a320612c3e1e8
+CT = 79070f33114a980dfd48215051e224dfd01471ac293242afddb36e37da1ee8a88a77d7f12cc6
+
+Count = 51
+Adata = 41aa11ec55980609482575b97eee172590ff545d5798fd4246313da3fdbbcda6
+Payload = 811d54bad842a8b92b96fc03b4fff8b5f1939fd3a49876dc
+CT = 12221081d6688bf1ded63d91e8df4d20c0cddc799f69d59ba850b0116f3269b5e44e57de7166
+
+Count = 52
+Adata = dedfb02e93b975270f50cffa3351c85975a7b21fd89bbb921c40c1e5310e6702
+Payload = 8bbf87b490020b863fc596a8d169d79c0cb3506e1f1f5aa2
+CT = 1880c38f9e2828ceca85573a8d4962093ded13c424eef9e50f053627bd0c90714820c4fbe5ec
+
+Count = 53
+Adata = a727ed3d13331ee6a224ae4b73f0ccb04b997fcf88533a1f57e9b055275de92b
+Payload = 7294ae94358669f2ada4b64c125b248df7fe86c6715e3b6a
+CT = e1abeaaf3bac4aba58e477de4e7b9118c6a0c56c4aaf982df865a77d66f1232cd7e36af3d1be
+
+Count = 54
+Adata = 6704dc39a259152d2dc3f08b8799ffecf4e1bc38ce5b77c71cc293c6664ef2dd
+Payload = 48033c46389f6221fb9cdda1ecb8fc25fdec6afe4eaa5fd0
+CT = db3c787d36b541690edc1c33b09849b0ccb22954755bfc97e1fba154f6b166549d0d6bb9b573
+
+Count = 55
+Adata = 6cba004dfb5e5d9e1433bf1223039ae1d2df89cd2db68f550327a22c8f946ae9
+Payload = 01acc909b7d3bb3b3e1f72845f05238d2e1d9162976d3bd2
+CT = 92938d32b9f99873cb5fb316032596181f43d2c8ac9c9895c485e9e28ae33959f8acbb640fbf
+
+Count = 56
+Adata = dd5799710523aa1da0b1209fab1e6f2ed177444ed3880d462deebbd5f774c621
+Payload = 3706def87786e49baec2d13407865286cb4e05908cac430f
+CT = a4399ac379acc7d35b8210a65ba6e713fa10463ab75de0488ef976fa9bda9544ed94ef266ed2
+
+Count = 57
+Adata = 5d7505ff863d218f6822150455b977ad2df3c02be094f6832ee68872b1ae7a01
+Payload = f38d4b225d9b80a0c5fadc61476aef419ad3d18937d8661f
+CT = 60b20f1953b1a3e830ba1df31b4a5ad4ab8d92230c29c5580caadf1dbd07515e3bfb6992e2cd
+
+Count = 58
+Adata = 796b62c7abf797de7f6bad8bf5d549688ccb7ada62fff9469c14b08208b07a8a
+Payload = 993bb3a85f67f6c1a809d8094ee80e2ad9b694063af2fdb3
+CT = 0a04f793514dd5895d49199b12c8bbbfe8e8d7ac01035ef4733ad369e4a067b7976c9d6d0456
+
+Count = 59
+Adata = 84fd27557aeb283282366083e3586f3a59691ccd0d43ec81c4e5f4e85715eba8
+Payload = 1286506be19fb865a288b09dda8af4323567cd9a66e08643
+CT = 81b91450efb59b2d57c8710f86aa41a704398e305d11250439860d66891f32ce0a09788f5899
+
+[Tlen = 16]
+
+Key = 4189351b5caea375a0299e81c621bf43
+Nonce = 48c0906930561e0ab0ef4cd972
+
+Count = 60
+Adata = 40a27c1d1e23ea3dbe8056b2774861a4a201cce49f19997d19206d8c8a343951
+Payload = 4535d12b4377928a7c0a61c9f825a48671ea05910748c8ef
+CT = 26c56961c035a7e452cce61bc6ee220d77b3f94d18fd10b6d80e8bf80f4a46cab06d4313f0db9be9
+
+Count = 61
+Adata = ac8dde7ba60e4ba226eecb0a789b1c4673ddffe8f371464389f52f767004f0a6
+Payload = 7c0889854658d3408c5d8043aad2f4ae4a89449a36f8a3b8
+CT = 1ff831cfc51ae62ea29b0791941972254cd0b846294d7be196363d27b9e11fee55111b273399f5ff
+
+Count = 62
+Adata = 8f2777ec4930f7e349c3bd4830120cebdd896db9d8a33d34f101672024bd737f
+Payload = c641cf589020b94026ae5ac0bfdc29822cc13862a54614c7
+CT = a5b1771213628c2e0868dd128117af092a98c4bebaf3cc9ef741e15ad9b2f5ab864ad94d3f9de562
+
+Count = 63
+Adata = a87426f83bf91bd3c3556bf859cd97f51c92609879f02dbca9c7ae637a3fbf05
+Payload = d204994c128d6204ef2939c22572daa56c12df2e4d3e33e9
+CT = b1f4210691cf576ac1efbe101bb95c2e6a4b23f2528bebb0652a083ea1b43b7da026692c7aa796d7
+
+Count = 64
+Adata = 7ff9ca86f820e4d57995d450611009ffaa726e6fbe4ce1558ca1e775daed9ec2
+Payload = aff9bb0238689255f54cd5fdebe6d3dff5f5604ab8d77038
+CT = cc090348bb2aa73bdb8a522fd52d5554f3ac9c96a762a861057e0faa2711cfa1e3da5499f9a1ee0b
+
+Count = 65
+Adata = faa6b7f8c6e076b5e5b981119b7ec2e0b9c73da4064f9704e303d5792f59674b
+Payload = 95d2cf30b6174b17278ad9f44079a2199082dab917f89763
+CT = f622777a35557e79094c5e267eb2249296db2665084d4f3a90b39704d8913391ebd3424117b93b68
+
+Count = 66
+Adata = b553e65640c1ad0d2ff748c5b2af9d970c74131cff4fa73384a33dfec056332e
+Payload = aaa53244520e157c4890a0e62100a12daa84f9be710242d7
+CT = c9558a0ed14c2012665627341fcb27a6acdd05626eb79a8ed0a6cb58733be0a3b608afdf78eaa70c
+
+Count = 67
+Adata = a9be73668b94bc6a212744522a0adff03d49fd495daadaf6cd32f4ca25ebc2b5
+Payload = 1066b96c3c44301073717520ea5c07adbac7759b88d52154
+CT = 73960126bf06057e5db7f2f2d4978126bc9e89479760f90daf20ce64e6a821e39ca96aded43f0875
+
+Count = 68
+Adata = 8b516c47e6630b2c31d8eefd8ba152d7315582a3f4d3f0e0eb2984a365b434db
+Payload = b5969813d0f892febe64ed52d429cc737b5df8d5e0c63207
+CT = d666205953baa79090a26a80eae24af87d040409ff73ea5ecf4699d23f5fc6742bffebbd16858f6e
+
+Count = 69
+Adata = 8ad3e84edbe7d9305848746cbd0f769bce47d5ae4609513210e54cd3b984db1f
+Payload = daa90a2de3937e7942e6711f165a89b9e077fe322cab597d
+CT = b959b26760d14b176c20f6cd28910f32e62e02ee331e81243713601bb16dc91af84ac19ebd43a1ec
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp
new file mode 100644
index 0000000000..75b0c429f6
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT192.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 192
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 11fd45743d946e6d37341fec49947e8c70482494a8f07fcc
+Nonce = c6aeebcb146cfafaae66f78aab
+
+Count = 0
+Adata = 7dc8c52144a7cb65b3e5a846e8fd7eae37bf6996c299b56e49144ebf43a1770f
+Payload = ee7e6075ba52846de5d6254959a18affc4faf59c8ef63489
+CT = 137d9da59baf5cbfd46620c5f298fc766de10ac68e774edf1f2c5bad
+
+Count = 1
+Adata = edb8834974b02fc9ab29b4b3c49683426124e729b44e43cde4ab9bb1b30b5531
+Payload = d05410f42d4759f8cab3884785cf8f60ecbf902e525b92e8
+CT = 2d57ed240cba812afb038dcb2ef6f9e945a46f7452dae8be24285996
+
+Count = 2
+Adata = 8baf194e81e47a6ca82ca51b488339d014a0a494007793aa5201ac72fc3f808d
+Payload = db3022ef4cd68ae22b501599448ffe2dda15cfd2e259315c
+CT = 2633df3f6d2b52301ae01015efb688a4730e3088e2d84b0a6c510570
+
+Count = 3
+Adata = c0b55acc7fbfa9d9af6e1f32b6626a1cd89b1c32513b5b50a18ddab028470953
+Payload = 7f0745bea62479c0080ecec52e37c1e32d72a6b3864da44a
+CT = 8204b86e87d9a11239becb49850eb76a846959e986ccde1cb418cfd2
+
+Count = 4
+Adata = 9dc672e64c468242ddeec318c71f9b8cbaa14639eba3c861acfc26463fb7d5d7
+Payload = 263dbe1bd5e9d9b29b316fe36ec8bb10f64543b4921c01f6
+CT = db3e43cbf4140160aa816a6fc5f1cd995f5ebcee929d7ba03e5b5794
+
+Count = 5
+Adata = 1798286c37c1504fc0d7402681f6f70711ef506dcc3e29d0183dc578ed976f92
+Payload = 22dbba2b1a39074ddac736767ebdedc37e4208b233e03b34
+CT = dfd847fb3bc4df9feb7733fad5849b4ad759f7e833614162f63b4847
+
+Count = 6
+Adata = ed2898d0bcb34eebf98b5279bc3e8a20214321a7e23bc55b2b7613b1a9b94f2c
+Payload = f0f1235ee88d04de3f3d1489ec6b28b285a6a4fbb344911a
+CT = 0df2de8ec970dc0c0e8d110547525e3b2cbd5ba1b3c5eb4c7ab29a40
+
+Count = 7
+Adata = 50c4a285d6a4e64efceb288b82e7c8277307cf1eaa4b8b9294f97a1c38926a60
+Payload = 0e50aa6a3079c0b8d61e51c3bd93b592a03719acb9f0252e
+CT = f35357ba1184186ae7ae544f16aac31b092ce6f6b9715f7868f40ff6
+
+Count = 8
+Adata = b48a16fb9a065d3aeb2bdf1860e4b0f1348c8f13cd00b1729ff8c19e4e9724f3
+Payload = 82f39f5207afcfd677a7544579f2b888a1eabdee4e835924
+CT = 7ff0628226521704461751c9d2cbce0108f142b44e022372ceeff92c
+
+Count = 9
+Adata = d92b80544f29aba52496e2c9a0aa4adeb89820be321cfd2f0a53585a15d04c7f
+Payload = bc3b08eec6506d1497572f901f0e5f3e9854b40b0f992d08
+CT = 4138f53ee7adb5c6a6e72a1cb43729b7314f4b510f18575e619c1124
+
+[Tlen = 6]
+
+Key = 146a163bbf10746e7c1201546ba46de769be23f9d7cc2c80
+Nonce = f5827e51707d8d64bb522985bb
+
+Count = 10
+Adata = 599b12ebd3347a5ad098772c44c49eed954ec27c3ba6206d899ddaabca23a762
+Payload = 473b6600559aefb67f7976f0a5cc744fb456efd86f615648
+CT = 26d2be30e171439d54a0fec291c6024d1de09d61b44f53258ba1360406f9
+
+Count = 11
+Adata = 3a8423feb661db30542dc3cfb596280429397f80755a4bc8d4d941d03b61aacc
+Payload = 7edfce3dedd65a8592aec2bfc7a751e2360f3137941fc960
+CT = 1f36160d593df6aeb9774a8df3ad27e09fb9438e4f31cc0db5e5938e8c75
+
+Count = 12
+Adata = 0dc79993047fd6e7260aac4d847fdb4d16483f28b13b5f17330744d401d2875b
+Payload = a9fb3ebba43c273cacbf0f7187030c69172f31382e9e059b
+CT = c812e68b10d78b1787668743b3097a6bbe994381f5b000f694f534b76f0b
+
+Count = 13
+Adata = 6546d9a90e0e763679d5469a1bcffcc4f18f35f50c7714d14c7329b76ce7984e
+Payload = a7573e5b7dd7f4ce9e4480f603c14145a27f7c7a9246a3cf
+CT = c6bee66bc93c58e5b59d08c437cb37470bc90ec34968a6a23c6c025faa1b
+
+Count = 14
+Adata = 7f398ff0d47e2c0fccd8a16cc9e79b4813abac42e346fa33ba033956f798d6ac
+Payload = 84370557e0bbf74fd0a4533185adfe202d9fa9d622bba72f
+CT = e5dedd6754505b64fb7ddb03b1a788228429db6ff995a242ae0f88d836be
+
+Count = 15
+Adata = d0f46fb37d516cc957aaefd3be2a8bede885330a8edb96f3e5e0ab8cd03a8c59
+Payload = 029575400bd3f2621c7d9ca9b6a09ea6f776968b19dc3f3e
+CT = 637cad70bf385e4937a4149b82aae8a45ec0e432c2f23a5366d09f64b4c2
+
+Count = 16
+Adata = 4abaa4260c864572e12553c5aabfe62e4e7038490d4ba160119fc5d646780cc6
+Payload = 448be3821d94452425fae41a06457260a2666e890fa94954
+CT = 25623bb2a97fe90f0e236c28324f04620bd01c30d4874c39677fd479c852
+
+Count = 17
+Adata = 686e0578eadd19583291a01e11a29fc95a2c156da100dd85429ad58ba65440c6
+Payload = aebfe3e15a876412ec9df714f1afa898e69004c1ef25732b
+CT = cf563bd1ee6cc839c7447f26c5a5de9a4f267678340b7646bbc332573774
+
+Count = 18
+Adata = e3d29f970667286a81586aa02bb490c72d8bb3a308eafec5da0d105fddd1a157
+Payload = 08b2ce5f7296016e86d02f8c7952d746703ee4f0429b8df3
+CT = 695b166fc67dad45ad09a7be4d58a144d988964999b5889e33171a8ccec1
+
+Count = 19
+Adata = 9e2ea8eb7f56087ee506925648661eeefffd643a056cd4f4fc5cc23172b5c637
+Payload = e73d7d23736db17cca816ab2440062a8051177d47feb514e
+CT = 86d4a513c7861d57e158e280700a14aaaca7056da4c55423bc8299cc9f95
+
+[Tlen = 8]
+
+Key = bdf277af2226f03ec1a0ba7a8532ade6aea9b3d519fe2d38
+Nonce = cc3c596be884e7caed503315c0
+
+Count = 20
+Adata = 4d6546167b3ed55f01c62bd384e02e1039c0d67ef7abe33291fecb136272f73b
+Payload = 0ff89eff92a530b66684cd75a39481e7e069a7d05e89b692
+CT = 6ef66a52c866bd5df20ec5096de92167ad83cab0e095ad0c778a299f1224f10c
+
+Count = 21
+Adata = 95722ef5e0cf9f482e4c359f1fd6b9efe2b6e0630413c40285b8958c31188ca4
+Payload = b1ea02e3721e44c327443fcf4b424cce19afbb9e8cf06b76
+CT = d0e4f64e28ddc928b3ce37b3853fec4e5445d6fe32ec70e8a5c2c6b097a04d50
+
+Count = 22
+Adata = f7b76a2a4fe0a1b07a6b193b4600aec02360eb35853d88fe8a4f31a8dda48ad9
+Payload = c1f9c7b2e0ba712b4d2b32e4693b145228213999703767fc
+CT = a0f7331fba79fcc0d9a13a98a746b4d265cb54f9ce2b7c62f62e74c2312f9243
+
+Count = 23
+Adata = 406f39cb77b8d8c63f7797d184b6ebde819af7d48de5003538c022fe96b841ce
+Payload = ebf3a717546199c6f6b14efe8888613ca7e075e8290b277c
+CT = 8afd53ba0ea2142d623b468246f5c1bcea0a188897173ce2f1cb228ffd2ff8e6
+
+Count = 24
+Adata = 3dd3110703a95b05b9b9cff92ab7244e6c6dcb4509522c305d5d33e03f1b0b60
+Payload = a0e317b790870e6703e6077dfb8ea327c12e29a17107284c
+CT = c1ede31aca44838c976c0f0135f303a78cc444c1cf1b33d21f38e2d280a8f3ff
+
+Count = 25
+Adata = 044ae4064156b6ebc0921cb2c3c607976339f824d4dc6902eac66910dce086b2
+Payload = 8a16990690717dc16eea24da39878a2ee7c1579976e5b173
+CT = eb186dabcab2f02afa602ca6f7fa2aaeaa2b3af9c8f9aaedafbcf46b4e75bb11
+
+Count = 26
+Adata = 5479cc7f92460ff7a3e500f76d70e3036c44300005058b5517e3f64ad41b46b3
+Payload = 1e7e51f0fa9a33ed618c26f5e37754df0f7de7778882c26c
+CT = 7f70a55da059be06f5062e892d0af45f42978a17369ed9f2fac11c84d08e918e
+
+Count = 27
+Adata = f950e96d65a55efb3be3a55daffb421afad1d5625e3440a16414085469effe1c
+Payload = 3ef1f4c438dce131990ba536d7a6166022ae7de4a436f87c
+CT = 5fff0069621f6cda0d81ad4a19dbb6e06f4410841a2ae3e2b50cb871173d9bb8
+
+Count = 28
+Adata = 52742be3969830ba9c2bce26c98c2fb44ac881ec55c85627b2c94ba17b0de8cf
+Payload = 3c7b4a68dfb766e24739f14932563fb81f24591f0e31e895
+CT = 5d75bec58574eb09d3b3f935fc2b9f3852ce347fb02df30b4ce29627efbc3523
+
+Count = 29
+Adata = e16e5dc034719e5d815f937b672cf34d5d420a3945c8f73645241779d2bec150
+Payload = 03038acd2d8351e4e5aa308e554abfcd0d0334d8f864ec60
+CT = 620d7e607740dc0f712038f29b371f4d40e959b84678f7fe095168ed90827db2
+
+[Tlen = 10]
+
+Key = 62f8eba1c2c5f66215493a6fa6ae007aae5be92f7880336a
+Nonce = 15769753f503aa324f4b0e8ee0
+
+Count = 30
+Adata = 1bc05440ee3e34d0f25e90ca1ecbb555d0fb92b311621d171be6f2b719923d23
+Payload = f5522e3405d9b77cbf3257db2b9675e618e8744a0ee03f0f
+CT = b9103942dbbb93e15086751c9bb0a3d33112b55f95b7d4f32ff0bb90a8879812683f
+
+Count = 31
+Adata = 25c32770a299020d8500d8a4b5d7621e4379dbd6ef34a9aceefd4055ea6144f5
+Payload = c8bf145fcffbafd6cd1a4c5b6cedfe008aacb2528ef51c80
+CT = 84fd032911998b4b22ae6e9cdccb2835a356734715a2f77c6982d0796e1bd1cc9879
+
+Count = 32
+Adata = cba0e0140f094e17652ea6f64c26f69dd9429bfefb41aaf104c38f3f6501f4f9
+Payload = f8813985f59bf284bd3882e899ca9b67fb496f3eb78d7ebe
+CT = b4c32ef32bf9d619528ca02f29ec4d52d2b3ae2b2cda9542fe08edf50e05d4d85faf
+
+Count = 33
+Adata = a846d0f56eb963b308ab8f697adca378ab6ccf9f739edcd7f5db197b2ffa99ac
+Payload = 72862d82d940748d54369e3143192453069b80d10f32e569
+CT = 3ec43af407225010bb82bcf6f33ff2662f6141c494650e95800ae2523c5f161ed96f
+
+Count = 34
+Adata = 1dc5f6d6103ed2ae7f4ecd7b1bae4d5b9c0adef9100527b1737e1cf57f1175ef
+Payload = 46f2199305ff4e1f21a89d96d3902c54939f52278ba7aa0e
+CT = 0ab00ee5db9d6a82ce1cbf5163b6fa61ba65933210f041f234a29547607846bc9834
+
+Count = 35
+Adata = 8c28bcb9c31191c347dd64e552af5aff500e6e6f39e866351dd7065501a2837d
+Payload = 18c38c41a4e70c3f7362249ea329059b0e026bce7ae976b0
+CT = 54819b377a8528a29cd60659130fd3ae27f8aadbe1be9d4c95f73957e86152df56bd
+
+Count = 36
+Adata = 1081afd5bf9f1a87169973ebdca85c2b69598154673d7ca9d6e2f63d52030fc1
+Payload = c89e388dd6124c41251e7422b420a71e4618f5cf9f0a63fc
+CT = 84dc2ffb087068dccaaa56e50406712b6fe234da045d8800b2b028cd785f4f964069
+
+Count = 37
+Adata = 079bc543c966734fa70814139ba8051271ee1c4f701579013c427f8efb141db7
+Payload = 68449bc3f6c8bd8f3a46a8e147522d979948c88ca791d204
+CT = 24068cb528aa9912d5f28a26f774fba2b0b209993cc639f8fd3ef357e5e69f504c95
+
+Count = 38
+Adata = e7094697b78d20174ec3c97a48abcf67c2ba6790b4db5fda82b454becd2a25ef
+Payload = 330088153204c3d5de7744047b60887c8c044e4eeaae4bab
+CT = 7f429f63ec66e74831c366c3cb465e49a5fe8f5b71f9a057e092ed15d1a074306a9e
+
+Count = 39
+Adata = f8d64ce2aa66e67de0f2fa584dec858983333b0570882ab628419bcee541395a
+Payload = 893c5c45db989bd39485caa05ed700bb17c526b426edf4ba
+CT = c57e4b3305fabf4e7b31e867eef1d68e3e3fe7a1bdba1f46afaad39e9183b2970027
+
+[Tlen = 12]
+
+Key = 5a5667197f46b8027980d0a3166c0a419713d4df0629a860
+Nonce = 6236b01079d180fce156fbaab4
+
+Count = 40
+Adata = 29bdf65b29394d363d5243d4249bad087520f8d733a763daa1356be458d487e5
+Payload = d0e4024d6e33daafc011fe463545ed20f172872f6f33cefa
+CT = 479f3d408bfa00d1cd1c8bf11a167ce7ae4bcdb011f04e38733013b8ebe5e92b1917640c
+
+Count = 41
+Adata = 314f069dd4ac5aa3fdc2a74e83daa1d5d18330cd3b90684a9260bb48f5626d49
+Payload = 9ebd994a9af0cb94552ffd749fdd97f75a1ebd0ad3de3a9a
+CT = 09c6a6477f3911ea582288c3b08e06300527f795ad1dba58425a1bad4381dc84fee903e3
+
+Count = 42
+Adata = 3aa7f30ac5bfbcb3f8de7c5e76269c608fbc76361d215e78abc0e308ddc3528f
+Payload = 590a27721a36987d1ffa15f23c6ca5cc556dfcfa6993a2fb
+CT = ce71187fffff420312f76045133f340b0a54b66517502239efcb43c6aaec88b51d0a378b
+
+Count = 43
+Adata = 5630345f662df248886f771b2b77cc0cbdc8fe4cc4a6cde52b1ea4e5d946cebe
+Payload = 65f4b3a00c1c1ef39445a69b2150b034705410140ff9dad0
+CT = f28f8cade9d5c48d9948d32c0e0321f32f6d5a8b713a5a12b9a60374d9304316e2fc50d9
+
+Count = 44
+Adata = 38ee97f0dc635c7416a024e3af5c95dd1d496db8a5a5c3bcc20b9093ca906dfb
+Payload = 0edea2afaeaf650704d2c6c6622aad82169807c983c17309
+CT = 99a59da24b66bf7909dfb3714d793c4549a14d56fd02f3cb07611163d6b0f1734292ed8c
+
+Count = 45
+Adata = ea3b3f3c5b28f7d48af2ccf97083937baccb0a6b1a041080a73b15b9640ccf44
+Payload = b80175a03dff1b10078ded64ed759e5453e3bc0657c68590
+CT = 2f7a4aadd836c16e0a8098d3c2260f930cdaf69929050552edefbcbb51d9d607b7b2e8f8
+
+Count = 46
+Adata = 287f31e69880823df7798c7970c0e42e600bf567ad78f5d559d0182d570c03cb
+Payload = 531c1e721e185f58b2c654b9098ce0c1338bab4149c7bef7
+CT = c467217ffbd18526bfcb210e26df71066cb2e1de37043e35f2b6d4dc8afae25ff400d73d
+
+Count = 47
+Adata = 1d4579c9410cc34ade1352ed433e0d4faaaa28200e359bcb4140d35939b3a792
+Payload = cead1c5af16ca89bc0821775f8cba8c25620a03dfd27d6f1
+CT = 59d6235714a572e5cd8f62c2d79839050919eaa283e4563319cd80c1ce0f9ed40f1e9dec
+
+Count = 48
+Adata = 3fec0e5cc24d67139437cbc8112414fc8daccd1a94b49a4c76e2d39303547317
+Payload = be322f58efa7f8c68a635e0b9cce77f28e3f8faaa76fcad4
+CT = 294910550a6e22b8876e2bbcb39de635d106c535d9ac4a16e53d5aeccfb4a6837b79a625
+
+Count = 49
+Adata = ec6857533675b5ed8d4315b0d5f59c826f3ccb2d0bd6f604bd54f7c9542123ce
+Payload = c222374d366baf2d0301340582aa056c04441ac766065ab1
+CT = 55590840d3a275530e0c41b2adf994ab5b7d505818c5da73385e080bf29ae097c328789a
+
+[Tlen = 14]
+
+Key = d2d4482ea8e98c1cf309671895a16610152ce283434bca38
+Nonce = 6ee177d48f59bd37045ec03731
+
+Count = 50
+Adata = 9ef2d0d556d05cf9d1ee9dab9b322a389c75cd4e9dee2c0d08eea961efce8690
+Payload = 78168e5cc3cddf4b90d5bc11613465030903e0196f1fe443
+CT = e2324a6d5643dfc8aea8c08cbbc245494a3dcbcb800c797c3abcdb0563978785bf7fd71c6c1f
+
+Count = 51
+Adata = 6f99d9ce00a4be502a5d2c76a07b914d56f49a1592c1ee2e46e11b3c9da0d083
+Payload = 3c3992cac792e019720d38f768beac3deb6a43e7e1f59f20
+CT = a61d56fb521ce09a4c70446ab2488c77a85468350ee6021fcb0e8ec0879db8ffa59125eac239
+
+Count = 52
+Adata = deae66f68bb18178d1bc0734f19fd3ab390049c2ca083a159f5c078fcb4f0a38
+Payload = 8eaae72e532943d66ce8250c6b434d299b6afbf8e2b4f8b1
+CT = 148e231fc6a7435552955991b1b56d63d854d02a0da7658e664a2d992f7cf821e19bb7d4dff8
+
+Count = 53
+Adata = e2d592cb412e65f9044257d78e7491f9f80c8b08102c2d5da20535cef74ad8c8
+Payload = 1b8096b79ace8c6ee5dbd8735f1287aa2c94865f382dc2da
+CT = 81a452860f408ceddba6a4ee85e4a7e06faaad8dd73e5fe546a4a816b709a55db450ac249c5c
+
+Count = 54
+Adata = 78a292662b8e05abc2d44fbefd0840795e7493028015d9f2aae7b3b7a4634437
+Payload = 014f15219463ac22820ba6a1fa04d7f686003ef24004da67
+CT = 9b6bd11001edaca1bc76da3c20f2f7bcc53e1520af174758fbebbdb2e35ebf682f7fe30996bc
+
+Count = 55
+Adata = de6ea86d3641d916c4394fdd31e6a50194993d6ef1d3dfd9fffca20b2f58107d
+Payload = cc8c855a4c122046916bdcf8089eba3ddb80483e201c7102
+CT = 56a8416bd99c20c5af16a065d2689a7798be63eccf0fec3deee137bb5b1e7385aa1bd5d69831
+
+Count = 56
+Adata = 87b937b1d36e8a9ab33a1d3eed617030923acaabc7e620dfcb3c388936030fc6
+Payload = 3fb7d1f17e7e36d5d4b816cc6db11d1d85848c577fdfe938
+CT = a59315c0ebf03656eac56a51b7473d57c6baa78590cc74079b13b729c70e1fa89c43a05a544b
+
+Count = 57
+Adata = 116f4855121d6aa53e8b8b43a2e23d468c8568c744f49de5f7f1a60cf4e16278
+Payload = 268fe424d6db30f680c10fe2684707a0778069958e9a3bf7
+CT = bcab201543553075bebc737fb2b127ea34be42476189a6c82d900340d90dc4f09a7171d331d6
+
+Count = 58
+Adata = e13e0c9cef1f86160a75ccb131586370b0edabbf8b3b63f21f3a6fee072dd926
+Payload = 9d64de7161895884e7fa3d6e9eb996e7ebe511b01fe19cd4
+CT = 07401a40f4075807d98741f3444fb6ada8db3a62f0f201ebe4ad0d90322ed2813a3343029e93
+
+Count = 59
+Adata = d4cd69b26ea43596278b8caec441fedcf0d729d4e0c27ed1332f48871c96e958
+Payload = e4abe343f98a2df09413c3defb85b56a6d34dba305dcce46
+CT = 7e8f27726c042d73aa6ebf43217395202e0af071eacf53790065601bb59972c35b580852e684
+
+[Tlen = 16]
+
+Key = a7177fd129674c6c91c1c89f4408139afe187026b8114893
+Nonce = 31bb28f0e1e63c36ca3959dd18
+
+Count = 60
+Adata = 2529a834668187213f5342a1f3deea0dc2765478c7d71c9c21b9eb1351a5f6cb
+Payload = 2cea0f7304860a4f40a28c8b890db60f3891b9982478495e
+CT = 5bb7aa6ab9c02a5712d62343fbe61f774e598d6b87545612380ea23dcffc9574f672bca92e306411
+
+Count = 61
+Adata = a4dbf26802b2dba1bf828f57618fd197d3e60b6efc9d884f965ce3b43e1dc008
+Payload = 2baf3d378942bd44f67fb787def50aaf446bf15c56243484
+CT = 5cf2982e34049d5ca40b184fac1ea3d732a3c5aff5082bc8b93605b46a8a6a9c7e02cb8feac67af4
+
+Count = 62
+Adata = cbd1302c9fffe29fe882838236f64fe9d9ba35db5499e90f0faa35f34c7490f2
+Payload = a0639aa4e7a8bda4e9e096d17c1c47d3786010fabe9c72d2
+CT = d73e3fbd5aee9dbcbb9439190ef7eeab0ea824091db06d9e82e411c052c0a025ab15767b0242ebf7
+
+Count = 63
+Adata = b6112eb8299b28445aca8f72e7170a1cd8bbfee4d2145fbe8d49c6af8831c4d4
+Payload = e2d78ce5df9284c045b84df33f551211ddccf7bb14cd4529
+CT = 958a29fc62d4a4d817cce23b4dbebb69ab04c348b7e15a65ab58a892f7142414d3f7cf10925a403a
+
+Count = 64
+Adata = c70a9fb811894b73e445b78db7a931705a181f3a8730341cbb50eaff43572c6e
+Payload = c3f1e735a6741aa481ad577a98dbac1f03cc80ea0dae1b94
+CT = b4ac422c1b323abcd3d9f8b2ea3005677504b419ae8204d8b5b3ce6bae6ecb060289508d6e9212fe
+
+Count = 65
+Adata = c7cbda495a7dc1d91837f652a9d084df9b717e99b29bf1ab7f6c17b3341ecd6c
+Payload = db8cd5d76e459afce765e07da98f4ac58231224238c293c7
+CT = acd170ced303bae4b5114fb5db64e3bdf4f916b19bee8c8ba16229a91a2298ffe104f9c032720abb
+
+Count = 66
+Adata = 4bd3a656796cb1fa87976f3a93471e33dd1209ce33d7a28aaca4d17c99d78c94
+Payload = fd66aebc94f2513b1b9218396b08c63a869b9c4dd0752a91
+CT = 8a3b0ba529b4712349e6b7f119e36f42f053a8be735935ddb9cacc4fdb44402971a0eee7f1ad90d7
+
+Count = 67
+Adata = 448cdd9cbbf863eb666fda36b825f3798827da3c1349611f45605ab734b24498
+Payload = 5831e9a6af0234d051ffd17a14b8e3c8da95067ab767901b
+CT = 2f6c4cbf124414c8038b7eb266534ab0ac5d3289144b8f5713306e7f0a61d4b3da372db669321143
+
+Count = 68
+Adata = f8f04f12174b5205866515ce3775bd8e11d50d8b96142be0c347a773379fb928
+Payload = 248a4969621cf291bec7f0d76d80b7f019d4eb002a22c46a
+CT = 53d7ec70df5ad289ecb35f1f1f6b1e886f1cdff3890edb2609726d3a3d04005dc13629658624d05b
+
+Count = 69
+Adata = 4ecd7c2188fb9cfc84a9ee2fab29ccbbd48a574ec20f1959eedfe96887fe0eb3
+Payload = 68f36fd96de8c57210f6f41da5b67d68533d722c604dda62
+CT = 1faecac0d0aee56a42825bd5d75dd41025f546dfc361c52e8631fb934e918210097f3cefc7f3b0ee
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp
new file mode 100644
index 0000000000..dbe86fbb71
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/VTT256.rsp
@@ -0,0 +1,393 @@
+# CAVS 11.0
+# "CCM-VTT" information
+# AES Keylen: 256
+# Generated on Tue Mar 15 08:09:25 2011
+
+Alen = 32
+Plen = 24
+Nlen = 13
+
+[Tlen = 4]
+
+Key = 9074b1ae4ca3342fe5bf6f14bcf2f27904f0b15179d95a654f61e699692e6f71
+Nonce = 2e1e0132468500d4bd47862563
+
+Count = 0
+Adata = 3c5f5404370abdcb1edde99de60d0682c600b034e063b7d3237723da70ab7552
+Payload = 239029f150bccbd67edbb67f8ae456b4ea066a4beee065f9
+CT = 9c8d5dd227fd9f81237601830afee4f0115636c8e5d5fd743cb9afed
+
+Count = 1
+Adata = ab91d1aa072947d22f0dc322355a022fe7f0747f4a184b48446bd27999ef01fe
+Payload = 25a43fd8bf241d67dab9e3c106cd27b71fd45a87b9254a53
+CT = 9ab94bfbc86549308714543d86d795f3e4840604b210d2de169d7775
+
+Count = 2
+Adata = 4c3bdc6186297896097b3297ba90bcde78dc8a9efe3bd8b10a85eed1bf63a30c
+Payload = e63d8303fa5c51550e417e77ec1ec647c9e2a853cab00fee
+CT = 5920f7208d1d050253ecc98b6c04740332b2f4d0c1859763b9c2e299
+
+Count = 3
+Adata = 8587324c1ff6712aed8af134744de5df1f88c5d2cb33f4f888af9fd39eb8e813
+Payload = f27548ec1608d3b8a5bdcbccb7e09cf4b5c29d3661b13a61
+CT = 4d683ccf614987eff8107c3037fa2eb04e92c1b56a84a2ec02f73205
+
+Count = 4
+Adata = 58820fb68ba1cd73b05a6698b4394ba1b13e8e296480f5afe1154d9b8536007c
+Payload = ecbd7091732e49c0f4bda2e63235ea43bbf8c8730f955f9c
+CT = 53a004b2046f1d97a910151ab22f580740a894f004a0c7114e1dd81b
+
+Count = 5
+Adata = f3034031933e7807d47140cf5c7794e42a228a522a83883b0765b57a411bad85
+Payload = 3002c6fb49497c7d1d06e1bd4edd57a9e54bbbb74e948c79
+CT = 8f1fb2d83e08282a40ab5641cec7e5ed1e1be73445a114f446525bc4
+
+Count = 6
+Adata = 05981dc26a1db2d8e2c3d85ea9a4d1dc3432d9edc4795ca03ca4661d2fc35b8c
+Payload = 214acfb2613b266f2929d43c7666f3a23e61423061cdbec3
+CT = 9e57bb91167a7238748463c0f67c41e6c5311eb36af8264e651844a3
+
+Count = 7
+Adata = 968a302a27624c304e894633af600c3cc7c614b7da3af0bf2d3f239c7605338a
+Payload = 9c575d592a9622c014c1303329757a65a414a9ed0c1b1b3f
+CT = 234a297a5dd77697496c87cfa96fc8215f44f56e072e83b249fd550d
+
+Count = 8
+Adata = 9011231ec382ecaaae57f34de1ac6bbb50741014a978160ce59c60491e64f30d
+Payload = 426a4c83793abdcff5e2a99e161785dc27c6168a329ee465
+CT = fd7738a00e7be998a84f1e62960d3798dc964a0939ab7ce84137defa
+
+Count = 9
+Adata = 96f0b1edec4ad14407dcaf30ed68942b46c48d58b2dd63af60fccd5bdd48e560
+Payload = e04006b68c83a5dd4ceac3cde238e48895ae17728fdc7bbe
+CT = 5f5d7295fbc2f18a11477431622256cc6efe4bf184e9e33356a4953f
+
+[Tlen = 6]
+
+Key = 8596a69890b0e47d43aeeca54b52029331da06fae63aa3249faaca94e2605feb
+Nonce = 20442e1c3f3c88919c39978b78
+
+Count = 10
+Adata = 4e0d3aa502bd03fe1761b167c4e0df1d228301d3ebaa4a0281becd813266e255
+Payload = f0b065da6ecb9ddcab855152d3b4155037adfa758ba96070
+CT = d6a0f377f7c1b14dcdba729cae5271b027e71cc7850173ec265867a29eb3
+
+Count = 11
+Adata = aeef2d1e3d3c9920a4fdb5f9d963b88e78a5d0edae531e3b55e702ed609d9a3c
+Payload = f2a8855e34854656df0776e80255ad1d125841c727201509
+CT = d4b813f3ad8f6ac7b93855267fb3c9fd0212a7752988069566e89a72dc0e
+
+Count = 12
+Adata = 3051ffb19862370bc46ca94a8eb906a660d539b18e965583e95acc149190e3e9
+Payload = 20955a0ca3c9c10d4055406ec12226130ecdaf195b08d65e
+CT = 0685cca13ac3ed9c266a63a0bcc442f31e8749ab55a0c5c2dff4f6257e06
+
+Count = 13
+Adata = aafa45a107d909756b4a1956d5228b50316fc5852afdeecf401fa2a71aabea46
+Payload = 246b60d17ea70deb1380fbf4bd767d88f53069b0f4136511
+CT = 027bf67ce7ad217a75bfd83ac0901968e57a8f02fabb768def0017c9acc1
+
+Count = 14
+Adata = ccdeab6a28b1b9e9f0c67116a91f2215b229d0edcd35d696db2bcf54e77db743
+Payload = 5b735697c5577ee0e352cf6a1495c490d6f7e97c3898f0ee
+CT = 7d63c03a5c5d5271856deca46973a070c6bd0fce3630e372c73969437912
+
+Count = 15
+Adata = 33a1e7d4820ed6a76a6dab90b4ba830888caf12a262e4eb6d75a505b2207de36
+Payload = 1170416faf81896c7f00815f53c2be5f7246d4794895b4b1
+CT = 3760d7c2368ba5fd193fa2912e24dabf620c32cb463da72dd7cb3721fcdd
+
+Count = 16
+Adata = 3df3edd9fc93be9960b5a632e2847b30b10187c8f83de5b45fcb2e3ed475569a
+Payload = 556765ffe5c46015cbd8194e32abc41e8f711773e2bcac90
+CT = 7377f3527cce4c84ade73a804f4da0fe9f3bf1c1ec14bf0c82183448e643
+
+Count = 17
+Adata = 4cb8663a1a934b6b27cbc1ed3040fbb99fbb6812f8ca35ff73cc13feeb483af7
+Payload = 3070e269f3e87cd82af3896895a5dd6fbfa9898279e0f73b
+CT = 166074c46ae250494cccaaa6e843b98fafe36f307748e4a76069901b5e3a
+
+Count = 18
+Adata = 876df130c01d0b9b8ebe43e71046c365e13124169026876d50d7e155f0299676
+Payload = dd18d40728c561e24e6e54834348dde5683f067baf8df469
+CT = fb0842aab1cf4d732851774d3eaeb9057875e0c9a125e7f56d65c2b005d4
+
+Count = 19
+Adata = da08b14e1b770b81faaf1e59851df1cba8838cd63bef141340ee378e65fdcbd4
+Payload = 7064a2491f716f4a2969815e4a281a54690ced9f794b264e
+CT = 567434e4867b43db4f56a29037ce7eb479460b2d77e335d275b37e9fb9e9
+
+[Tlen = 8]
+
+Key = bae73483de27b581a7c13f178a6d7bda168c1b4a1cb9180512a13e3ab914eb61
+Nonce = daf54faef6e4fc7867624b76f2
+
+Count = 20
+Adata = 7022eaa52c9da821da72d2edd98f6b91dfe474999b75b34699aeb38465f70c1c
+Payload = 28ef408d57930086011b167ac04b866e5b58fe6690a0b9c3
+CT = 356367c6cee4453658418d9517f7c6faddcd7c65aef460138cf050f48c505151
+
+Count = 21
+Adata = a61b6c1f0293a7c35520abf158a995e5ae59b43ec5f38ff6fd6529970c9f83ac
+Payload = 1c5ad37d2a55afbc390b27cde0c42d6651fe191239bfaa27
+CT = 01d6f436b322ea0c6051bc2237786df2d76b9b1107eb73f76bca352f92f383e1
+
+Count = 22
+Adata = 0f1c6dffeda98f7a159f9cc61820bfb29910d8eaa41b751a41f9fe5648f02fba
+Payload = 6efe6652d46a84166d30befe2fbee0795e9475b401eedd60
+CT = 737241194d1dc1a6346a2511f802a0edd801f7b73fba04b014fd7c84052208d9
+
+Count = 23
+Adata = 151110a9ce7e44e5d76d9cad53c1819317527fcd169051f01c6a3efcc06ea999
+Payload = 55b791ee495299916ff3c2327b4990952bebd0a2da9acfc5
+CT = 483bb6a5d025dc2136a959ddacf5d001ad7e52a1e4ce1615c3ebc7214b9eef31
+
+Count = 24
+Adata = 0ba1210696d735eebc13b609d0ec33bc740805105dd82f065b82892b931f1e6d
+Payload = 794a86f5b20d344ad86fd5523d08f1864737be57731440c2
+CT = 64c6a1be2b7a71fa81354ebdeab4b112c1a23c544d409912eff08182f8a00f13
+
+Count = 25
+Adata = 5a3b71b0fdecce8bd759d3d72321b5c3e882c82627c14e0b59cc8c6d191f243f
+Payload = efa6ddd6fb8e4480a0f64414694e5f9e7f2e9b97cbe9cd14
+CT = f22afa9d62f90130f9acdffbbef21f0af9bb1994f5bd14c46894be1f8fa14538
+
+Count = 26
+Adata = 5d344c5b94695a66192b6692e420c8eaa3cb482502be837b2a0a91b787fbe48e
+Payload = 561dd3bf419ae33ff521a43898cf12c6a5c6163eec22abc1
+CT = 4b91f4f4d8eda68fac7b3fd74f7352522353943dd2767211f4393bca514c3336
+
+Count = 27
+Adata = 08344486df2b2f9a6880a03503a3986c485f067c480c31a51607553b875f91fa
+Payload = 6d3596f25401f2e3b099613236f1d88a2f3d8edc1f04bc0c
+CT = 70b9b1b9cd76b753e9c3fadde14d981ea9a80cdf215065dcb708ffd04c8c2da0
+
+Count = 28
+Adata = 9d0824a4dc7e67326c5b68a6ea99cb68298a2af2cc1952351454b038f6270603
+Payload = c563a43e4cc0f93d955432f68287e63400a7fdcae738ba84
+CT = d8ef8375d5b7bc8dcc0ea919553ba6a086327fc9d96c63541511d7d684d58762
+
+Count = 29
+Adata = c4384069e09a3d4de2c94e7e6055d8a00394e268398d6ea32914097aec37a1f4
+Payload = 18c5865b414b2a06b4d71ab9550985b4f3c3d7817e8a8d7c
+CT = 0549a110d83c6fb6ed8d815682b5c5207556558240de54acef0919c5f5daf093
+
+[Tlen = 10]
+
+Key = d5b321b0ac2fedce0933d57d12195c7b9941f4caa95529125ed21c41fac43374
+Nonce = b35fb2262edfa14938a0fba03e
+
+Count = 30
+Adata = ba762bbda601d711e2dfc9dbe3003d39df1043ca845612b8e9dc9ff5c5d06ec4
+Payload = 6aa6ea668df60b0db85592d0a819c9df9e1099916272aafb
+CT = 97027de5effd82c58f8dbfb909d7696fbe2d54916262912001a4d765bc1c95c90a95
+
+Count = 31
+Adata = 77a685958ca801dbcbf346d6bac72662d3870899d7bcdef6665d57bacd4e558f
+Payload = c2992096828325820e2d7acaa17ac789b6830ec3128dd7f9
+CT = 3f3db715e088ac4a39f557a300b4673996bec3c3129dec22288aecb4c38c2391c21d
+
+Count = 32
+Adata = 3a54d3e14bbd0549570ef12425c4b36fd25382d56b68e217bc711ab1625fe9bb
+Payload = e5151262cafdd2f4dea187372dacb9e5975065572446f2a5
+CT = 18b185e1a8f65b3ce979aa5e8c621955b76da8572456c97edb4bd2cb1f1222e0d64f
+
+Count = 33
+Adata = 5c7604f9ac8fdf30ee5820e5aeb75b65d7855e5d2ff9ccf021640707bf1f53e8
+Payload = 1fe786f52daab92a6aa5f43263bed74153d90579a34bceff
+CT = e24311764fa130e25d7dd95bc27077f173e4c879a35bf5249283c1a61e9113462325
+
+Count = 34
+Adata = 42b8863ea100babc1713654afcf54f21f8bff754223ad70269ace9d034f26a96
+Payload = 56c3130c5af210b5bcf7c58b968fc75fc92b9c339efb7aee
+CT = ab67848f38f9997d8b2fe8e2374167efe91651339eeb4135bd3ffe1b1051ec3206db
+
+Count = 35
+Adata = c5a369a8291f4278e797ff11ea5e777d69df3b9c0c32d46150ed4b3e2c3defdd
+Payload = daa716f3cd1e008b46318ec90d976c3fbf88c3ff73cf0052
+CT = 27038170af15894371e9a3a0ac59cc8f9fb50eff73df3b8910d5d255f193b29eb961
+
+Count = 36
+Adata = 63bdceb36a032d3e0e81b4e98ad9861e2c708cef4e870c5b88a87ecc24449be3
+Payload = 42477d7d44881dabccfce52efb8a2cc917b182a23b71fb49
+CT = bfe3eafe26839463fb24c8475a448c79378c4fa23b61c0924e524729fb06212508e6
+
+Count = 37
+Adata = b7f8e7b66726e07c3c73d74135f068bb8025c9da9ba70affb9ed9a69675f0eef
+Payload = 07f48cdc12aa27119fbdfda4ec07ce6068c92ba7ba9c9309
+CT = fa501b5f70a1aed9a865d0cd4dc96ed048f4e6a7ba8ca8d2222af86d91fb6a2b09d3
+
+Count = 38
+Adata = 09891ed14f4488069cd6a5744061e06f8ff8d1bc87b10448b3fbfc1a4e327787
+Payload = e2e7002b769fb5b4201053457158147d99b0d5147f3acac2
+CT = 1f4397a814943c7c17c87e2cd096b4cdb98d18147f2af1194cddcb65a76c40698017
+
+Count = 39
+Adata = 8f9786940943752c536548497f9dae2bd8d677b8bbcb0121a9c9f3c399b62e4b
+Payload = 86be1d1949fe03b8b80ef7abb3e27394273d7b76d7697f0e
+CT = 7b1a8a9a2bf58a708fd6dac2122cd3240700b676d77944d5ddb42d504b6fc47d6575
+
+[Tlen = 12]
+
+Key = 7f4af6765cad1d511db07e33aaafd57646ec279db629048aa6770af24849aa0d
+Nonce = dde2a362ce81b2b6913abc3095
+
+Count = 40
+Adata = 404f5df97ece7431987bc098cce994fc3c063b519ffa47b0365226a0015ef695
+Payload = 7ebef26bf4ecf6f0ebb2eb860edbf900f27b75b4a6340fdb
+CT = 353022db9c568bd7183a13c40b1ba30fcc768c54264aa2cd2927a053c9244d3217a7ad05
+
+Count = 41
+Adata = e9ed05813262fbe769c1104d8ba5c836dbd229a22a681de3565d17ac1129f96b
+Payload = fdf5a5fb377bb52ad07a971c6a9da3e1a68d279be9ac4ed7
+CT = b67b754b5fc1c80d23f26f5e6f5df9ee9880de7b69d2e3c11c000c9d88f047ca198c4e65
+
+Count = 42
+Adata = f246f1e948c81c98ea13f03dd8eea878449d0c3d5b5fe87c633bbe0106fcb899
+Payload = e5e6b57e74ce7afbde3697e2a69d61ca615aa3dfd32fe31f
+CT = ae6865ce1c7407dc2dbe6fa0a35d3bc55f575a3f53514e095c09878f1a963b795b29f4dd
+
+Count = 43
+Adata = e4683285695348ff04a61d51d90b868dfe4cf6ea246544727adeaeface571d57
+Payload = ef2c3a6bb8602d290045854a5f223e6f43bfd0bb9278fa88
+CT = a4a2eadbd0da500ef3cd7d085ae264607db2295b1206579e807d196d2628df1c384816f7
+
+Count = 44
+Adata = 42695369dbd69f07b46db282653704c34106aad82efdcc99b452598b5353f904
+Payload = beda29c7fe15c73ee5bef96485eb8c9e3cd3ea7ee633ef45
+CT = f554f97796afba1916360126802bd69102de139e664d4253961c666279394e1e28cf1b02
+
+Count = 45
+Adata = 58c3ce3906633475441229cfcdf05e02ff3738ae8d1b255974f431b3309ed41e
+Payload = 419c96ba8142b27e3377716358c97a8a636d7fe8403165e1
+CT = 0a12460ae9f8cf59c0ff89215d0920855d608608c04fc8f764efe624dd6c6f8b8cdc76e3
+
+Count = 46
+Adata = a9c06d8029f8da31629c3a6ddceb6009220a69fc614af1c231ae8702b3a85d6e
+Payload = 69bb441a7640f77e124d66af45a0e9f646658a838dfcb957
+CT = 223594aa1efa8a59e1c59eed4060b3f9786873630d8214410ef4b71970b9f80087533cf7
+
+Count = 47
+Adata = a92e88edd297da8c7089e21822b3e6cffd6837c78b975c8413fd6cca1b99bcb0
+Payload = a45b755658d38bdea57d1faae21d75428a17f2c74a33d2d5
+CT = efd5a5e63069f6f956f5e7e8e7dd2f4db41a0b27ca4d7fc36e27dfbf1ff7f08d1b213848
+
+Count = 48
+Adata = 421533453c8129fc8e681c68b9d7371adb0a19442ede7accd185129fcb7db648
+Payload = 2c3e28b61cede08121e80ee08c4f1f19dabb19add9d2dc8a
+CT = 67b0f80674579da6d260f6a2898f4516e4b6e04d59ac719ca48d1a0b815139fa28652d94
+
+Count = 49
+Adata = 55351bc7ddbc6b668d435088f1f9cf6f53caae16d4292b14bc0deec20f393ba0
+Payload = 81fa7fd41ba267bcbdf024cef1543b041cadd96b62a7cf1f
+CT = ca74af6473181a9b4e78dc8cf494610b22a0208be2d962091301c87a2a94df147c8cce4c
+
+[Tlen = 14]
+
+Key = 5c8b59d3e7986c277d5ad51e4a2233251076809ebf59463f47cd10b4aa951f8c
+Nonce = 21ff892b743d661189e205c7f3
+
+Count = 50
+Adata = f1e0af185180d2eb63e50e37ba692647cac2c6a149d70c81dbd34685ed78feaa
+Payload = 138ee53b1914d3322c2dd0a4e02faab2236555131d5eea08
+CT = 5b2f3026f30fdd50accc40ddd093b7997f23d7c6d3c8bc425f82c828413643b8794494cb5236
+
+Count = 51
+Adata = 45c5c284836414407268d7c8a89a0146759cfc92242004027d58d0828fad74e7
+Payload = fe3df84ee9b237f9edd77a5b8af96bc3e184579ac9c6e246
+CT = b69c2d5303a9399b6d36ea22ba4576e8bdc2d54f0750b40c6db5c92de5fb3aafba9537795e17
+
+Count = 52
+Adata = a41ea42692eac0914fef35e58409007342cef027de141223ffb46da7f58df034
+Payload = e0f5c02f9f84e57fada3f3575f1b1a748f360e0ea781b7b8
+CT = a8541532759feb1d2d42632e6fa7075fd3708cdb6917e1f21af6cf931ac943fd3affa6ad6fd1
+
+Count = 53
+Adata = 17dae00f2a9417780ecfef98f290a5ca9b17c873a9149cd81c18bd33164a0405
+Payload = 3a77a2ec5a1be6cbfbbfaab3e65427cb38d6798b132ff5c7
+CT = 72d677f1b000e8a97b5e3acad6e83ae06490fb5eddb9a38d38a3f09c56ae653be49b355fb938
+
+Count = 54
+Adata = 33b44873a7a1e5b0fdbb7e7347623e4fa1ccd937feb26fda2749b42f00744e50
+Payload = d0628b26019dad84de628d9dabf42cfb195165a369c22b49
+CT = 98c35e3beb86a3e65e831de49b4831d04517e776a7547d03974deec7ce2e1f296890bee795cb
+
+Count = 55
+Adata = f4fc5acff75d404849675b813cf7adcaeb8f3d56cb9a54a083f8ec07feb666bb
+Payload = 10b5ec41036e4bc5d61728e8811b520b7080c2177c122cbd
+CT = 5814395ce97545a756f6b891b1a74f202cc640c2b2847af798a3bc56f900bee7e8271c6dab22
+
+Count = 56
+Adata = ba051d1bc19b9a27520834fa3977b6413a319c9a52c8785e3e9594bd4265d911
+Payload = 648a84813ca97aef4ab7e143ee29acb946388660f18eb671
+CT = 2c2b519cd6b2748dca56713ade95b1921a7e04b53f18e03be6623d80c677633a9e4f999bb885
+
+Count = 57
+Adata = f5c629299d18901c8c34c42e8fc29a70c377c160fdea4a6068a36867707575f7
+Payload = 3ead49ed0b41de79c829098d034b666bce052d79bf1f56db
+CT = 760c9cf0e15ad01b48c899f433f77b409243afac71890091c65b88ff4fdd9b8187f7d71ba04b
+
+Count = 58
+Adata = da486fd2953a72838e67e1909ed4042df67c355b648a45bcd2cc1ba610659e76
+Payload = 4543457c8fdf463c4bf8515a762cdc83d9aaa887d3eaa2af
+CT = 0de2906165c4485ecb19c1234690c1a885ec2a521d7cf4e5727c3404564ed41528973d389c7c
+
+Count = 59
+Adata = a0b1d3600f6eba910a11537d61fa12184959f1c3ae386570cbbc9106f7a7ba07
+Payload = 22071ef5d204417f99bc2faf53ecc4c6cf795e77805633ee
+CT = 6aa6cbe8381f4f1d195dbfd66350d9ed933fdca24ec065a446ecb536703a7a97928f80fcc7cf
+
+[Tlen = 16]
+
+Key = 60823b64e0b2da3a7eb772bd5941c534e6ff94ea96b564e2b38f82c78bb54522
+Nonce = 48526f1bffc97dd65e42906983
+
+Count = 60
+Adata = fab62b3e5deda7a9c1128663cc81c44b74ab1bfe70bc1c9dec7c7fd08173b80a
+Payload = a8be794613835c4366e75817d228438f011a2ec8a86f9797
+CT = cc3efe04d84a4ec5cb6a6c28dc2c2d386a359d9550dbdec963ddd56464aed6d0613159d1aa181dcb
+
+Count = 61
+Adata = b3ff11e57eeab41bc597622c770c9eea333e178d5bd5689c6a30011187a965b8
+Payload = 7590769380dc91832da023798dfdd447b9f7adaa09d7e2d0
+CT = 1110f1d14b158305802d174683f9baf0d2d81ef7f163ab8e7c1273765bc5bfdeca429cc8ebd8aca2
+
+Count = 62
+Adata = 2a953a081c5d52bc500c9c12f56cd2aab5c920d73098335baa5d947100cb3411
+Payload = 30e4de5e8c275677f8f4f7bbf9d101f96b38d79968ea028c
+CT = 5464591c47ee44f15579c384f7d56f4e001764c4905e4bd2886229c09b986bee3a8a3025c150d3a3
+
+Count = 63
+Adata = 99cc9d1b3db79640dfdc4423af3ded03c329f7ba5b6b509269c10e59519053b8
+Payload = 852698f6ab4aa794b3d657c4a2ca7b9c8bfb5fc9b4ad0aca
+CT = e1a61fb46083b5121e5b63fbacce152be0d4ec944c19439480cd04041918c4071ea5ac263f36c544
+
+Count = 64
+Adata = b76aef71eaf03c2d0dc0623e90596fcb0bc4dbbed1d5bb24c8af37d778863e5b
+Payload = cd337fcf362d301d66916c7097bdeb31df8206e00f7ac106
+CT = a9b3f88dfde4229bcb1c584f99b98586b4adb5bdf7ce8858f001d6002eafaec49c472acdfaedf1de
+
+Count = 65
+Adata = 42a718d892e229a1807b74bd730fb15500ac4a790392100aef362cd7628d5806
+Payload = 0041a0cf48fcf870b21db6107cfd9ef91e409afc7562ffa7
+CT = 64c1278d8335eaf61f90822f72f9f04e756f29a18dd6b6f975d86cde91b6610496c3bb5276238741
+
+Count = 66
+Adata = e788c98ae85b11b3ae884eed6f3b8f5bcf5ab1b7b20ad3f44f760b2287cc5793
+Payload = fcc74ef1908dbcab9b05c76ee5a9941cdef933d433c0d25f
+CT = 9847c9b35b44ae2d3688f351ebadfaabb5d68089cb749b01db7d9f10e75d1b213beae0e0230dd82b
+
+Count = 67
+Adata = d330fc1ca406dd9528e9281aa1a3cdf013b698c14a4e55371e7539c9f6867dd4
+Payload = 611dade00cec14743be4e035cafe7507df5fb94b278875b1
+CT = 059d2aa2c72506f29669d40ac4fa1bb0b4700a16df3c3cefc63ba64291e73e6349ed089a53564291
+
+Count = 68
+Adata = 06bbadd5d22d1796d88415d7a4b024313f243bd0f58aafc75bb554a691d7e54f
+Payload = b67b5dd7f90ecd48a45853cb193e0d9702d78898f07e831d
+CT = d2fbda9532c7dfce09d567f4173a632069f83bc508caca43ac4d7bd964a2f9e2303df688dd0513da
+
+Count = 69
+Adata = 54da66d406f2d98edd999b673ef44d46ffd196091c8b7582ac2ed6bf13dc648f
+Payload = d092dc436c41836bdb815e473bc6a1906f37624e73b494f9
+CT = b4125b01a78891ed760c6a7835c2cf270418d1138b00dda7b4cd237cd9a7c9d93b9cc0f171818dae
diff --git a/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip
new file mode 100644
index 0000000000..34bb67b1ac
--- /dev/null
+++ b/lib/crypto/test/crypto_SUITE_data/aes_ccm_vectors/ccmtestvectors.zip
Binary files differ
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index f708d7272d..3f26493cd3 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -39,6 +39,10 @@ all() ->
get_all_possible_methods,
engine_load_all_methods,
engine_load_some_methods,
+ multiple_engine_load,
+ engine_list,
+ get_id_and_name,
+ engine_by_id,
bad_arguments,
unknown_engine,
pre_command_fail_bad_value,
@@ -46,6 +50,7 @@ all() ->
failed_engine_init,
ctrl_cmd_string,
ctrl_cmd_string_optional,
+ ensure_load,
{group, engine_stored_key}
].
@@ -70,11 +75,18 @@ groups() ->
init_per_suite(Config) ->
- case crypto:info_lib() of
- [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}] ->
+ case {os:type(), crypto:info_lib()} of
+ {_, [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}]} ->
{skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
- Res ->
- ct:log("crypto:info_lib() -> ~p\n", [Res]),
+
+ {{unix,darwin}, _} ->
+ {skip, "Engine unsupported on Darwin"};
+
+ {{win32,_}, _} ->
+ {skip, "Engine unsupported on Windows"};
+
+ {OS, Res} ->
+ ct:log("crypto:info_lib() -> ~p\nos:type() -> ~p", [Res,OS]),
try crypto:start() of
ok ->
Config;
@@ -97,7 +109,7 @@ init_per_group(engine_stored_key, Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{error, notsup} ->
- {skip, "Engine not supported on this OpenSSL version"};
+ {skip, "Engine not supported on this SSL version"};
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"};
Other ->
@@ -132,11 +144,12 @@ get_all_possible_methods() ->
get_all_possible_methods(Config) when is_list(Config) ->
try
List = crypto:engine_get_all_methods(),
+ true = erlang:is_list(List),
ct:log("crypto:engine_get_all_methods() -> ~p\n", [List]),
ok
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
engine_load_all_methods()->
@@ -149,13 +162,12 @@ engine_load_all_methods(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
- {<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
{ok, E} ->
@@ -181,7 +193,7 @@ engine_load_all_methods(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end
end.
@@ -195,21 +207,20 @@ engine_load_some_methods(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
Md5Hash1 = crypto:hash(md5, "Don't panic"),
Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
EngineMethods = crypto:engine_get_all_methods() --
- [engine_method_dh,engine_method_rand,
+ [engine_method_dh, engine_method_rand,
engine_method_ciphers, engine_method_store,
engine_method_pkey_meths, engine_method_pkey_asn1_meths],
case crypto:engine_load(<<"dynamic">>,
[{<<"SO_PATH">>, Engine},
- {<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[],
EngineMethods) of
- {ok, E} ->
+ {ok, E} ->
case crypto:hash(md5, "Don't panic") of
Md5Hash1 ->
ct:fail(fail_to_load_engine_still_original);
@@ -232,7 +243,168 @@ engine_load_some_methods(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+multiple_engine_load()->
+ [{doc, "Use a dummy md5 engine that does not implement md5"
+ "but rather returns a static binary to test that crypto:engine_load "
+ "functions works when called multiple times."}].
+
+multiple_engine_load(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
+ Md5Hash1 = crypto:hash(md5, "Don't panic"),
+ Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ {ok, E1} = crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []),
+ {ok, E2} = crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E2),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:engine_unload(E1),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash2 ->
+ ct:fail(fail_to_unload_still_test_engine);
+ Md5Hash1 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_unload_engine)
+ end;
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+engine_list()->
+ [{doc, "Test add and remove engine ID to the SSL internal engine list."}].
+
+engine_list(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ EngineList0 = crypto:engine_list(),
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ EngineList0 = crypto:engine_list(),
+ ok = crypto:engine_add(E),
+ [<<"MD5">>] = lists:subtract(crypto:engine_list(), EngineList0),
+ ok = crypto:engine_remove(E),
+ EngineList0 = crypto:engine_list(),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+get_id_and_name()->
+ [{doc, "Test fetching id and name from an engine."}].
+
+get_id_and_name(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ <<"MD5">> = crypto:engine_get_id(E),
+ <<"MD5 test engine">> = crypto:engine_get_name(E),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
+
+engine_by_id()->
+ [{doc, "Test fetching a new reference the the engine when the"
+ "engine id is added to the SSL engine list."}].
+
+engine_by_id(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ case crypto:engine_load(<<"dynamic">>,
+ [{<<"SO_PATH">>, Engine},
+ <<"LOAD">>],
+ []) of
+ {ok, E} ->
+ case crypto:engine_by_id(<<"MD5">>) of
+ {error,bad_engine_id} ->
+ ok;
+ {ok, _} ->
+ ct:fail(fail_engine_found)
+ end,
+ ok = crypto:engine_add(E),
+ {ok, _E1} = crypto:engine_by_id(<<"MD5">>),
+ ok = crypto:engine_remove(E),
+ ok = crypto:engine_unload(E);
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
end
end.
@@ -246,7 +418,7 @@ bad_arguments(Config) when is_list(Config) ->
{error, notexist} ->
{skip, "OTP Test engine not found"};
{ok, Engine} ->
- try
+ try
try
crypto:engine_load(fail_engine, [], [])
catch
@@ -276,7 +448,7 @@ bad_arguments(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end
end.
@@ -289,7 +461,7 @@ unknown_engine(Config) when is_list(Config) ->
ok
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_value() ->
@@ -311,7 +483,7 @@ pre_command_fail_bad_value(Config) when is_list(Config) ->
end
catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
pre_command_fail_bad_key() ->
@@ -334,9 +506,9 @@ pre_command_fail_bad_key(Config) when is_list(Config) ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
failed_engine_init()->
@@ -352,18 +524,20 @@ failed_engine_init(Config) when is_list(Config) ->
[{<<"SO_PATH">>, Engine},
{<<"ID">>, <<"MD5">>}],
[]) of
- {error, add_engine_failed} ->
+ {error, engine_init_failed} ->
ok;
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
+ {skip, "Engine not supported on this SSL version"}
end.
+%%-------------------------------------------------------------------------
+%% Test the optional flag in ctrl comands
ctrl_cmd_string()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
ctrl_cmd_string(Config) when is_list(Config) ->
@@ -377,22 +551,22 @@ ctrl_cmd_string(Config) when is_list(Config) ->
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
- {ok, E} ->
+ {ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>) of
ok ->
ct:fail(fail_ctrl_cmd_should_fail);
- {error,ctrl_cmd_failed} ->
+ {error,ctrl_cmd_failed} ->
ok
end,
- ok = crypto:engine_unload(E);
+ ok = crypto:engine_unload(E);
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
- end.
+ {skip, "Engine not supported on this SSL version"}
+ end.
ctrl_cmd_string_optional()->
[{doc, "Test that a not known optional ctrl comand do not fail"}].
@@ -407,25 +581,66 @@ ctrl_cmd_string_optional(Config) when is_list(Config) ->
{<<"ID">>, <<"MD5">>},
<<"LOAD">>],
[]) of
- {ok, E} ->
+ {ok, E} ->
case crypto:engine_ctrl_cmd_string(E, <<"TEST">>, <<"17">>, true) of
ok ->
ok;
- _ ->
+ _ ->
ct:fail(fail_ctrl_cmd_string)
end,
- ok = crypto:engine_unload(E);
+ ok = crypto:engine_unload(E);
{error, bad_engine_id} ->
{skip, "Dynamic Engine not supported"}
end
end
- catch
+ catch
error:notsup ->
- {skip, "Engine not supported on this OpenSSL version"}
- end.
+ {skip, "Engine not supported on this SSL version"}
+ end.
+
+ensure_load()->
+ [{doc, "Test the special ensure load function."}].
+
+ensure_load(Config) when is_list(Config) ->
+ case crypto:get_test_engine() of
+ {error, notexist} ->
+ {skip, "OTP Test engine not found"};
+ {ok, Engine} ->
+ try
+ Md5Hash1 = <<106,30,3,246,166,222,229,158,244,217,241,179,50,232,107,109>>,
+ Md5Hash1 = crypto:hash(md5, "Don't panic"),
+ Md5Hash2 = <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>,
+ case crypto:ensure_engine_loaded(<<"MD5">>, Engine) of
+ {ok, E} ->
+ {ok, _E1} = crypto:ensure_engine_loaded(<<"MD5">>, Engine),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash1 ->
+ ct:fail(fail_to_load_still_original_engine);
+ Md5Hash2 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_load_engine)
+ end,
+ ok = crypto:ensure_engine_unloaded(E),
+ case crypto:hash(md5, "Don't panic") of
+ Md5Hash2 ->
+ ct:fail(fail_to_unload_still_test_engine);
+ Md5Hash1 ->
+ ok;
+ _ ->
+ ct:fail(fail_to_unload_engine)
+ end;
+ {error, bad_engine_id} ->
+ {skip, "Dynamic Engine not supported"}
+ end
+ catch
+ error:notsup ->
+ {skip, "Engine not supported on this SSL version"}
+ end
+ end.
%%%----------------------------------------------------------------
-%%% Pub/priv key storage tests. Thoose are for testing the crypto.erl
+%%% Pub/priv key storage tests. Those are for testing the crypto.erl
%%% support for using priv/pub keys stored in an engine.
sign_verify_rsa(Config) ->
@@ -467,7 +682,7 @@ sign_verify_rsa_pwd_bad_pwd(Config) ->
_ -> {fail, "PWD prot pubkey sign succeded with no pwd!"}
catch
error:badarg -> ok
- end.
+ end.
priv_encrypt_pub_decrypt_rsa(Config) ->
Priv = #{engine => engine_ref(Config),
@@ -540,7 +755,7 @@ get_pub_from_priv_key_rsa_pwd_no_pwd(Config) ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
- Pub ->
+ Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded although no pwd!"}
end.
@@ -556,7 +771,7 @@ get_pub_from_priv_key_rsa_pwd_bad_pwd(Config) ->
{skip, "RSA not supported"};
{error, Error} ->
{fail, {wrong_error,Error}};
- Pub ->
+ Pub ->
ct:log("rsa Pub = ~p",[Pub]),
{fail, "PWD prot pubkey fetch succeded with bad pwd!"}
end.
@@ -590,7 +805,7 @@ get_pub_from_priv_key_ecdsa(Config) ->
ct:log("ecdsa Pub = ~p",[Pub]),
sign_verify(ecdsa, sha, Priv, Pub)
end.
-
+
%%%================================================================
%%% Help for engine_stored_pub_priv_keys* test cases
%%%
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index cc34c20ac6..64d593f64a 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.3
+CRYPTO_VSN = 4.3.3
diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml
index 9f7214ac69..395b69973d 100644
--- a/lib/debugger/doc/src/notes.xml
+++ b/lib/debugger/doc/src/notes.xml
@@ -33,6 +33,21 @@
<p>This document describes the changes made to the Debugger
application.</p>
+<section><title>Debugger 4.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Debugger 4.2.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index ac901c5469..0eb258567f 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -248,7 +248,7 @@ handle_int_msg({attached, AttPid}, Status, _Bs,
tell_attached({attached, M, Line, get(trace)}),
%% Give info about status and call level as well
- %% In this case, Status can not be exit_at
+ %% In this case, Status cannot be exit_at
Msg = case Status of
idle -> {func_at,M,Line,Le};
break -> {break_at,M,Line,Le};
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index d62e5915a7..a3cbb497f8 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 4.2.5
+DEBUGGER_VSN = 4.2.6
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 4ec72eecd9..3cf776e566 100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the Dialyzer
application.</p>
+<section><title>Dialyzer 3.3.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Optimize Dialyzer's handling of left-associative use
+ of <c>andalso</c> and <c>orelse</c> in guards. </p>
+ <p>
+ Own Id: OTP-15268 Aux Id: ERL-680 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Dialyzer 3.3</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index abd89034f3..ebe4040c34 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -643,7 +643,7 @@ sets_filter([Mod|Mods], ExpTypes) ->
src_compiler_opts() ->
[no_copt, to_core, binary, return_errors,
no_inline, strict_record_tests, strict_record_updates,
- dialyzer].
+ dialyzer, no_spawn_compiler_process].
-spec format_errors([{module(), string()}]) -> [string()].
diff --git a/lib/dialyzer/src/typer.erl b/lib/dialyzer/src/typer.erl
index 4b99f5f72e..5a1b8619c9 100644
--- a/lib/dialyzer/src/typer.erl
+++ b/lib/dialyzer/src/typer.erl
@@ -980,7 +980,7 @@ fatal_error(Slogan) ->
mode_error(OldMode, NewMode) ->
Msg = io_lib:format("Mode was previously set to '~s'; "
- "can not set it to '~s' now",
+ "cannot set it to '~s' now",
[OldMode, NewMode]),
fatal_error(Msg).
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
index ea92613781..3606b21932 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_validator.erl
@@ -272,7 +272,7 @@ valfun_1(if_end, Vst) ->
valfun_1({try_case_end,Src}, Vst) ->
assert_term(Src, Vst),
kill_state(Vst);
-%% Instructions that can not cause exceptions
+%% Instructions that cannot cause exceptions
valfun_1({move,Src,Dst}, Vst) ->
Type = get_term_type(Src, Vst),
set_type_reg(Type, Dst, Vst);
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
index 1d065b3723..88b464a721 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber.erl
@@ -300,7 +300,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -562,7 +562,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Length,_Form,OptOrMand) ->
BytesVar,","]),
false;
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
NewLength = case DoLength of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
index 9164ec6551..573bb15c92 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/asn1/asn1ct_gen_ber_bin_v2.erl
@@ -290,7 +290,7 @@ gen_encode_prim(_Erules,D,DoTag,Value) when record(D,type) ->
'ASN1_OPEN_TYPE' ->
emit_encode_func('open_type', Value,DoTag);
XX ->
- exit({'can not encode' ,XX})
+ exit({'cannot encode' ,XX})
end.
@@ -602,7 +602,7 @@ gen_dec_prim(_Erules,Att,BytesVar,DoTag,_TagIn,_Form,_OptOrMand) ->
BytesVar,","]),
add_func({decode_open_type_as_binary,2});
Other ->
- exit({'can not decode' ,Other})
+ exit({'cannot decode' ,Other})
end,
case {DoTag,NewTypeName} of
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
index 4008f8d789..9e0cdac2dc 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_lib.erl
@@ -779,7 +779,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
index af49ceff72..b4e9edb7ce 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/mnesia/mnesia_tm.erl
@@ -1529,7 +1529,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
case catch mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C, DumperMode} when record(C, commit) ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
diff --git a/lib/dialyzer/test/small_SUITE_data/results/left_assoc b/lib/dialyzer/test/small_SUITE_data/results/left_assoc
new file mode 100644
index 0000000000..58cdad29de
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/left_assoc
@@ -0,0 +1,2 @@
+
+left_assoc.erl:93: The variable __@2 can never match since previous clauses completely covered the type binary()
diff --git a/lib/dialyzer/test/small_SUITE_data/results/maps_sum b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
index b29ac77d88..daa099e490 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/maps_sum
+++ b/lib/dialyzer/test/small_SUITE_data/results/maps_sum
@@ -1,4 +1,4 @@
-maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (maps:iterator() | map()) -> any()
+maps_sum.erl:15: Invalid type specification for function maps_sum:wrong1/1. The success typing is (maps:iterator(_,_) | map()) -> any()
maps_sum.erl:26: Function wrong2/1 has no local return
maps_sum.erl:27: The call lists:foldl(fun((_,_,_) -> any()),0,Data::any()) will never return since it differs in the 1st argument from the success typing arguments: (fun((_,_) -> any()),any(),[any()])
diff --git a/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl b/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl
new file mode 100644
index 0000000000..0250e4ab49
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/left_assoc.erl
@@ -0,0 +1,96 @@
+-module(left_assoc).
+
+%% As pointed out in ERL-680, analyzing guards with short circuit
+%% operators becomes very slow as the number of left associations
+%% grows.
+
+-spec from_iso8601('Elixir.String':t(), 'Elixir.Calendar':calendar()) ->
+ {ok, t()} | {error, atom()}.
+
+-export_type([t/0]).
+
+-type t() ::
+ #{'__struct__' := 'Elixir.Date',
+ calendar := 'Elixir.Calendar':calendar(),
+ day := 'Elixir.Calendar':day(),
+ month := 'Elixir.Calendar':month(),
+ year := 'Elixir.Calendar':year()}.
+
+-export([from_iso8601/1,
+ from_iso8601/2]).
+
+from_iso8601(__@1) ->
+ from_iso8601(__@1, 'Elixir.Calendar.ISO').
+
+from_iso8601(<<45/integer,_rest@1/binary>>, _calendar@1) ->
+ case raw_from_iso8601(_rest@1, _calendar@1) of
+ {ok,#{year := _year@1} = _date@1} ->
+ {ok,_date@1#{year := - _year@1}};
+ __@1 ->
+ __@1
+ end;
+from_iso8601(<<_rest@1/binary>>, _calendar@1) ->
+ raw_from_iso8601(_rest@1, _calendar@1).
+
+raw_from_iso8601(_string@1, _calendar@1) ->
+ case _string@1 of
+ <<_y1@1/integer,
+ _y2@1/integer,
+ _y3@1/integer,
+ _y4@1/integer,
+ 45/integer,
+ _m1@1/integer,
+ _m2@1/integer,
+ 45/integer,
+ _d1@1/integer,
+ _d2@1/integer>>
+ when
+ ((((((((((((((_y1@1 >= 48
+ andalso
+ _y1@1 =< 57)
+ andalso
+ _y2@1 >= 48)
+ andalso
+ _y2@1 =< 57)
+ andalso
+ _y3@1 >= 48)
+ andalso
+ _y3@1 =< 57)
+ andalso
+ _y4@1 >= 48)
+ andalso
+ _y4@1 =< 57)
+ andalso
+ _m1@1 >= 48)
+ andalso
+ _m1@1 =< 57)
+ andalso
+ _m2@1 >= 48)
+ andalso
+ _m2@1 =< 57)
+ andalso
+ _d1@1 >= 48)
+ andalso
+ _d1@1 =< 57)
+ andalso
+ _d2@1 >= 48)
+ andalso
+ _d2@1 =< 57 ->
+ {ok,
+ #{year => (_y1@1 - 48) * 1000 + (_y2@1 - 48) * 100
+ +
+ (_y3@1 - 48) * 10
+ +
+ (_y4@1 - 48),
+ month => (_m1@1 - 48) * 10 + (_m2@1 - 48),
+ day => (_d1@1 - 48) * 10 + (_d2@1 - 48),
+ calendar => _calendar@1,
+ '__struct__' => 'Elixir.Date'}};
+ __@1 ->
+ case __@1 of
+ _ ->
+ {error,invalid_format};
+ __@2 ->
+ error({with_clause,__@2})
+ end
+ end.
diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk
index 7240b66fb5..98ab533a58 100644
--- a/lib/dialyzer/vsn.mk
+++ b/lib/dialyzer/vsn.mk
@@ -1 +1 @@
-DIALYZER_VSN = 3.3
+DIALYZER_VSN = 3.3.1
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index 7672598060..7c7fbeafef 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2016. All Rights Reserved.
+# Copyright Ericsson AB 2010-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 3232c3380a..4bfc98de40 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -43,6 +43,26 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 2.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix function_clause when sending an outgoing request
+ after DPA has been sent in response to an incoming DPR.
+ The caused the diameter_peer_fsm gen_server associated
+ with the peer connection to fail, which could then result
+ in the transport connection being reset before the peer
+ closed it upon reception of DPA.</p>
+ <p>
+ Own Id: OTP-15198 Aux Id: ERIERL-213 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 2.1.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index d99f11a697..cf5e7f21d3 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -901,7 +901,7 @@ outgoing(#diameter_packet{header = #diameter_header{is_request = false}}
ok;
%% Outgoing request: discard.
-outgoing(Msg, #state{dpr = {_,_,_}}) ->
+outgoing(Msg, #state{}) ->
invalid(false, send_after_dpr, header(Msg)).
header(#diameter_packet{header = H}) ->
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index 3389f11937..51830f5276 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -58,7 +58,8 @@
{"2.1.1", [{restart_application, diameter}]}, %% 20.1.2
{"2.1.2", [{restart_application, diameter}]}, %% 20.1.3
{"2.1.3", [{restart_application, diameter}]}, %% 20.2
- {"2.1.4", [{restart_application, diameter}]} %% 20.3
+ {"2.1.4", [{restart_application, diameter}]}, %% 20.3
+ {"2.1.5", [{update, diameter_peer_fsm}]} %% 21.0
],
[
{"0.9", [{restart_application, diameter}]},
@@ -98,6 +99,7 @@
{"2.1.1", [{restart_application, diameter}]},
{"2.1.2", [{restart_application, diameter}]},
{"2.1.3", [{restart_application, diameter}]},
- {"2.1.4", [{restart_application, diameter}]}
+ {"2.1.4", [{restart_application, diameter}]},
+ {"2.1.5", [{update, diameter_peer_fsm}]}
]
}.
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index 3081034df9..8c75c9e55e 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 2.1.5
+DIAMETER_VSN = 2.1.6
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml
index 2ef941b06d..e818887eb8 100644
--- a/lib/edoc/doc/src/notes.xml
+++ b/lib/edoc/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the EDoc
application.</p>
+<section><title>Edoc 0.9.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Edoc 0.9.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index bea9277e1f..0b3636f030 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.9.3
+EDOC_VSN = 0.9.4
diff --git a/lib/eldap/README b/lib/eldap/README
index e1bde9d658..238f140e93 100644
--- a/lib/eldap/README
+++ b/lib/eldap/README
@@ -23,7 +23,7 @@ system has been configured with SSL.
In the test directory there are some hints and examples
on how to test the code and how to setup and populate
an OpenLDAP server. The 'eldap' code has been tested
-agains OpenLDAP, IPlanet and ActiveDirectory servers.
+against OpenLDAP, IPlanet and ActiveDirectory servers.
If you plan to incorporate this code into your system
I suggest that you build a server/supervisor harnesk
diff --git a/lib/eldap/doc/src/notes.xml b/lib/eldap/doc/src/notes.xml
index ef7dda510c..bf9358c4d1 100644
--- a/lib/eldap/doc/src/notes.xml
+++ b/lib/eldap/doc/src/notes.xml
@@ -31,6 +31,37 @@
</header>
<p>This document describes the changes made to the Eldap application.</p>
+<section><title>Eldap 1.2.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Eldap 1.2.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.4</title>
<section><title>Improvements and New Features</title>
@@ -46,6 +77,22 @@
</section>
+<section><title>Eldap 1.2.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -61,6 +108,22 @@
</section>
+<section><title>Eldap 1.2.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A race condition at close could cause the eldap client to
+ exit with a badarg message as cause.</p>
+ <p>
+ Own Id: OTP-15342 Aux Id: ERIERL-242 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eldap 1.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -337,4 +400,3 @@
<p>New application. </p>
</section>
</chapter>
-
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index 2b84872b92..6497922852 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -957,10 +957,19 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) ->
do_unbind(Data) ->
Req = "",
log2(Data, "unbind request = ~p (has no reply)~n", [Req]),
- send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
case Data#eldap.using_tls of
- true -> ssl:close(Data#eldap.fd);
- false -> gen_tcp:close(Data#eldap.fd)
+ true ->
+ send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
+ ssl:close(Data#eldap.fd);
+ false ->
+ OldTrapExit = process_flag(trap_exit, true),
+ catch send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}),
+ catch gen_tcp:close(Data#eldap.fd),
+ receive
+ {'EXIT', _From, _Reason} -> ok
+ after 0 -> ok
+ end,
+ process_flag(trap_exit, OldTrapExit)
end,
{no_reply, Data#eldap{binddn = (#eldap{})#eldap.binddn,
passwd = (#eldap{})#eldap.passwd,
diff --git a/lib/eldap/test/make_certs.erl b/lib/eldap/test/make_certs.erl
index cfa43289e1..e8a13ae113 100644
--- a/lib/eldap/test/make_certs.erl
+++ b/lib/eldap/test/make_certs.erl
@@ -348,7 +348,7 @@ req_cnf(C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -394,7 +394,7 @@ ca_cnf(C) ->
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk
index f2b3cd47f2..6d541e4689 100644
--- a/lib/eldap/vsn.mk
+++ b/lib/eldap/vsn.mk
@@ -1 +1 @@
-ELDAP_VSN = 1.2.4
+ELDAP_VSN = 1.2.6
diff --git a/lib/erl_docgen/doc/src/doc-build.xml b/lib/erl_docgen/doc/src/doc-build.xml
index 3ea8798639..17e13bff81 100644
--- a/lib/erl_docgen/doc/src/doc-build.xml
+++ b/lib/erl_docgen/doc/src/doc-build.xml
@@ -178,7 +178,7 @@
</section>
<section>
- <title>Upcomming changes</title>
+ <title>Upcoming changes</title>
<p>
The output from the <c>erl_docgen</c> documentation build process is now just the OTP style.
But in a near future we will for example add the possibility to change logo, color in the PDF and
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 7a09b62351..97c842a324 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -31,7 +31,23 @@
</header>
<p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
- <section><title>Erl_Docgen 0.8</title>
+ <section><title>Erl_Docgen 0.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Indexing for the online search function has been
+ corrected for CREF documents.</p>
+ <p>
+ Own Id: OTP-14406</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erl_Docgen 0.8</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl
index b496614854..6bce577f08 100644
--- a/lib/erl_docgen/priv/xsl/db_eix.xsl
+++ b/lib/erl_docgen/priv/xsl/db_eix.xsl
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
- # Copyright Ericsson AB 2009-2016. All Rights Reserved.
+ # Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -199,11 +199,34 @@
<xsl:template name="name">
<xsl:param name="lastfuncsblock"/>
+ <xsl:variable name="signature">
+ <xsl:variable name="signature1">
+ <xsl:choose>
+ <xsl:when test="ancestor::cref">
+ <xsl:value-of
+ select="normalize-space(nametext)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of
+ select="normalize-space(substring-before(., '->'))"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="string-length($signature1) > 0">
+ <xsl:value-of select="$signature1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="normalize-space(.)"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+
<xsl:variable name="tmpstring">
- <xsl:value-of select="substring-before(substring-after(., '('), '->')"/>
+ <xsl:value-of select="substring-after($signature, '(')"/>
</xsl:variable>
- <xsl:variable name="ustring">
+ <xsl:variable name="argstring">
<xsl:choose>
<xsl:when test="string-length($tmpstring) > 0">
<xsl:call-template name="remove-paren">
@@ -219,10 +242,19 @@
</xsl:variable>
<xsl:variable name="arity">
- <xsl:call-template name="calc-arity">
- <xsl:with-param name="string" select="substring-before($ustring, ')')"/>
- <xsl:with-param name="no-of-pars" select="0"/>
- </xsl:call-template>
+ <xsl:choose>
+ <xsl:when
+ test="string-length(substring-before(., '->')) > 0">
+ <xsl:call-template name="calc-arity">
+ <xsl:with-param
+ name="string"
+ select="substring-before($argstring, ')')"/>
+ <xsl:with-param name="no-of-pars" select="0"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise/>
+ </xsl:choose>
+
</xsl:variable>
<xsl:variable name="fname">
@@ -250,10 +282,18 @@
</xsl:variable>
<xsl:text> {"</xsl:text><xsl:value-of select="$fname"/>
+ <xsl:text>", "</xsl:text>
+ <xsl:call-template name="escape-doublequotes">
+ <xsl:with-param name="string" select="$signature"/>
+ </xsl:call-template>
<xsl:text>", "</xsl:text><xsl:value-of select="$fname"/>
- <xsl:text>(</xsl:text><xsl:value-of select="normalize-space($tmpstring)"/>
- <xsl:text>", "</xsl:text><xsl:value-of select="$fname"/>
- <xsl:text>-</xsl:text><xsl:value-of select="$arity"/><xsl:text>"}</xsl:text>
+ <xsl:choose>
+ <xsl:when test="string-length($arity) > 0">
+ <xsl:text>-</xsl:text><xsl:value-of select="$arity"/>
+ </xsl:when>
+ <xsl:otherwise/>
+ </xsl:choose>
+ <xsl:text>"}</xsl:text>
<xsl:choose>
<xsl:when test="($lastfuncsblock = 'true') and (position() = last())">
@@ -345,6 +385,27 @@
</xsl:template>
+ <xsl:template name="escape-doublequotes">
+ <xsl:param name="string"/>
+ <xsl:param name="pPat">"</xsl:param>
+ <xsl:param name="pRep">\"</xsl:param>
+
+ <xsl:choose>
+ <xsl:when test="not(contains($string, $pPat))">
+ <xsl:copy-of select="$string"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="substring-before($string, $pPat)"/>
+ <xsl:copy-of select="$pRep"/>
+ <xsl:call-template name="escape-doublequotes">
+ <xsl:with-param
+ name="string"
+ select="substring-after($string, $pPat)"/>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
<!-- default content handling -->
<xsl:template match="text()"/>
diff --git a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index b065c18cda..d562cfddcc 100644
--- a/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -182,7 +182,7 @@ chapter_title(#xmlElement{content=Es}) -> % name = h3 | h4
%% otp_xmlify(Es1) -> Es2
%% Es1 = Es2 = [#xmlElement{} | #xmlText{}]
%% Fix things that are allowed in XHTML but not in chapter/erlref DTDs.
-%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) can not occur
+%% 1) lists (<ul>, <ol>, <dl>) and code snippets (<pre>) cannot occur
%% within a <p>, such a <p> must be splitted into a sequence of <p>,
%% <ul>, <ol>, <dl> and <pre>.
%% 2) <a> must only have either a href attribute (corresponds to a
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 0b24604daa..3b2f6db6a1 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.8
+ERL_DOCGEN_VSN = 0.8.1
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index a155ceef7e..46dd995289 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -29,11 +29,6 @@ dnl m4_define(EI_VERSION,regexp(m4_include(VERSION),[version \([-.0-9A-Za-z]+\)]
AC_INIT()
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
dnl How to set srcdir absolute is taken from the GNU Emacs distribution
#### Make srcdir absolute, if it isn't already. It's important to
#### avoid running the path through pwd unnecessary, since pwd can
diff --git a/lib/erl_interface/doc/src/Makefile b/lib/erl_interface/doc/src/Makefile
index 173bd2e83b..507a84a453 100644
--- a/lib/erl_interface/doc/src/Makefile
+++ b/lib/erl_interface/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1998-2017. All Rights Reserved.
+# Copyright Ericsson AB 1998-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml
index 1438317d8d..07ddd82718 100644
--- a/lib/erl_interface/doc/src/notes.xml
+++ b/lib/erl_interface/doc/src/notes.xml
@@ -31,6 +31,53 @@
</header>
<p>This document describes the changes made to the Erl_interface application.</p>
+<section><title>Erl_Interface 3.10.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Make <c>ei_connect</c> and friends also accept state
+ <c>ok_simultaneous</c> during handshake, which means the
+ other node has initiated a connection setup that will be
+ cancelled in favor of this connection.</p>
+ <p>
+ Own Id: OTP-15161 Aux Id: ERIERL-191 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ei_receive_msg</c>,
+ <c>ei_xreceive_msg</c>, <c>ei_receive_msg_tmo</c> and
+ <c>ei_xreceive_msg_tmo</c>. The <c>x-&gt;index</c> was
+ set to entire buffer size instead of the number of bytes
+ actually received.</p>
+ <p>
+ Own Id: OTP-15171</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>ei_connect_init</c> which could be
+ provoked if called by concurrent threads.
+ <c>ei_connect_init</c> called posix interface
+ <c>gethostbyname</c> which is documented as not thread
+ safe.</p>
+ <p>
+ Own Id: OTP-15191</p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in erl_compare_ext() ignoring the tail of lists
+ of otherwise equal content. Example: <c>[a | b]</c> and
+ <c>[a | c]</c> compared equal and <c>{[a], b}</c> and
+ <c>{[a], c}</c> compared equal.</p>
+ <p>
+ Own Id: OTP-15277 Aux Id: PR-1929 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erl_Interface 3.10.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/erl_interface/src/INSTALL b/lib/erl_interface/src/INSTALL
index b42a17ac46..bf3ca8b6a5 100644
--- a/lib/erl_interface/src/INSTALL
+++ b/lib/erl_interface/src/INSTALL
@@ -122,10 +122,10 @@ you can use the `configure' options `--x-includes=DIR' and
Specifying the System Type
==========================
- There may be some features `configure' can not figure out
+ There may be some features `configure' cannot figure out
automatically, but needs to determine by the type of host the package
will run on. Usually `configure' can figure that out, but if it prints
-a message saying it can not guess the host type, give it the
+a message saying it cannot guess the host type, give it the
`--host=TYPE' option. TYPE can either be a short name for the system
type, such as `sun4', or a canonical name with three fields:
CPU-COMPANY-SYSTEM
diff --git a/lib/erl_interface/src/README.internal b/lib/erl_interface/src/README.internal
index c1f2d6863f..42c45b46a9 100644
--- a/lib/erl_interface/src/README.internal
+++ b/lib/erl_interface/src/README.internal
@@ -167,12 +167,12 @@ NOTE!!!! Sending a "char" to macros like isupper(), isalpha() where
the character is > 127 will cause serios problems on some
machines/OS. The reason is that
- 'char' may be unsigned, i.e. the Swedish char '�' will
+ 'char' may be unsigned, i.e. the Swedish char 'ä' will
as a number be negativ.
The implementation of isupper() and others will on some
machines use an array that is indexed with the incoming
- character code. The Swedish '�' will then create an access
+ character code. The Swedish 'ä' will then create an access
on memory outside the array!
This may give a random value as a result or a segmentation
@@ -219,7 +219,7 @@ There are some functions in the 'ei' library that uses the GCC and
VC++ "long long" type. Unfortunately this can lead to some trouble.
When user code is linked with the "libei.a" the linker will extract
-all objects files needed for resolving all symbol referenses
+all objects files needed for resolving all symbol references
found. This means that you want to follow the rule that
* To reduce executable code size we use resonably small C source
@@ -252,7 +252,7 @@ example is that in plain R9C the ei_x_encode_longlong() function is
located in the file "ei_x_encode.c". So if any "long long" ei_x
function is used we have an unessesary dependency on
"ei_encode_longlong.o" and then need to link with GNU ld on with the
-user code or explicitely link with "libgcc.a". The situation can be
+user code or explicitly link with "libgcc.a". The situation can be
visible in in plain R9C using
% nm -A erl_interface-3.4/lib/libei.a | \
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 75b705a8fa..9df4fa3b6c 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1022,7 +1022,7 @@ int ei_do_receive_msg(int fd, int staticbuffer_p,
erl_errno = EMSGSIZE;
return ERL_ERROR;
}
- x->index = x->buffsz;
+ x->index = msglen;
switch (msg->msgtype) { /* FIXME does not handle trace tokens and monitors */
case ERL_SEND:
case ERL_REG_SEND:
diff --git a/lib/erl_interface/src/legacy/erl_marshal.c b/lib/erl_interface/src/legacy/erl_marshal.c
index c18067b9bc..932bba43bf 100644
--- a/lib/erl_interface/src/legacy/erl_marshal.c
+++ b/lib/erl_interface/src/legacy/erl_marshal.c
@@ -1803,7 +1803,7 @@ static int cmp_exe2(unsigned char **e1, unsigned char **e2)
k = 0;
while (1) {
if (k++ == min){
- if (i == j) return 0;
+ if (i == j) return compare_top_ext(e1 , e2);
if (i < j) return -1;
return 1;
}
diff --git a/lib/erl_interface/src/misc/ei_pthreads.c b/lib/erl_interface/src/misc/ei_pthreads.c
index 25608edeec..c6d07a9a0a 100644
--- a/lib/erl_interface/src/misc/ei_pthreads.c
+++ b/lib/erl_interface/src/misc/ei_pthreads.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -78,7 +78,7 @@ static void tls_init_once(void)
errno_tls_index = TlsAlloc();
if (errno_tls_index == TLS_OUT_OF_INDEXES) {
fprintf(stderr,
- "FATAL ERROR: can not allocate TLS index for "
+ "FATAL ERROR: cannot allocate TLS index for "
"erl_errno (error code = %d)!\n",GetLastError());
exit(1);
}
@@ -206,6 +206,7 @@ volatile int *__erl_errno_place(void)
use_fallback = 1;
return &fallback_errno;
}
+ *erl_errno_p = 0;
if (pthread_setspecific(erl_errno_key, erl_errno_p) != 0 ||
(erl_errno_p = pthread_getspecific(erl_errno_key)) == NULL) {
diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl
index 85c567acd3..78a433d21b 100644
--- a/lib/erl_interface/test/ei_accept_SUITE.erl
+++ b/lib/erl_interface/test/ei_accept_SUITE.erl
@@ -25,6 +25,7 @@
-include("ei_accept_SUITE_data/ei_accept_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
ei_accept/1, ei_threaded_accept/1,
monitor_ei_process/1]).
@@ -38,8 +39,11 @@ all() ->
[ei_accept, ei_threaded_accept,
monitor_ei_process].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
ei_accept(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
@@ -91,7 +95,7 @@ ei_threaded_accept(Config) when is_list(Config) ->
%% Test erlang:monitor toward erl_interface "processes"
monitor_ei_process(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
Myname = hd(tl(string:tokens(atom_to_list(node()), "@"))),
@@ -99,7 +103,6 @@ monitor_ei_process(Config) when is_list(Config) ->
EINode = list_to_atom("c42@"++Myname),
io:format("EINode ~p ~n", [EINode]),
- Self = self(),
Port = 6543,
{ok, ListenFd} = ei_publish(P, Port),
MRef1 = erlang:monitor(process, {any, EINode}),
diff --git a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
index 04bba90732..50df848b69 100644
--- a/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
+++ b/lib/erl_interface/test/ei_accept_SUITE_data/ei_accept_test.c
@@ -75,11 +75,7 @@ TESTCASE(interpret)
ei_term term;
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -100,8 +96,9 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
}
static void cmd_ei_connect_init(char* buf, int len)
diff --git a/lib/erl_interface/test/ei_connect_SUITE.erl b/lib/erl_interface/test/ei_connect_SUITE.erl
index 66498deadc..75b6bf18da 100644
--- a/lib/erl_interface/test/ei_connect_SUITE.erl
+++ b/lib/erl_interface/test/ei_connect_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_connect_SUITE_data/ei_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
ei_send/1,
ei_reg_send/1,
ei_format_pid/1,
@@ -44,8 +45,11 @@ all() ->
[ei_send, ei_reg_send, ei_rpc, ei_format_pid, ei_send_funs,
ei_threaded_send, ei_set_get_tracelevel].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
ei_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -58,7 +62,7 @@ ei_send(Config) when is_list(Config) ->
ei_format_pid(Config) when is_list(Config) ->
S = self(),
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -70,7 +74,7 @@ ei_format_pid(Config) when is_list(Config) ->
ok.
ei_send_funs(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -88,7 +92,7 @@ ei_send_funs(Config) when is_list(Config) ->
ok.
ei_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -137,7 +141,7 @@ start_einode(Einode, N, Host) ->
ok.
ei_rpc(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
@@ -150,7 +154,7 @@ ei_rpc(Config) when is_list(Config) ->
ok.
ei_set_get_tracelevel(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
5 = ei_set_get_tracelevel(P, 5),
0 = ei_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = ei_connect(P, node()),
diff --git a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
index 6a3796dd24..29c03d7604 100644
--- a/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
+++ b/lib/erl_interface/test/ei_connect_SUITE_data/ei_connect_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -74,11 +74,7 @@ TESTCASE(interpret)
ei_term term;
ei_x_new(&x);
- for (;;) {
- if (get_bin_term(&x, &term)) {
- report(1);
- return;
- } else {
+ while (get_bin_term(&x, &term) == 0) {
char* buf = x.buff, func[MAXATOMLEN];
int index = x.index, arity;
if (term.ei_type != ERL_SMALL_TUPLE_EXT || term.arity != 2)
@@ -99,8 +95,10 @@ TESTCASE(interpret)
message("\"%d\" \n", func);
fail("bad command");
}
- }
- }
+ }
+ report(1);
+ ei_x_free(&x);
+ return;
}
diff --git a/lib/erl_interface/test/ei_decode_SUITE.erl b/lib/erl_interface/test/ei_decode_SUITE.erl
index 74fb9b8916..75560ea7c9 100644
--- a/lib/erl_interface/test/ei_decode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_decode_SUITE_data/ei_decode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_long/1,
test_ei_decode_ulong/1,
test_ei_decode_longlong/1,
@@ -42,6 +43,9 @@ all() ->
test_ei_decode_char, test_ei_decode_nonoptimal,
test_ei_decode_misc, test_ei_decode_utf8_atom].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: for historical reasons we don't pach as tight as we can,
@@ -51,7 +55,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_long),
+ P = runner:start(Config, ?test_ei_decode_long),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -60,7 +64,7 @@ test_ei_decode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_ulong),
+ P = runner:start(Config, ?test_ei_decode_ulong),
send_integers(P),
runner:recv_eot(P),
ok.
@@ -77,7 +81,7 @@ test_ei_decode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_longlong),
+ P = runner:start(Config, ?test_ei_decode_longlong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -91,7 +95,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_decode_ulonglong),
+ P = runner:start(Config, ?test_ei_decode_ulonglong),
send_integers2(P),
runner:recv_eot(P),
ok
@@ -104,7 +108,7 @@ test_ei_decode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_decode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_char),
+ P = runner:start(Config, ?test_ei_decode_char),
send_term_as_binary(P,0),
send_term_as_binary(P,16#7f),
@@ -119,7 +123,7 @@ test_ei_decode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_nonoptimal(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_nonoptimal),
+ P = runner:start(Config, ?test_ei_decode_nonoptimal),
send_non_optimal_pos(P), % decode_char
send_non_optimal(P), % decode_long
@@ -168,7 +172,7 @@ send_non_optimal_neg(P) ->
%% ######################################################################## %%
test_ei_decode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_misc),
+ P = runner:start(Config, ?test_ei_decode_misc),
send_term_as_binary(P,0.0),
send_term_as_binary(P,-1.0),
@@ -199,7 +203,7 @@ test_ei_decode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_decode_utf8_atom(Config) ->
- P = runner:start(?test_ei_decode_utf8_atom),
+ P = runner:start(Config, ?test_ei_decode_utf8_atom),
send_latin1_atom_as_binary(P,"å"),
send_latin1_atom_as_binary(P,"ä"),
diff --git a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
index b7a2c4bb8b..f945a7d378 100644
--- a/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
+++ b/lib/erl_interface/test/ei_decode_SUITE_data/ei_decode_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -105,6 +105,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail1("size of encoded data (%d) is incorrect", size1); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_2_FAIL(FUNC,SIZE,TYPE,VAL) \
@@ -148,6 +149,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
#define dump(arr, num) { \
@@ -205,6 +207,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data is incorrect"); \
return; \
} \
+ free_packet(buf); \
} \
#define EI_DECODE_STRING(FUNC,SIZE,VAL) \
@@ -248,6 +251,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data should be 0"); \
return; \
} \
+ free_packet(buf); \
} \
//#define EI_DECODE_UTF8_STRING(FUNC,SIZE,VAL)
@@ -310,6 +314,7 @@ int ei_decode_my_string(const char *buf, int *index, char *to,
fail("size of encoded data is incorrect"); \
return; \
} \
+ free_packet(buf); \
} \
/* ******************************************************************** */
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE.erl b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
index 160720b413..0f23cdfbb9 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_decode_encode_SUITE_data/ei_decode_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_decode_encode/1]).
suite() ->
@@ -33,6 +34,9 @@ suite() ->
all() ->
[test_ei_decode_encode].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
% NOTE: these types have no meaning on the C side so we pass them
@@ -42,7 +46,7 @@ all() ->
%% ######################################################################## %%
test_ei_decode_encode(Config) when is_list(Config) ->
- P = runner:start(?test_ei_decode_encode),
+ P = runner:start(Config, ?test_ei_decode_encode),
Fun = fun (X) -> {X,true} end,
Pid = self(),
diff --git a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
index 467f789fdb..9977683d59 100644
--- a/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
+++ b/lib/erl_interface/test/ei_decode_encode_SUITE_data/ei_decode_encode_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2004-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2004-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -466,6 +466,7 @@ void decode_encode_big(struct Type* t)
send_buffer(arg.buff, arg.index);
ei_x_free(&arg);
ei_free_big(p);
+ free_packet(buf);
}
diff --git a/lib/erl_interface/test/ei_encode_SUITE.erl b/lib/erl_interface/test/ei_encode_SUITE.erl
index 8857b092f3..0267a5126f 100644
--- a/lib/erl_interface/test/ei_encode_SUITE.erl
+++ b/lib/erl_interface/test/ei_encode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_encode_SUITE_data/ei_encode_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
test_ei_encode_long/1,
test_ei_encode_ulong/1,
test_ei_encode_longlong/1,
@@ -45,6 +46,9 @@ all() ->
test_ei_encode_fails, test_ei_encode_utf8_atom,
test_ei_encode_utf8_atom_len].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% ---------------------------------------------------------------------------
@@ -55,7 +59,7 @@ all() ->
%% ######################################################################## %%
test_ei_encode_long(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_long),
+ P = runner:start(Config, ?test_ei_encode_long),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -77,7 +81,7 @@ test_ei_encode_long(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_ulong(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_ulong),
+ P = runner:start(Config, ?test_ei_encode_ulong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -101,7 +105,7 @@ test_ei_encode_longlong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_longlong),
+ P = runner:start(Config, ?test_ei_encode_longlong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -132,7 +136,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?test_ei_encode_ulonglong),
+ P = runner:start(Config, ?test_ei_encode_ulonglong),
{<<97,0>> ,0} = get_buf_and_term(P),
{<<97,255>> ,255} = get_buf_and_term(P),
@@ -158,7 +162,7 @@ test_ei_encode_ulonglong(Config) when is_list(Config) ->
%% FIXME maybe the API should change to use "unsigned char" to be clear?!
test_ei_encode_char(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_char),
+ P = runner:start(Config, ?test_ei_encode_char),
{<<97, 0>>,0} = get_buf_and_term(P),
{<<97,127>>,16#7f} = get_buf_and_term(P),
@@ -171,7 +175,7 @@ test_ei_encode_char(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_misc(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_misc),
+ P = runner:start(Config, ?test_ei_encode_misc),
<<131>> = get_binaries(P),
@@ -217,7 +221,7 @@ test_ei_encode_misc(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_fails(Config) when is_list(Config) ->
- P = runner:start(?test_ei_encode_fails),
+ P = runner:start(Config, ?test_ei_encode_fails),
XAtom = list_to_atom(lists:duplicate(255, $x)),
YAtom = list_to_atom(lists:duplicate(255, $y)),
@@ -236,7 +240,7 @@ test_ei_encode_fails(Config) when is_list(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
@@ -251,7 +255,7 @@ test_ei_encode_utf8_atom(Config) ->
%% ######################################################################## %%
test_ei_encode_utf8_atom_len(Config) ->
- P = runner:start(?test_ei_encode_utf8_atom_len),
+ P = runner:start(Config, ?test_ei_encode_utf8_atom_len),
{<<119,2,195,133>>,'Å'} = get_buf_and_term(P),
{<<119,4,195,133,195,132>>,'ÅÄ'} = get_buf_and_term(P),
diff --git a/lib/erl_interface/test/ei_format_SUITE.erl b/lib/erl_interface/test/ei_format_SUITE.erl
index 07ee479b1f..e074c184c1 100644
--- a/lib/erl_interface/test/ei_format_SUITE.erl
+++ b/lib/erl_interface/test/ei_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
-export([format_wo_ver/1,
all/0, suite/0,
+ init_per_testcase/2,
atoms/1,
tuples/1,
lists/1]).
@@ -41,10 +42,13 @@ suite() ->
all() ->
[format_wo_ver, atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -84,7 +88,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -105,7 +109,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
@@ -146,7 +150,7 @@ lists(Config) when is_list(Config) ->
format_wo_ver(Config) when is_list(Config) ->
- P = runner:start(?format_wo_ver),
+ P = runner:start(Config, ?format_wo_ver),
{term, [-1, 2, $c, {a, "b"}, {c, 10}]} = get_term(P),
diff --git a/lib/erl_interface/test/ei_print_SUITE.erl b/lib/erl_interface/test/ei_print_SUITE.erl
index 6d5c341eae..c75ce55a7d 100644
--- a/lib/erl_interface/test/ei_print_SUITE.erl
+++ b/lib/erl_interface/test/ei_print_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("ei_print_SUITE_data/ei_print_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1, strings/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, "''"} = get_term(P),
{term, "a"} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, "{}"} = get_term(P),
{term, "{a}"} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, "[]"} = get_term(P),
{term, "[a]"} = get_term(P),
@@ -125,7 +129,7 @@ lists(Config) when is_list(Config) ->
ok.
strings(Config) when is_list(Config) ->
- P = runner:start(?strings),
+ P = runner:start(Config, ?strings),
{term, "\"\\n\""} = get_term(P),
{term, "\"\\r\\n\""} = get_term(P),
diff --git a/lib/erl_interface/test/ei_tmo_SUITE.erl b/lib/erl_interface/test/ei_tmo_SUITE.erl
index 003fe20594..5b9de80128 100644
--- a/lib/erl_interface/test/ei_tmo_SUITE.erl
+++ b/lib/erl_interface/test/ei_tmo_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,14 +39,16 @@ all() ->
[framework_check, ei_accept_tmo, ei_connect_tmo,
ei_send_tmo, ei_recv_tmo].
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
+ Config1 = runner:init_per_testcase(?MODULE, Case, Config),
+
% test if platform is vxworks_simso
{_,Host} = split(node()),
Bool = case atom_to_list(Host) of
[$v,$x,$s,$i,$m | _] -> true;
_ -> false
end,
- [{vxsim,Bool}|Config].
+ [{vxsim,Bool} | Config1].
end_per_testcase(_Case, _Config) ->
ok.
@@ -55,7 +57,7 @@ end_per_testcase(_Case, _Config) ->
framework_check(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?framework_check),
+ P = runner:start(Config, ?framework_check),
runner:send_term(P,{hello,world}),
{term, {hello,world}} = runner:get_term(P),
runner:recv_eot(P),
@@ -71,7 +73,7 @@ ei_recv_tmo(Config) when is_list(Config) ->
do_one_recv(Config,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -84,7 +86,7 @@ do_one_recv(Config,CNode) ->
runner:recv_eot(P1).
do_one_recv_failure(Config,CNode) ->
- P1 = runner:start(?recv_tmo),
+ P1 = runner:start(Config, ?recv_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -110,7 +112,7 @@ ei_send_tmo(Config) when is_list(Config) ->
do_one_send(Config,From,CNode) ->
{_,Host} = split(node()),
- P1 = runner:start(?send_tmo),
+ P1 = runner:start(Config, ?send_tmo),
runner:send_term(P1,{CNode,
erlang:get_cookie(),
node()}),
@@ -139,7 +141,7 @@ do_one_send_failure(Config,From,FakeName,CName,VxSim) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?send_tmo),
+ P3 = runner:start(Config, ?send_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{CName,
Cookie,
@@ -202,7 +204,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
%dbg:p(self()),
VxSim = proplists:get_value(vxsim, Config),
DummyNode = make_and_check_dummy(),
- P = runner:start(?connect_tmo),
+ P = runner:start(Config, ?connect_tmo),
runner:send_term(P,{c_nod_connect_tmo_1,
kaksmula_som_ingen_bryr_sig_om,
DummyNode}),
@@ -219,7 +221,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
end
end,
runner:recv_eot(P),
- P2 = runner:start(?connect_tmo),
+ P2 = runner:start(Config, ?connect_tmo),
runner:send_term(P2,{c_nod_connect_tmo_2,
erlang:get_cookie(),
node()}),
@@ -237,7 +239,7 @@ ei_connect_tmo(Config) when is_list(Config) ->
exit(Else)
end,
EpmdSocket = register(OurName, LSocket, 1, 5),
- P3 = runner:start(?connect_tmo),
+ P3 = runner:start(Config, ?connect_tmo),
Cookie = kaksmula_som_ingen_bryr_sig_om,
runner:send_term(P3,{c_nod_connect_tmo_3,
Cookie,
@@ -266,12 +268,12 @@ ei_connect_tmo(Config) when is_list(Config) ->
ei_accept_tmo(Config) when is_list(Config) ->
%%dbg:tracer(),
%%dbg:p(self()),
- P = runner:start(?accept_tmo),
+ P = runner:start(Config, ?accept_tmo),
runner:send_term(P,{c_nod_som_ingen_kontaktar_1,
kaksmula_som_ingen_bryr_sig_om}),
{term,{-1,ETimedout,ETimedout}} = runner:get_term(P, 10000),
runner:recv_eot(P),
- P2 = runner:start(?accept_tmo),
+ P2 = runner:start(Config, ?accept_tmo),
runner:send_term(P2,{c_nod_som_vi_kontaktar_1,
erlang:get_cookie()}),
receive after 1000 -> ok end,
@@ -280,7 +282,7 @@ ei_accept_tmo(Config) when is_list(Config) ->
{term, X} = runner:get_term(P2, 10000),
runner:recv_eot(P2),
true = is_integer(X),
- P3 = runner:start(?accept_tmo),
+ P3 = runner:start(Config, ?accept_tmo),
runner:send_term(P3,{c_nod_som_vi_kontaktar_2,
erlang:get_cookie()}),
receive after 1000 -> ok end,
diff --git a/lib/erl_interface/test/erl_connect_SUITE.erl b/lib/erl_interface/test/erl_connect_SUITE.erl
index cd73f07b8f..782691b8fb 100644
--- a/lib/erl_interface/test/erl_connect_SUITE.erl
+++ b/lib/erl_interface/test/erl_connect_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_connect_SUITE_data/erl_connect_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
erl_send/1, erl_reg_send/1,
erl_send_cookie_file/1]).
@@ -38,8 +39,11 @@ all() ->
[erl_send, erl_reg_send, erl_send_cookie_file].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
erl_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
@@ -56,7 +60,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
vxworks ->
{skip,"Skipped on VxWorks"};
_ ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, '', 0),
{ok,Fd} = erl_connect(P, node()),
@@ -70,7 +74,7 @@ erl_send_cookie_file(Config) when is_list(Config) ->
end.
erl_reg_send(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
1 = erl_connect_init(P, 42, erlang:get_cookie(), 0),
{ok,Fd} = erl_connect(P, node()),
diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl
index 3d1e33081b..77910a9fc7 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE.erl
+++ b/lib/erl_interface/test/erl_eterm_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-export([all/0, suite/0,
+ init_per_testcase/2,
build_terms/1, round_trip_conversion/1,
decode_terms/1, decode_float/1,
t_erl_mk_int/1, t_erl_mk_list/1,
@@ -94,6 +95,9 @@ all() ->
high_chaparal, broken_data, cnode_1].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 1. B a s i c t e s t s
@@ -104,7 +108,7 @@ all() ->
%% a list and verifies that the result is as expected.
build_terms(Config) when is_list(Config) ->
- P = runner:start(?build_terms),
+ P = runner:start(Config, ?build_terms),
{term, Term} = get_term(P),
io:format("Received: ~p", [Term]),
[ARefLN, ARef, APortLN, APort, APidLN, APid,
@@ -136,7 +140,7 @@ build_terms(Config) when is_list(Config) ->
%% This test is run entirely in C code.
round_trip_conversion(Config) when is_list(Config) ->
- runner:test(?round_trip_conversion),
+ runner:test(Config, ?round_trip_conversion),
ok.
%% This test sends a list of all data types to the C code function,
@@ -156,7 +160,7 @@ decode_terms(Config) when is_list(Config) ->
{element1, 42, 767}, "A string",
1, -1, 0, 3.0, ABinary, 'I am an atom'],
- P = runner:start(?decode_terms),
+ P = runner:start(Config, ?decode_terms),
runner:send_term(P, Terms),
runner:recv_eot(P),
@@ -165,7 +169,7 @@ decode_terms(Config) when is_list(Config) ->
%% Decodes the floating point number 3.1415.
decode_float(Config) when is_list(Config) ->
- P = runner:start(?decode_float),
+ P = runner:start(Config, ?decode_float),
runner:send_term(P, 3.1415),
runner:recv_eot(P),
ok.
@@ -173,7 +177,7 @@ decode_float(Config) when is_list(Config) ->
%% Tests the erl_free_compound() function.
t_erl_free_compound(Config) when is_list(Config) ->
- runner:test(?t_erl_free_compound),
+ runner:test(Config, ?t_erl_free_compound),
ok.
@@ -186,7 +190,7 @@ t_erl_free_compound(Config) when is_list(Config) ->
%% This tests the erl_mk_list() function.
t_erl_mk_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_list),
+ P = runner:start(Config, ?t_erl_mk_list),
{term, []} = get_term(P),
{term, [abc]} = get_term(P),
@@ -200,7 +204,7 @@ t_erl_mk_list(Config) when is_list(Config) ->
%% This tests the erl_mk_int() function.
t_erl_mk_int(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_int),
+ P = runner:start(Config, ?t_erl_mk_int),
{term, 0} = get_term(P),
{term, 127} = get_term(P),
@@ -255,14 +259,14 @@ t_erl_mk_int(Config) when is_list(Config) ->
%% Basic test of erl_copy_term().
basic_copy(Config) when is_list(Config) ->
- runner:test(?basic_copy),
+ runner:test(Config, ?basic_copy),
ok.
%% This tests the erl_mk_tuple() function.
t_erl_mk_tuple(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_tuple),
+ P = runner:start(Config, ?t_erl_mk_tuple),
{term, {madonna, 21, 'mad donna', 12}} = get_term(P),
{term, {'Madonna',21,{children,{"Isabella",2}},
@@ -275,7 +279,7 @@ t_erl_mk_tuple(Config) when is_list(Config) ->
%% This tests the erl_mk_atom() function.
t_erl_mk_atom(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_atom),
+ P = runner:start(Config, ?t_erl_mk_atom),
{term, madonna} = (get_term(P)),
{term, 'Madonna'} = (get_term(P)),
@@ -295,7 +299,7 @@ t_erl_mk_atom(Config) when is_list(Config) ->
%% This tests the erl_mk_binary() function.
t_erl_mk_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_binary),
+ P = runner:start(Config, ?t_erl_mk_binary),
{term, Bin} = (get_term(P)),
"{madonna,21,'mad donna',1234.567.890, !#$%&/()=?+-@, \" \\}" = binary_to_list(Bin),
@@ -307,7 +311,7 @@ t_erl_mk_binary(Config) when is_list(Config) ->
%% This tests the erl_mk_empty_list() function.
t_erl_mk_empty_list(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_empty_list),
+ P = runner:start(Config, ?t_erl_mk_empty_list),
{term, []} = get_term(P),
@@ -322,7 +326,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
vxworks ->
{skipped, "Floating point numbers never compare equal on PPC"};
_ ->
- P = runner:start(?t_erl_mk_float),
+ P = runner:start(Config, ?t_erl_mk_float),
{term, {3.1415, 1.999999, 2.000000, 2.000001,
2.000002, 12345.67890}} = get_term(P),
runner:recv_eot(P),
@@ -333,7 +337,7 @@ t_erl_mk_float(Config) when is_list(Config) ->
%% This tests the erl_mk_pid() function.
t_erl_mk_pid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_pid),
+ P = runner:start(Config, ?t_erl_mk_pid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 3, 2} = nc2vinfo(A_pid),
@@ -342,7 +346,7 @@ t_erl_mk_pid(Config) when is_list(Config) ->
ok.
t_erl_mk_xpid(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xpid),
+ P = runner:start(Config, ?t_erl_mk_xpid),
{term, A_pid} = (get_term(P)),
{pid, kalle@localhost, 32767, 8191} = nc2vinfo(A_pid),
@@ -354,7 +358,7 @@ t_erl_mk_xpid(Config) when is_list(Config) ->
%% This tests the erl_mk_port() function.
t_erl_mk_port(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_port),
+ P = runner:start(Config, ?t_erl_mk_port),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 4} = nc2vinfo(A_port),
@@ -363,7 +367,7 @@ t_erl_mk_port(Config) when is_list(Config) ->
ok.
t_erl_mk_xport(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_xport),
+ P = runner:start(Config, ?t_erl_mk_xport),
{term, A_port} = (get_term(P)),
{port, kalle@localhost, 268435455} = nc2vinfo(A_port),
@@ -375,7 +379,7 @@ t_erl_mk_xport(Config) when is_list(Config) ->
%% This tests the erl_mk_ref() function.
t_erl_mk_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_ref),
+ P = runner:start(Config, ?t_erl_mk_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [6]} = nc2vinfo(A_ref),
@@ -384,7 +388,7 @@ t_erl_mk_ref(Config) when is_list(Config) ->
ok.
t_erl_mk_long_ref(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_long_ref),
+ P = runner:start(Config, ?t_erl_mk_long_ref),
{term, A_ref} = (get_term(P)),
{ref, kalle@localhost, _Length, [4294967295,4294967295,262143]}
@@ -397,7 +401,7 @@ t_erl_mk_long_ref(Config) when is_list(Config) ->
%% This tests the erl_mk_string() function.
t_erl_mk_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_string),
+ P = runner:start(Config, ?t_erl_mk_string),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -417,7 +421,7 @@ t_erl_mk_string(Config) when is_list(Config) ->
%% This tests the erl_mk_estring() function.
t_erl_mk_estring(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_estring),
+ P = runner:start(Config, ?t_erl_mk_estring),
{term, "madonna"} = (get_term(P)),
{term, "Madonna"} = (get_term(P)),
@@ -437,7 +441,7 @@ t_erl_mk_estring(Config) when is_list(Config) ->
%% This tests the erl_mk_uint() function.
t_erl_mk_uint(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_uint),
+ P = runner:start(Config, ?t_erl_mk_uint),
{term, 54321} = (get_term(P)),
{term, 2147483647} = (get_term(P)),
@@ -453,7 +457,7 @@ t_erl_mk_uint(Config) when is_list(Config) ->
%% This tests the erl_mk_var() function.
t_erl_mk_var(Config) when is_list(Config) ->
- P = runner:start(?t_erl_mk_var),
+ P = runner:start(Config, ?t_erl_mk_var),
{term, 1} = (get_term(P)),
{term, 0} = (get_term(P)),
@@ -470,7 +474,7 @@ t_erl_mk_var(Config) when is_list(Config) ->
%% This tests the erl_cons() function.
t_erl_cons(Config) when is_list(Config) ->
- P = runner:start(?t_erl_cons),
+ P = runner:start(Config, ?t_erl_cons),
{term, [madonna, 21]} = get_term(P),
@@ -490,7 +494,7 @@ t_erl_cons(Config) when is_list(Config) ->
%% Tests the erl_length() function.
t_erl_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_length),
+ P = runner:start(Config, ?t_erl_length),
0 = erl_length(P, []),
1 = erl_length(P, [a]),
@@ -513,7 +517,7 @@ erl_length(Port, List) ->
%% Tests the erl_hd() function.
t_erl_hd(Config) when is_list(Config) ->
- P = runner:start(?t_erl_hd),
+ P = runner:start(Config, ?t_erl_hd),
'NULL' = erl_hd(P, 42),
'NULL' = erl_hd(P, abc),
@@ -537,7 +541,7 @@ erl_hd(Port, List) ->
%% Tests the erl_tail() function.
t_erl_tl(Config) when is_list(Config) ->
- P = runner:start(?t_erl_tl),
+ P = runner:start(Config, ?t_erl_tl),
'NULL' = erl_tl(P, 42),
'NULL' = erl_tl(P, abc),
@@ -561,20 +565,20 @@ erl_tl(Port, List) ->
%% Tests the type checking macros (done in the C program).
type_checks(Config) when is_list(Config) ->
- runner:test(?type_checks),
+ runner:test(Config, ?type_checks),
ok.
%% Tests the extractor macros (done in the C program).
extractor_macros(Config) when is_list(Config) ->
- runner:test(?extractor_macros),
+ runner:test(Config, ?extractor_macros),
ok.
%% This tests the erl_size() function.
t_erl_size(Config) when is_list(Config) ->
- P = runner:start(?t_erl_size),
+ P = runner:start(Config, ?t_erl_size),
{term, 0} = (get_term(P)),
{term, 4} = (get_term(P)),
@@ -589,7 +593,7 @@ t_erl_size(Config) when is_list(Config) ->
%% This tests the erl_var_content() function.
t_erl_var_content(Config) when is_list(Config) ->
- P = runner:start(?t_erl_var_content),
+ P = runner:start(Config, ?t_erl_var_content),
{term, 17} = (get_term(P)),
{term, "http://www.madonna.com"} = (get_term(P)),
@@ -604,7 +608,7 @@ t_erl_var_content(Config) when is_list(Config) ->
%% This tests the erl_element() function.
t_erl_element(Config) when is_list(Config) ->
- P = runner:start(?t_erl_element),
+ P = runner:start(Config, ?t_erl_element),
{term, madonna} = get_term(P),
{term, 21} = get_term(P),
@@ -630,7 +634,7 @@ t_erl_element(Config) when is_list(Config) ->
%% Tests the erl_iolist_length() function.
t_erl_iolist_length(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_length),
+ P = runner:start(Config, ?t_erl_iolist_length),
%% Flat lists.
@@ -697,7 +701,7 @@ erl_iolist_length(Port, List) ->
%% Tests the erl_iolist_to_binary() function.
t_erl_iolist_to_binary(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_binary),
+ P = runner:start(Config, ?t_erl_iolist_to_binary),
%% Flat lists.
@@ -768,7 +772,7 @@ iolist_to_list(Port, Term) ->
%% Tests the erl_iolist_to_string() function.
t_erl_iolist_to_string(Config) when is_list(Config) ->
- P = runner:start(?t_erl_iolist_to_string),
+ P = runner:start(Config, ?t_erl_iolist_to_string),
%% Flat lists.
@@ -947,14 +951,14 @@ collect_line1([C|Rest], Result) ->
%% Test case submitted by Per Lundgren, ERV.
high_chaparal(Config) when is_list(Config) ->
- P = runner:start(?high_chaparal),
+ P = runner:start(Config, ?high_chaparal),
{term, [hello, world]} = get_term(P),
runner:recv_eot(P),
ok.
%% OTP-7448
broken_data(Config) when is_list(Config) ->
- P = runner:start(?broken_data),
+ P = runner:start(Config, ?broken_data),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_ext_SUITE.erl b/lib/erl_interface/test/erl_ext_SUITE.erl
index afaba1fd93..ff3b495f7b 100644
--- a/lib/erl_interface/test/erl_ext_SUITE.erl
+++ b/lib/erl_interface/test/erl_ext_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_ext_SUITE_data/ext_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
compare_tuple/1,
compare_list/1,
compare_string/1,
@@ -40,28 +41,30 @@ all() ->
[compare_tuple, compare_list, compare_string,
compare_list_string, compare_nc_ext].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
compare_tuple(Config) when is_list(Config) ->
- P = runner:start(?compare_tuple),
+ P = runner:start(Config, ?compare_tuple),
runner:recv_eot(P),
ok.
compare_list(Config) when is_list(Config) ->
- P = runner:start(?compare_list),
+ P = runner:start(Config, ?compare_list),
runner:recv_eot(P),
ok.
compare_string(Config) when is_list(Config) ->
- P = runner:start(?compare_string),
+ P = runner:start(Config, ?compare_string),
runner:recv_eot(P),
ok.
compare_list_string(Config) when is_list(Config) ->
- P = runner:start(?compare_list_string),
+ P = runner:start(Config, ?compare_list_string),
runner:recv_eot(P),
ok.
compare_nc_ext(Config) when is_list(Config) ->
- P = runner:start(?compare_nc_ext),
+ P = runner:start(Config, ?compare_nc_ext),
runner:recv_eot(P),
ok.
diff --git a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
index 1e986feacf..6b47c3e510 100644
--- a/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
+++ b/lib/erl_interface/test/erl_ext_SUITE_data/ext_test.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2017. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -88,6 +88,11 @@ TESTCASE(compare_list) {
// erlang:term_to_binary([0, 1000])
unsigned char term4[] = {131,108,0,0,0,2,97,0,98,0,0,3,232,106};
+ // erlang:term_to_binary([a|b])
+ unsigned char term5a[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,98};
+ // erlang:term_to_binary([a|c])
+ unsigned char term5b[] = {131,108,0,0,0,1,100,0,1,97,100,0,1,99};
+
erl_init(NULL, 0);
start_a = term1;
start_b = term2;
@@ -103,6 +108,13 @@ TESTCASE(compare_list) {
test_compare_ext("lists1", start_a, end_a, start_b, end_b, -1);
+ start_a = term5a;
+ start_b = term5b;
+ end_a = term5a + sizeof(term5a);
+ end_b = term5b + sizeof(term5b);
+
+ test_compare_ext("lists5", start_a, end_a, start_b, end_b, -1);
+
report(1);
}
diff --git a/lib/erl_interface/test/erl_format_SUITE.erl b/lib/erl_interface/test/erl_format_SUITE.erl
index c1a7d8377e..69dfdcc4c8 100644
--- a/lib/erl_interface/test/erl_format_SUITE.erl
+++ b/lib/erl_interface/test/erl_format_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_format_SUITE_data/format_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, tuples/1, lists/1]).
-import(runner, [get_term/1]).
@@ -38,10 +39,13 @@ suite() ->
all() ->
[atoms, tuples, lists].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
+
%% Tests formatting various atoms.
atoms(Config) when is_list(Config) ->
- P = runner:start(?atoms),
+ P = runner:start(Config, ?atoms),
{term, ''} = get_term(P),
{term, 'a'} = get_term(P),
@@ -79,7 +83,7 @@ atoms(Config) when is_list(Config) ->
%% Tests formatting various tuples
tuples(Config) when is_list(Config) ->
- P = runner:start(?tuples),
+ P = runner:start(Config, ?tuples),
{term, {}} = get_term(P),
{term, {a}} = get_term(P),
@@ -100,7 +104,7 @@ tuples(Config) when is_list(Config) ->
%% Tests formatting various lists
lists(Config) when is_list(Config) ->
- P = runner:start(?lists),
+ P = runner:start(Config, ?lists),
{term, []} = get_term(P),
{term, [a]} = get_term(P),
diff --git a/lib/erl_interface/test/erl_global_SUITE.erl b/lib/erl_interface/test/erl_global_SUITE.erl
index ecc6753c7f..6d3a75c8d7 100644
--- a/lib/erl_interface/test/erl_global_SUITE.erl
+++ b/lib/erl_interface/test/erl_global_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_global_SUITE_data/erl_global_test_cases.hrl").
-export([all/0,suite/0,
+ init_per_testcase/2,
erl_global_registration/1,
erl_global_whereis/1, erl_global_names/1]).
@@ -39,9 +40,11 @@ suite() ->
[{ct_hooks,[ts_install_cth]},
{timetrap, {seconds, 30}}].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
erl_global_registration(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
ok = erl_global_register(P, Fd, ?GLOBAL_NAME),
@@ -53,7 +56,7 @@ erl_global_registration(Config) when is_list(Config) ->
ok.
erl_global_whereis(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
@@ -66,7 +69,7 @@ erl_global_whereis(Config) when is_list(Config) ->
ok.
erl_global_names(Config) when is_list(Config) ->
- P = runner:start(?interpret),
+ P = runner:start(Config, ?interpret),
{ok, Fd} = erl_connect(P, node(), 42, erlang:get_cookie(), 0),
Self = self(),
diff --git a/lib/erl_interface/test/erl_match_SUITE.erl b/lib/erl_interface/test/erl_match_SUITE.erl
index 5566714092..bb62d6288d 100644
--- a/lib/erl_interface/test/erl_match_SUITE.erl
+++ b/lib/erl_interface/test/erl_match_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@
-include("erl_match_SUITE_data/match_test_cases.hrl").
-export([all/0, suite/0,
+ init_per_testcase/2,
atoms/1, lists/1, tuples/1, references/1, pids/1, ports/1,
bind/1, integers/1, floats/1, binaries/1, strings/1]).
@@ -40,6 +41,8 @@ all() ->
[atoms, lists, tuples, references, pids, ports, bind,
integers, floats, binaries, strings].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
atoms(Config) when is_list(Config) ->
P = start_matcher(Config),
@@ -239,7 +242,7 @@ bind(Config) when is_list(Config) ->
ok.
start_bind(Config) ->
- runner:start(?erl_match_bind).
+ runner:start(Config, ?erl_match_bind).
bind_ok(Port, Bind, Term) ->
true = erl_bind(Port, Bind, Term).
@@ -258,7 +261,7 @@ erl_bind(Port, Pattern, Term) ->
start_matcher(Config) ->
- runner:start(?erl_match_server).
+ runner:start(Config, ?erl_match_server).
eq(Port, Pattern, Term) ->
true = erl_match(Port, Pattern, Term).
diff --git a/lib/erl_interface/test/port_call_SUITE.erl b/lib/erl_interface/test/port_call_SUITE.erl
index fb10bd895f..5c4f5f3cee 100644
--- a/lib/erl_interface/test/port_call_SUITE.erl
+++ b/lib/erl_interface/test/port_call_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,7 +32,9 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--export([all/0, suite/0, basic/1]).
+-export([all/0, suite/0,
+ init_per_testcase/2,
+ basic/1]).
% Private exports
-include_lib("common_test/include/ct.hrl").
@@ -44,6 +46,8 @@ suite() ->
all() ->
[basic].
+init_per_testcase(Case, Config) ->
+ runner:init_per_testcase(?MODULE, Case, Config).
basic(Config) when is_list(Config) ->
case os:type() of
diff --git a/lib/erl_interface/test/runner.erl b/lib/erl_interface/test/runner.erl
index 947e56c4e0..484890006e 100644
--- a/lib/erl_interface/test/runner.erl
+++ b/lib/erl_interface/test/runner.erl
@@ -21,8 +21,9 @@
%%
-module(runner).
--export([test/1, test/2,
- start/1, send_term/2, finish/1, send_eot/1, recv_eot/1,
+-export([test/2, test/3,
+ init_per_testcase/3,
+ start/2, send_term/2, finish/1, send_eot/1, recv_eot/1,
get_term/1, get_term/2]).
-define(default_timeout, 5000).
@@ -32,11 +33,11 @@
%% This function is useful for test cases written in C which requires
%% no further input, and only returns a result by calling report().
-test(Tc) ->
- test(Tc, ?default_timeout).
+test(Config, Tc) ->
+ test(Config, Tc, ?default_timeout).
-test(Tc, Timeout) ->
- Port = start(Tc),
+test(Config, Tc, Timeout) ->
+ Port = start(Config, Tc),
case get_term(Port, Timeout) of
eot ->
@@ -54,12 +55,51 @@ test(Tc, Timeout) ->
%%
%% Returns: {ok, Port}
-start({Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
- Port = open_port({spawn, Prog}, [{packet, 4}, exit_status]),
+start(Config, {Prog, Tc}) when is_list(Prog), is_integer(Tc) ->
+ Port = open_port({spawn, prog_cmd(Config, Prog)},
+ [{packet, 4}, exit_status]),
Command = [Tc div 256, Tc rem 256],
Port ! {self(), {command, Command}},
Port.
+prog_cmd(Config, Prog) ->
+ case proplists:get_value(valgrind_cmd_fun, Config) of
+ undefined ->
+ Prog;
+ Fun when is_function(Fun) ->
+ Fun(Prog)
+ end.
+
+init_per_testcase(Suite, Case, Config) ->
+ case os:getenv("VALGRIND_LOG_DIR") of
+ false ->
+ Config;
+ LogDir ->
+ Valgrind = case os:find_executable("valgrind") of
+ false ->
+ ct:fail("VALGRIND_LOG_DIR set, "
+ "but no valgrind executable found");
+ VG -> VG
+ end,
+
+ LogFileOpt = case os:getenv("VALGRIND_LOG_XML") of
+ false ->
+ " --log-file=";
+ "yes" ->
+ " --xml=yes --xml-file="
+ end,
+ Fun = fun(Prog) ->
+ LogFile = io_lib:format("erl_interface-~w.~w-~s.log.%p",
+ [Suite, Case, filename:basename(Prog)]),
+ Valgrind
+ ++ LogFileOpt ++ filename:join(LogDir,LogFile)
+ ++ " " ++ os:getenv("VALGRIND_MISC_FLAGS","")
+ ++ " " ++ Prog
+ end,
+ [{valgrind_cmd_fun, Fun} | Config]
+ end.
+
+
%% Finishes a test case by send an 'eot' message to the C program
%% and waiting for an 'eot'.
%%
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index 586b23c5b3..06ef907d6c 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1,2 +1,2 @@
-EI_VSN = 3.10.3
+EI_VSN = 3.10.4
ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/et/doc/src/et_collector.xml b/lib/et/doc/src/et_collector.xml
index 6a85b81ec2..fd90ecfc41 100644
--- a/lib/et/doc/src/et_collector.xml
+++ b/lib/et/doc/src/et_collector.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,7 +46,8 @@
<v>option() = {parent_pid, pid()} | {event_order, event_order()} | {dict_insert, {filter, collector}, collector_fun()} | {dict_insert, {filter, event_filter_name()}, event_filter_fun()} | {dict_insert, {subscriber, pid()}, dict_val()} | {dict_insert, dict_key(), dict_val()} | {dict_delete, dict_key()} | {trace_client, trace_client()} | {trace_global, boolean()} | {trace_pattern, trace_pattern()} | {trace_port, integer()} | {trace_max_queue, integer()}</v>
<v>event_order() = trace_ts | event_ts</v>
<v>trace_pattern() = {report_module(), extended_dbg_match_spec()} | undefined</v>
- <v>report_module() = atom() | undefined &lt;v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>report_module() = atom() | undefined</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>trace_client() = {event_file, file_name()} | {dbg_trace_type(), dbg_trace_parameters()}</v>
<v>file_name() = string()</v>
@@ -221,7 +222,7 @@
<v>CollectorPid = pid()</v>
<v>RawPattern = {report_module(), extended_dbg_match_spec()}</v>
<v>report_module() = atom() | undefined</v>
- <v>extended_dbg_match_spec()() = detail_level() | dbg_match_spec()</v>
+ <v>extended_dbg_match_spec() = detail_level() | dbg_match_spec()</v>
<v>RawPattern = detail_level()</v>
<v>detail_level() = min | max | integer(X) when X =&lt; 0, X >= 100</v>
<v>TracePattern = {report_module(), dbg_match_spec_match_spec()}</v>
@@ -348,7 +349,8 @@
<v>done() = 0</v>
<v>forward() = infinity | integer(X) where X > 0</v>
<v>backward() = '-infinity' | integer(X) where X &lt; 0</v>
- <v>Fun = fun(Event, Acc) -> NewAcc &lt;v>Acc = NewAcc = term()</v>
+ <v>Fun = fun(Event, Acc) -> NewAcc</v>
+ <v>Acc = NewAcc = term()</v>
</type>
<desc>
<p>Iterate over the currently stored events.</p>
diff --git a/lib/et/doc/src/et_selector.xml b/lib/et/doc/src/et_selector.xml
index 441a4dd278..30ca74c872 100644
--- a/lib/et/doc/src/et_selector.xml
+++ b/lib/et/doc/src/et_selector.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2002</year><year>2016</year>
+ <year>2002</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -90,7 +90,9 @@
<fsummary>Transforms trace data and makes an event record out of it</fsummary>
<type>
- <v>Mod = module_name() | undefined &lt;v>module_name() = atom() &lt;v>ValidTraceData = erlang_trace_data() | record(event)</v>
+ <v>Mod = module_name() | undefined</v>
+ <v>module_name() = atom()</v>
+ <v>ValidTraceData = erlang_trace_data() | record(event)</v>
<v>erlang_trace_data() = {trace, Pid, Label, Info} | {trace, Pid, Label, Info, Extra} | {trace_ts, Pid, Label, Info, ReportedTS} | {trace_ts, Pid, Label, Info, Extra, ReportedTS} | {seq_trace, Label, Info} | {seq_trace, Label, Info, ReportedTS} | {drop, NumberOfDroppedItems}</v>
</type>
diff --git a/lib/et/doc/src/notes.xml b/lib/et/doc/src/notes.xml
index e7cec937b3..110d3b2110 100644
--- a/lib/et/doc/src/notes.xml
+++ b/lib/et/doc/src/notes.xml
@@ -37,6 +37,21 @@
one section in this document. The title of each section is the
version number of <c>Event Tracer (ET)</c>.</p>
+<section><title>ET 1.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>ET 1.6.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/et/src/et_collector.erl b/lib/et/src/et_collector.erl
index ffe244324c..3609238509 100644
--- a/lib/et/src/et_collector.erl
+++ b/lib/et/src/et_collector.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -509,7 +509,7 @@ get_global_pid() ->
%% CollectorPid = pid()
%% RawPattern = {report_module(), extended_dbg_match_spec()}
%% report_module() = atom() | undefined
-%% extended_dbg_match_spec()() = detail_level() | dbg_match_spec()
+%% extended_dbg_match_spec() = detail_level() | dbg_match_spec()
%% RawPattern = detail_level()
%% detail_level() = min | max | integer(X) when X =< 0, X >= 100
%% TracePattern = {report_module(), dbg_match_spec_match_spec()}
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index 08ded8b6f1..9563a38000 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -1 +1 @@
-ET_VSN = 1.6.2
+ET_VSN = 1.6.3
diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml
index 0d2d61d553..67a9ae5fcb 100644
--- a/lib/eunit/doc/src/notes.xml
+++ b/lib/eunit/doc/src/notes.xml
@@ -33,6 +33,21 @@
</header>
<p>This document describes the changes made to the EUnit application.</p>
+<section><title>Eunit 2.3.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Eunit 2.3.6</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 054e21f6ad..46ef5eea3c 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.3.6
+EUNIT_VSN = 2.3.7
diff --git a/lib/ftp/doc/src/ftp.xml b/lib/ftp/doc/src/ftp.xml
index 23a9e3fec7..34e3ff84b0 100644
--- a/lib/ftp/doc/src/ftp.xml
+++ b/lib/ftp/doc/src/ftp.xml
@@ -314,7 +314,7 @@
<fsummary>Transfers a binary into a remote file.</fsummary>
<type>
<v>Pid = pid()</v>
- <v>Bin = binary()()</v>
+ <v>Bin = binary()</v>
<v>RemoteFile = string()</v>
<v>Reason = restriction_reason()| shortage_reason() | common_reason()</v>
</type>
@@ -736,7 +736,7 @@
<fsummary>Transfers a binary into a remote file.</fsummary>
<type>
<v>Pid = pid()</v>
- <v>Bin = binary()()</v>
+ <v>Bin = binary()</v>
<v>RemoteFile = string()</v>
<v>Reason = restriction_reason() | common_reason() | shortage_reason()</v>
</type>
diff --git a/lib/ftp/doc/src/notes.xml b/lib/ftp/doc/src/notes.xml
index 50f38941e5..01c1f88cf1 100644
--- a/lib/ftp/doc/src/notes.xml
+++ b/lib/ftp/doc/src/notes.xml
@@ -33,7 +33,22 @@
<file>notes.xml</file>
</header>
- <section><title>FTP 1.0</title>
+ <section><title>Ftp 1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>FTP 1.0</title>
<section><title>First released version</title>
<list>
diff --git a/lib/ftp/src/ftp.app.src b/lib/ftp/src/ftp.app.src
index 237174358f..66ccace390 100644
--- a/lib/ftp/src/ftp.app.src
+++ b/lib/ftp/src/ftp.app.src
@@ -1,6 +1,6 @@
{application, ftp,
[{description, "FTP client"},
- {vsn, "1.0"},
+ {vsn, "%VSN%"},
{registered, []},
{mod, { ftp_app, []}},
{applications,
diff --git a/lib/ftp/vsn.mk b/lib/ftp/vsn.mk
index 3099144a6e..d5d6c45b28 100644
--- a/lib/ftp/vsn.mk
+++ b/lib/ftp/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = ftp
-FTP_VSN = 1.0
+FTP_VSN = 1.0.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(FTP_VSN)$(PRE_VSN)"
diff --git a/lib/hipe/doc/src/Makefile b/lib/hipe/doc/src/Makefile
index bd6a7b2f74..104c15f2bb 100644
--- a/lib/hipe/doc/src/Makefile
+++ b/lib/hipe/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2006-2017. All Rights Reserved.
+# Copyright Ericsson AB 2006-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/hipe/doc/src/hipe_app.xml b/lib/hipe/doc/src/hipe_app.xml
index 63bc6ea2d7..480290cd9e 100644
--- a/lib/hipe/doc/src/hipe_app.xml
+++ b/lib/hipe/doc/src/hipe_app.xml
@@ -62,6 +62,13 @@
and the runtime system that have limited or no support for HiPE compiled modules.
</p>
<taglist>
+ <tag>Binary matching</tag>
+ <item><p>The HiPE compiler will crash on modules containing binary
+ matching unless they have been compiled with the <c>+no_bsm3</c> flag.
+ Note that this will disable all related optimizations done by the BEAM
+ compiler.</p>
+ </item>
+
<tag>Stack traces</tag>
<item><p>Stack traces returned from <seealso marker="erts:erlang#get_stacktrace/0">
<c>erlang:get_stacktrace/0</c></seealso> or as part of <c>'EXIT'</c> terms
@@ -78,12 +85,12 @@
</item>
<tag>NIFs</tag>
- <item><p>Modules compiled with HiPE can not call <seealso marker="erts:erlang#load_nif-2">
+ <item><p>Modules compiled with HiPE cannot call <seealso marker="erts:erlang#load_nif-2">
<c>erlang:load_nif/2</c></seealso> to load NIFs.</p>
</item>
<tag>-on_load</tag>
- <item><p>Modules compiled with HiPE can not use
+ <item><p>Modules compiled with HiPE cannot use
<seealso marker="doc/reference_manual:code_loading#on_load"><c>-on_load()</c></seealso>
directives.</p>
</item>
diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml
index f47868296a..d9f58382bc 100644
--- a/lib/hipe/doc/src/notes.xml
+++ b/lib/hipe/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to HiPE.</p>
+<section><title>Hipe 3.18.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Hipe 3.18</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index f429d40272..ffe81ef9b8 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -647,6 +647,13 @@ trans_fun([{put_tuple,_Size,Reg}|Instructions], Env) ->
Primop = hipe_icode:mk_primop(Dest,mktuple,Src),
Moves ++ [Primop | trans_fun(Instructions2,Env2)];
%%--- put --- SHOULD NOT REALLY EXIST HERE; put INSTRUCTIONS ARE HANDLED ABOVE.
+%%--- put_tuple2 ---
+trans_fun([{put_tuple2,Reg,{list,Elements}}|Instructions], Env) ->
+ Dest = [mk_var(Reg)],
+ {Moves,Vars,Env2} = trans_elements(Elements, [], [], Env),
+ Src = lists:reverse(Vars),
+ Primop = hipe_icode:mk_primop(Dest, mktuple, Src),
+ Moves ++ [Primop | trans_fun(Instructions, Env2)];
%%--- badmatch ---
trans_fun([{badmatch,Arg}|Instructions], Env) ->
BadVar = trans_arg(Arg),
@@ -1139,9 +1146,10 @@ trans_fun([{test,has_map_fields,{f,Lbl},Map,{list,Keys}}|Instructions], Env) ->
lists:flatten([[K, {r, 0}] || K <- Keys])),
[MapMove, TestInstructions | trans_fun(Instructions, Env2)];
trans_fun([{get_map_elements,{f,Lbl},Map,{list,KVPs}}|Instructions], Env) ->
+ KVPs1 = overwrite_map_last(Map, KVPs),
{MapMove, MapVar, Env1} = mk_move_and_var(Map, Env),
{TestInstructions, GetInstructions, Env2} =
- trans_map_query(MapVar, map_label(Lbl), Env1, KVPs),
+ trans_map_query(MapVar, map_label(Lbl), Env1, KVPs1),
[MapMove, TestInstructions, GetInstructions | trans_fun(Instructions, Env2)];
%%--- put_map_assoc ---
trans_fun([{put_map_assoc,{f,Lbl},Map,Dst,_N,{list,Pairs}}|Instructions], Env) ->
@@ -1563,6 +1571,21 @@ trans_type_test2(function2, Lbl, Arg, Arity, Env) ->
hipe_icode:label_name(True), map_label(Lbl)),
{[Move1,Move2,I,True],Env2}.
+
+%%
+%% Makes sure that if a get_map_elements instruction will overwrite
+%% the map source, it will be done last.
+%%
+overwrite_map_last(Map, KVPs) ->
+ overwrite_map_last2(Map, KVPs, []).
+
+overwrite_map_last2(Map, [Key,Map|KVPs], _Last) ->
+ overwrite_map_last2(Map, KVPs, [Key,Map]);
+overwrite_map_last2(Map, [Key,Val|KVPs], Last) ->
+ [Key,Val|overwrite_map_last2(Map, KVPs, Last)];
+overwrite_map_last2(_Map, [], Last) ->
+ Last.
+
%%
%% Handles the get_map_elements instruction and the has_map_fields
%% test instruction.
@@ -1683,6 +1706,19 @@ trans_puts([{put,X}|Code], Vars, Moves, Env) ->
trans_puts(Code, Vars, Moves, Env) -> %% No more put operations
{Moves, Code, Vars, Env}.
+trans_elements([X|Code], Vars, Moves, Env) ->
+ case type(X) of
+ var ->
+ Var = mk_var(X),
+ trans_elements(Code, [Var|Vars], Moves, Env);
+ #beam_const{value=C} ->
+ Var = mk_var(new),
+ Move = hipe_icode:mk_move(Var, hipe_icode:mk_const(C)),
+ trans_elements(Code, [Var|Vars], [Move|Moves], Env)
+ end;
+trans_elements([], Vars, Moves, Env) ->
+ {Moves, Vars, Env}.
+
%%-----------------------------------------------------------------------
%% The code for this instruction is a bit large because we are treating
%% different cases differently. We want to use the icode `type'
diff --git a/lib/hipe/icode/hipe_icode_range.erl b/lib/hipe/icode/hipe_icode_range.erl
index 34b18acccd..098a7a8d8c 100644
--- a/lib/hipe/icode/hipe_icode_range.erl
+++ b/lib/hipe/icode/hipe_icode_range.erl
@@ -1633,7 +1633,7 @@ inf_bsl(_, pos_inf) -> neg_inf;
inf_bsl(Number, neg_inf) when is_integer(Number), Number >= 0 -> 0;
inf_bsl(_Number, neg_inf) -> -1;
inf_bsl(Number1, Number2) when is_integer(Number1), is_integer(Number2) ->
- %% We can not shift left with a number which is not a fixnum. We
+ %% We cannot shift left with a number which is not a fixnum. We
%% don't have enough memory.
Bits = ?BITS,
if Number2 > (Bits bsl 1) -> inf_bsl(Number1, pos_inf);
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
index 54c435c127..44f0566379 100644
--- a/lib/hipe/llvm/hipe_llvm_main.erl
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -526,8 +526,8 @@ unique_folder(FunName, Arity, Options) ->
case proplists:get_bool(llvm_save_temps, Options) of
true -> %% Store folder in current directory
DirName;
- false -> %% Temporarily store folder in tempfs (/dev/shm/)
- "/dev/shm/" ++ DirName
+ false -> %% Temporarily store folder in tempfs or tmp dir
+ tmpfs_folder() ++ DirName
end,
%% Make sure it does not exist
case dir_exists(Dir) of
@@ -537,6 +537,14 @@ unique_folder(FunName, Arity, Options) ->
Dir
end.
+tmpfs_folder() ->
+ case os:type() of
+ {unix, linux} ->
+ "/dev/shm/";
+ {unix, _} -> %% Fallback to tmp dir. e.g. FreeBSD
+ "/tmp/"
+ end.
+
%% @doc Function that checks that a given Filename is an existing Directory
%% Name (from http://rosettacode.org/wiki/Ensure_that_a_file_exists#Erlang)
dir_exists(Filename) ->
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index ac2e6c1e3b..2348e9b1f6 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -196,7 +196,7 @@
file/1,
file/2,
get_llvm_version/0,
- llvm_support_available/0,
+ erllvm_is_supported/0,
load/1,
help/0,
help_hiper/0,
@@ -218,12 +218,11 @@
%% Basic type declaration for exported functions of the 'hipe' module
%%-------------------------------------------------------------------
--type mod() :: atom().
--type f_unit() :: mod() | binary().
+-type mod() :: module().
+-type file_or_bin() :: file:filename() | binary().
-type ret_rtl() :: [_].
-type c_ret() :: {'ok', mod()} | {'error', term()} |
{'ok', mod(), ret_rtl()}. %% The last for debugging only
--type compile_file() :: atom() | string() | binary().
-type compile_ret() :: {hipe_architecture(), binary()} | list().
%%-------------------------------------------------------------------
@@ -233,26 +232,26 @@
%%-------------------------------------------------------------------
-%% @spec load(Mod) -> {module, Mod} | {error, Reason}
-%% Mod = mod()
+%% @spec load(Module) -> {module, Module} | {error, Reason}
+%% Module = mod()
%% Reason = term()
%%
%% @doc Like load/2, but tries to locate a BEAM file automatically.
%%
%% @see load/2
--spec load(Mod) -> {'module', Mod} | {'error', term()} when Mod :: mod().
+-spec load(Module) -> {'module', Module} | {'error', Reason :: term()}
+ when Module :: mod().
-load(Mod) ->
- load(Mod, beam_file(Mod)).
+load(Module) ->
+ load(Module, beam_file(Module)).
-%% @spec load(Mod, BeamFileName) -> {module, Mod} | {error, Reason}
-%% Mod = mod()
+%% @spec load(Module, BeamFileName) -> {module, Module} | {error, Reason}
+%% Module = mod()
+%% BeamFileName = file:filename()
%% Reason = term()
-%% BeamFileName = string()
-%% filename() = term()
%%
-%% @type mod() = atom(). A module name.
+%% @type mod() = module(). A module name.
%%
%% @doc User interface for loading code into memory. The code can be
%% given as a native code binary or as the file name of a BEAM file
@@ -262,8 +261,8 @@ load(Mod) ->
%%
%% @see load/1
--spec load(Mod, string()) -> {'module', Mod} | {'error', term()}
- when Mod :: mod().
+-spec load(Module, file:filename()) -> {'module', Module} | {'error', term()}
+ when Module :: mod().
load(Mod, BeamFileName) when is_list(BeamFileName) ->
Architecture = erlang:system_info(hipe_architecture),
@@ -273,26 +272,22 @@ load(Mod, BeamFileName) when is_list(BeamFileName) ->
Error -> {error, Error}
end.
-%% @spec c(Name) -> {ok, Name} | {error, Reason}
-%% Name = mod()
+%% @spec c(Mod) -> {ok, Mod} | {error, Reason}
+%% Mod = mod()
%% Reason = term()
%%
-%% @equiv c(Name, [])
+%% @equiv c(Mod, [])
-spec c(mod()) -> c_ret().
-c(Name) ->
- c(Name, []).
+c(Mod) ->
+ c(Mod, []).
-%% @spec c(Name, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod()
+%% @spec c(Module, options()) -> {ok, Module} | {error, Reason}
+%% Module = mod()
%% options() = [option()]
%% option() = term()
%% Reason = term()
-%%
-%% @type fun() = atom(). A function identifier.
-%%
-%% @type arity() = integer(). A function arity; always nonnegative.
%%
%% @doc User-friendly native code compiler interface. Reads BEAM code
%% from the corresponding "Module<code>.beam</code>" file in the
@@ -307,12 +302,12 @@ c(Name) ->
-spec c(mod(), comp_options()) -> c_ret().
-c(Name, Options) ->
- c(Name, beam_file(Name), Options).
+c(Module, Options) ->
+ c(Module, beam_file(Module), Options).
-%% @spec c(Name, File, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod()
-%% File = filename() | binary()
+%% @spec c(Module, File, options()) -> {ok, Module} | {error, Reason}
+%% Module = mod()
+%% File = file:filename() | binary()
%% Reason = term()
%%
%% @doc Like <code>c/2</code>, but reads BEAM code from the specified
@@ -321,32 +316,32 @@ c(Name, Options) ->
%% @see c/2
%% @see f/2
-c(Name, File, Opts) ->
+c(Module, File, Opts) ->
Opts1 = user_compile_opts(Opts),
- case compile(Name, File, Opts1) of
+ case compile(Module, File, Opts1) of
{ok, Res} ->
case proplists:get_bool(to_rtl, Opts1) of
- true -> {ok, Name, Res};
- false -> {ok, Name}
+ true -> {ok, Module, Res};
+ false -> {ok, Module}
end;
Other ->
Other
end.
%% @spec f(File) -> {ok, Name} | {error, Reason}
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Name = mod()
%% Reason = term()
%%
%% @equiv f(File, [])
--spec f(f_unit()) -> {'ok', mod()} | {'error', term()}.
+-spec f(file_or_bin()) -> {'ok', mod()} | {'error', term()}.
f(File) ->
f(File, []).
%% @spec f(File, options()) -> {ok, Name} | {error, Reason}
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Name = mod()
%% Reason = term()
%%
@@ -355,7 +350,7 @@ f(File) ->
%%
%% @see c/3
--spec f(f_unit(), comp_options()) -> {'ok', mod()} | {'error', term()}.
+-spec f(file_or_bin(), comp_options()) -> {'ok', mod()} | {'error', term()}.
f(File, Opts) ->
case file(File, user_compile_opts(Opts)) of
@@ -371,20 +366,20 @@ user_compile_opts(Opts) ->
Opts ++ ?USER_DEFAULTS.
-%% @spec compile(Name) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod()
+%% @spec compile(Module) -> {ok, {Target,Binary}} | {error, Reason}
+%% Module = mod()
%% Binary = binary()
%% Reason = term()
%%
-%% @equiv compile(Name, [])
+%% @equiv compile(Module, [])
-spec compile(mod()) -> {'ok', compile_ret()} | {'error', term()}.
-compile(Name) ->
- compile(Name, []).
+compile(Module) ->
+ compile(Module, []).
-%% @spec compile(Name, options()) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod()
+%% @spec compile(Module, options()) -> {ok, {Target,Binary}} | {error, Reason}
+%% Module = mod()
%% Binary = binary()
%% Reason = term()
%%
@@ -403,26 +398,26 @@ compile(Name) ->
%% @see file/2
%% @see load/2
--spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', _}.
+-spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', term()}.
-compile(Name, Options) ->
- compile(Name, beam_file(Name), Options).
+compile(Module, Options) ->
+ compile(Module, beam_file(Module), Options).
--spec beam_file(mod()) -> string().
+-spec beam_file(mod()) -> file:filename().
beam_file(Module) when is_atom(Module) ->
case code:which(Module) of
non_existing ->
- ?error_msg("Cannot find ~w.beam file.",[Module]),
+ ?error_msg("Cannot find ~w.beam file.", [Module]),
?EXIT({cant_find_beam_file,Module});
- File -> % string()
+ File when is_list(File) ->
File
end.
%% @spec compile(Name, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
%% Name = mod()
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Binary = binary()
%% Reason = term()
%%
@@ -431,7 +426,7 @@ beam_file(Module) when is_atom(Module) ->
%%
%% @see compile/2
--spec compile(mod(), compile_file(), comp_options()) ->
+-spec compile(mod(), file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile(Name, File, Opts0) when is_atom(Name) ->
@@ -475,18 +470,18 @@ compile(Name, File, Opts0) when is_atom(Name) ->
run_compiler(Name, DisasmFun, IcodeFun, Opts)
end.
--spec compile_core(mod(), cerl:c_module(), compile_file(), comp_options()) ->
+-spec compile_core(mod(), cerl:c_module(), file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile_core(Name, Core0, File, Opts) ->
Core = cerl:from_records(Core0),
compile(Name, Core, File, Opts).
-%% @spec compile(Name, Core, File, options()) ->
+%% @spec compile(Module, Core, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
-%% Name = mod()
+%% Module = mod()
%% Core = coreErlang() | []
-%% File = filename() | binary()
+%% File = file:filename() | binary()
%% Binary = binary()
%% Reason = term()
%%
@@ -499,7 +494,7 @@ compile_core(Name, Core0, File, Opts) ->
%%
%% @see compile/3
--spec compile(mod(), cerl:c_module() | [], compile_file(), comp_options()) ->
+-spec compile(mod(), cerl:c_module() | [], file_or_bin(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
compile(Name, [], File, Opts) ->
@@ -511,37 +506,35 @@ compile(Name, Core, File, Opts) when is_atom(Name) ->
end,
run_compiler(Name, DisasmFun, IcodeFun, Opts).
-%% @spec file(File) -> {ok, Name, {Target, Binary}} | {error, Reason}
-%% File = filename() | binary()
-%% Name = mod() | mfa()
+%% @spec file(File) -> {ok, Mod, {Target, Binary}} | {error, Reason}
+%% File = file:filename()
+%% Mod = mod()
%% Binary = binary()
%% Reason = term()
%%
%% @equiv file(File, [])
--spec file(Mod) -> {'ok', Mod, compile_ret()} | {'error', term()}
- when Mod :: mod().
+-spec file(file:filename()) -> {'ok', mod(), compile_ret()} | {'error', term()}.
file(File) ->
file(File, []).
-%% @spec file(File, options()) -> {ok, Name, {Target,Binary}} | {error, Reason}
-%% File = filename()
-%% Name = mod() | mfa()
+%% @spec file(File, options()) -> {ok, Mod, {Target, Binary}} | {error, Reason}
+%% File = file:filename()
+%% Mod = mod()
%% Binary = binary()
%% Reason = term()
%%
%% @doc Like <code>compile/2</code>, but takes the module name from the
-%% specified <code>File</code>. Returns both the name and the final
+%% specified <code>File</code>. Returns both the module name and the final
%% binary if successful.
%%
%% @see file/1
%% @see compile/2
--spec file(Mod, comp_options()) -> {'ok', Mod, compile_ret()}
- | {'error', term()}
- when Mod :: mod().
-file(File, Options) when is_atom(File) ->
+-spec file(file:filename(), comp_options()) -> {'ok', mod(), compile_ret()}
+ | {'error', Reason :: term()}.
+file(File, Options) when is_list(File) ->
case beam_lib:info(File) of
L when is_list(L) ->
{module, Mod} = lists:keyfind(module, 1, L),
@@ -653,7 +646,7 @@ run_compiler_1(Name, DisasmFun, IcodeFun, Options) ->
get(hipe_target_arch)),
Opts =
case proplists:get_bool(to_llvm, Opts0) andalso
- not llvm_support_available() of
+ not llvm_version_is_OK() of
true ->
?error_msg("No LLVM version 3.9 or greater "
"found in $PATH; aborting "
@@ -1607,9 +1600,15 @@ check_options(Opts) ->
ok
end.
--spec llvm_support_available() -> boolean().
+-spec erllvm_is_supported() -> boolean().
+erllvm_is_supported() ->
+ %% XXX: The test should really check the _target_ architecture,
+ %% (hipe_target_arch), but there's no guarantee it's set.
+ Arch = erlang:system_info(hipe_architecture),
+ lists:member(Arch, [amd64, x86]) andalso llvm_version_is_OK().
-llvm_support_available() ->
+-spec llvm_version_is_OK() -> boolean().
+llvm_version_is_OK() ->
get_llvm_version() >= {3,9}.
-type llvm_version() :: {Major :: integer(), Minor :: integer()}.
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 6da8a76d34..1ab41f4deb 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -215,7 +215,7 @@ gen_enter(I, VarMap, ConstTab) ->
{Code1, ConstTab2} =
case hipe_icode:enter_type(I) of
primop ->
- IsGuard = false, % enter can not happen in a guard
+ IsGuard = false, % enter cannot happen in a guard
hipe_rtl_primops:gen_enter_primop({Fun, Args}, IsGuard, ConstTab1);
Type ->
Call = gen_enter_1(Fun, Args, Type),
diff --git a/lib/hipe/rtl/hipe_rtl_arith.inc b/lib/hipe/rtl/hipe_rtl_arith.inc
index c05b7aa160..575f10b542 100644
--- a/lib/hipe/rtl/hipe_rtl_arith.inc
+++ b/lib/hipe/rtl/hipe_rtl_arith.inc
@@ -118,8 +118,8 @@ eval_alu(Op, Arg1, Arg2) ->
%% Björn & Bjarni:
%% We need to be able to do evaluations based only on the bits, since
-%% there are cases where we can evaluate a subset of the bits, but can
-%% not do a full eval-alub call (eg. a + 0 gives no carry)
+%% there are cases where we can evaluate a subset of the bits, but
+%% cannot do a full eval-alub call (eg. a + 0 gives no carry)
%%
-spec eval_cond_bits(hipe_rtl:alub_cond(), boolean(),
boolean(), boolean(), boolean()) -> boolean().
diff --git a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
index cad43e2df5..72373e536d 100644
--- a/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
+++ b/lib/hipe/rtl/hipe_rtl_ssa_const_prop.erl
@@ -31,11 +31,11 @@
%%
%% Some things to note:
%%
-%% 1. All precoloured registers are assumed to contain bottom. We can not
+%% 1. All precoloured registers are assumed to contain bottom. We cannot
%% do anything with them since they are not in SSA-form. This might be
%% possible to resolve in some way, but we decided to not go there.
%%
-%% 2. const_labels are assumed to be bottom, we can not find the address
+%% 2. const_labels are assumed to be bottom, we cannot find the address
%% in any nice way (that I know of, maybe someone can help ?). I
%% suppose they don't get a value until linking (or some step that
%% resembles it). They are only affecting bignums and floats (at least
@@ -579,7 +579,7 @@ visit_multimove(Inst, Env) ->
%% Procedure : visit_call/2
%% Purpose : execute a call-instruction. All calls return bottom. We make
%% this assumption since the icode-leel have taken care of BIF's
-%% and we belive that we are left with the things that can not be
+%% and we belive that we are left with the things that cannot be
%% done att compile time.
%% Arguments : Inst - The instruction
%% Env - The environment
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
index efeb0887ab..3650cda663 100644
--- a/lib/hipe/test/Makefile
+++ b/lib/hipe/test/Makefile
@@ -13,7 +13,6 @@ MODULES= \
# .erl files for these modules are automatically generated
GEN_MODULES= \
basic_SUITE \
- bs_SUITE \
maps_SUITE \
sanity_SUITE
diff --git a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl b/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
deleted file mode 100644
index 4c08064670..0000000000
--- a/lib/hipe/test/basic_SUITE_data/basic_inline_function.erl
+++ /dev/null
@@ -1,73 +0,0 @@
-%%% -*- erlang-indent-level: 2 -*-
-%%%-------------------------------------------------------------------
-%%% Author: Kostis Sagonas
-%%%
-%%% Contains tests that depend on the compiler inliner being turned on.
-%%%-------------------------------------------------------------------
--module(basic_inline_function).
-
--export([test/0]).
-
--compile({inline, [{to_objects, 3}]}).
-
-test() ->
- ok = test_inline_match(),
- ok.
-
-%%--------------------------------------------------------------------
-
-test_inline_match() ->
- bad_object = test1(a, {binary, foo, set}, c),
- bad_object = test2(a, {binary, foo, set}, c),
- bad_object = test3(a, {binary, foo, set}, c),
- ok.
-
-%% Inlined
-test1(KeysObjs, C, Ts) ->
- case catch to_objects(KeysObjs, C, Ts) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% "Inlined" by hand
-test2(KeysObjs, C, _Ts) ->
- case catch (case C of
- {binary, _, set} ->
- <<_ObjSz0:32, _T/binary>> = KeysObjs;
- _ -> ok
- end) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% Not inlined
-test3(KeysObjs, C, Ts) ->
- case catch fto_objects(KeysObjs, C, Ts) of
- {'EXIT', _} ->
- bad_object;
- ok ->
- ok
- end.
-
-%% Inlined.
-to_objects(Bin, {binary, _, set}, _Ts) ->
- <<_ObjSz0:32, _T/binary>> = Bin,
- ok;
-to_objects(<<_ObjSz0:32, _T/binary>> ,_, _) ->
- ok;
-to_objects(_Bin, _, _Ts) ->
- ok.
-
-%% Not Inlined.
-fto_objects(Bin, {binary, _, set}, _Ts) ->
- <<_ObjSz0:32, _T/binary>> = Bin,
- ok;
-fto_objects(<<_ObjSz0:32, _T/binary>> ,_,_) ->
- ok;
-fto_objects(_Bin, _, _Ts) ->
- ok.
-
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index 8813af5dfc..c506dd5e1d 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -170,7 +170,7 @@ run(TestCase, Dir, _OutDir) ->
{ok, TestCase} = hipe:c(TestCase, [o0|HiPEOpts]),
ok = TestCase:test(),
ToLLVM = try TestCase:to_llvm() catch error:undef -> true end,
- case ToLLVM andalso hipe:llvm_support_available() of
+ case ToLLVM andalso hipe:erllvm_is_supported() of
true ->
{ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
ok = TestCase:test();
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index b081cb0c26..b51f17aff0 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.18
+HIPE_VSN = 3.18.1
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index 2c70c2b050..e5adb4eb20 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -173,7 +173,7 @@
<item>
<p>For <c>ip_comm</c> configuration options, see
<seealso marker="kernel:gen_tcp#listen-2">gen_tcp:listen/2</seealso>, some options
- that are used internally by httpd can not be set.</p>
+ that are used internally by httpd cannot be set.</p>
<p>For <c>SSL</c> configuration options, see
<seealso marker="ssl:ssl#listen-2">ssl:listen/2</seealso>.</p>
<p>Default is <c>ip_comm</c>.</p>
diff --git a/lib/inets/doc/src/mod_security.xml b/lib/inets/doc/src/mod_security.xml
index ec8d6ec42c..6f3f3c048a 100644
--- a/lib/inets/doc/src/mod_security.xml
+++ b/lib/inets/doc/src/mod_security.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1998</year><year>2016</year>
+ <year>1998</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -135,7 +135,8 @@
<type>
<v>What = atom()</v>
<v>Port = integer()</v>
- <v>Address = {A,B,C,D} | string() &lt;v>Dir = string()</v>
+ <v>Address = {A,B,C,D} | string()</v>
+ <v>Dir = string()</v>
<v>Data = [Info]</v>
<v>Info = {Name, Value}</v>
</type>
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index d967f56576..e34dd78a2a 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -33,12 +33,63 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 7.0</title>
+ <section><title>Inets 7.0.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
<item>
<p>
+ Enhance error handling, that is mod_get will return 403
+ if a path is a directory and not a file.</p>
+ <p>
+ Own Id: OTP-15192</p>
+ </item>
+ <item>
+ <p>
+ Do not use chunked-encoding with 1xx, 204 and 304
+ responses when using mod_esi. Old behavior was not
+ compliant with HTTP/1.1 RFC and could cause clients to
+ hang when they received 1xx, 204 or 304 responses that
+ included an empty chunked-encoded body.</p>
+ <p>
+ Own Id: OTP-15241</p>
+ </item>
+ <item>
+ <p>
+ Add robust handling of chunked-encoded HTTP responses
+ with an empty body (1xx, 204, 304). Old behavior could
+ cause the client to hang when connecting to a faulty
+ server implementation.</p>
+ <p>
+ Own Id: OTP-15242</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 7.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Change status code for no mod found to handle request to
+ 501</p>
+ <p>
+ Own Id: OTP-15215</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 7.0</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
Fixed HTTP content injection bug in httpc (ERL-456).</p>
<p>
Own Id: OTP-14726</p>
@@ -92,6 +143,65 @@
</section>
+ <section><title>Inets 6.5.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Do not use chunked-encoding with 1xx, 204 and 304
+ responses when using mod_esi. Old behavior was not
+ compliant with HTTP/1.1 RFC and could cause clients to
+ hang when they received 1xx, 204 or 304 responses that
+ included an empty chunked-encoded body.</p>
+ <p>
+ Own Id: OTP-15241</p>
+ </item>
+ <item>
+ <p>
+ Add robust handling of chunked-encoded HTTP responses
+ with an empty body (1xx, 204, 304). Old behavior could
+ cause the client to hang when connecting to a faulty
+ server implementation.</p>
+ <p>
+ Own Id: OTP-15242</p>
+ </item>
+ </list>
+ </section>
+
+ </section>
+
+ <section><title>Inets 6.5.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Change status code for no mod found to handle request to
+ 501</p>
+ <p>
+ Own Id: OTP-15215</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Inets 6.5.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling, that is mod_get will return 403
+ if a path is a directory and not a file.</p>
+ <p>
+ Own Id: OTP-15192</p>
+ </item>
+ </list>
+ </section>
+
+</section>
<section><title>Inets 6.5.2.1</title>
@@ -1167,7 +1277,7 @@
Add option {ftp_extension, boolean} to enable use of
extended commands EPSV and EPRT, as specified in RFC
2428, for IPv4 instead of using the legacy commands. Ipv6
- can not be supported without the extended commands.</p>
+ cannot be supported without the extended commands.</p>
<p>
Own Id: OTP-12255</p>
</item>
diff --git a/lib/inets/doc/src/notes_history.xml b/lib/inets/doc/src/notes_history.xml
index c12899e614..1523827db9 100644
--- a/lib/inets/doc/src/notes_history.xml
+++ b/lib/inets/doc/src/notes_history.xml
@@ -1149,8 +1149,8 @@
<list type="bulleted">
<item>
<p>When further testing the functionality of https requests
- that goes through a proxy. We realised that alas this can
- not currently be supported as it requires features from
+ that goes through a proxy. We realised that alas this
+ cannot currently be supported as it requires features from
the ssl implementation that is not currently available.
So for now an error message will be returned when trying
to use this functionality.</p>
diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl
index cbf428ab3e..2e647a1438 100644
--- a/lib/inets/src/http_client/httpc_cookie.erl
+++ b/lib/inets/src/http_client/httpc_cookie.erl
@@ -271,7 +271,7 @@ lookup_cookies(CookieDb, Host, Path) ->
lookup_domain_cookies(_CookieDb, [], AccCookies) ->
lists:flatten(AccCookies);
-%% Top domains can not have cookies
+%% Top domains cannot have cookies
lookup_domain_cookies(_CookieDb, [_], AccCookies) ->
lists:flatten(AccCookies);
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 5e05b8170a..1bf5d25c98 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -961,13 +961,23 @@ handle_http_body(_, #state{status = {ssl_tunnel, Request},
NewState = answer_request(Request, ClientErrMsg, State),
{stop, normal, NewState};
-handle_http_body(<<>>, #state{status_line = {_,304, _}} = State) ->
+%% All 1xx (informational), 204 (no content), and 304 (not modified)
+%% responses MUST NOT include a message-body, and thus are always
+%% terminated by the first empty line after the header fields.
+%% This implies that chunked encoding MUST NOT be used for these
+%% status codes.
+handle_http_body(<<>>, #state{headers = Headers,
+ status_line = {_,StatusCode, _}} = State)
+ when Headers#http_response_h.'transfer-encoding' =/= "chunked" andalso
+ (StatusCode =:= 204 orelse %% No Content
+ StatusCode =:= 304 orelse %% Not Modified
+ 100 =< StatusCode andalso StatusCode =< 199) -> %% Informational
handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, #state{status_line = {_,204, _}} = State) ->
- handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
+handle_http_body(<<>>, #state{headers = Headers,
+ request = #request{method = head}} = State)
+ when Headers#http_response_h.'transfer-encoding' =/= "chunked" ->
handle_response(State#state{body = <<>>});
handle_http_body(Body, #state{headers = Headers,
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 0333442bf2..0dc0483fa9 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -863,7 +863,7 @@ select_session(Candidates, _, Max, pipeline) ->
select_session(Candidates, Max).
select_session([] = _Candidates, _Max) ->
- ?hcrd("select session - no candicate", []),
+ ?hcrd("select session - no candidate", []),
no_connection;
select_session(Candidates, Max) ->
NewCandidates =
diff --git a/lib/inets/src/http_client/httpc_request.erl b/lib/inets/src/http_client/httpc_request.erl
index 9b81bd7a80..0f20d93bc1 100644
--- a/lib/inets/src/http_client/httpc_request.erl
+++ b/lib/inets/src/http_client/httpc_request.erl
@@ -213,15 +213,18 @@ update_body(Headers, Body) ->
update_headers(Headers, ContentType, Body, []) ->
case Body of
[] ->
- Headers#http_request_h{'content-length' = "0"};
+ Headers1 = Headers#http_request_h{'content-length' = "0"},
+ handle_content_type(Headers1, ContentType);
<<>> ->
- Headers#http_request_h{'content-length' = "0"};
+ Headers1 = Headers#http_request_h{'content-length' = "0"},
+ handle_content_type(Headers1, ContentType);
{Fun, _Acc} when is_function(Fun, 1) ->
%% A client MUST NOT generate a 100-continue expectation in a request
%% that does not include a message body. This implies that either the
%% Content-Length or the Transfer-Encoding header MUST be present.
%% DO NOT send content-type when Body is empty.
- Headers#http_request_h{'content-type' = ContentType};
+ Headers1 = Headers#http_request_h{'content-type' = ContentType},
+ handle_transfer_encoding(Headers1);
_ ->
Headers#http_request_h{
'content-length' = body_length(Body),
@@ -230,12 +233,26 @@ update_headers(Headers, ContentType, Body, []) ->
update_headers(_, _, _, HeadersAsIs) ->
HeadersAsIs.
+handle_transfer_encoding(Headers = #http_request_h{'transfer-encoding' = undefined}) ->
+ Headers;
+handle_transfer_encoding(Headers) ->
+ %% RFC7230 3.3.2
+ %% A sender MUST NOT send a 'Content-Length' header field in any message
+ %% that contains a 'Transfer-Encoding' header field.
+ Headers#http_request_h{'content-length' = undefined}.
+
body_length(Body) when is_binary(Body) ->
integer_to_list(size(Body));
body_length(Body) when is_list(Body) ->
integer_to_list(length(Body)).
+%% Set 'Content-Type' when it is explicitly set.
+handle_content_type(Headers, "") ->
+ Headers;
+handle_content_type(Headers, ContentType) ->
+ Headers#http_request_h{'content-type' = ContentType}.
+
method(Method) ->
http_util:to_upper(atom_to_list(Method)).
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 52f5fa03a9..37e4f97bc0 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -22,7 +22,7 @@
-export([print/1]).
-export([get/2, put/2, post/2, yahoo/2, test1/2, get_bin/2, peer/2,new_status_and_location/2]).
--export([newformat/3, post_chunked/3]).
+-export([newformat/3, post_chunked/3, post_204/3]).
%% These are used by the inets test-suite
-export([delay/1, chunk_timeout/3]).
@@ -151,6 +151,12 @@ post_chunked(SessionID, _Env, {last, _Body, undefined} = _Bodychunk) ->
post_chunked(_, _, _Body) ->
exit(body_not_chunked).
+post_204(SessionID, _Env, _Input) ->
+ mod_esi:deliver(SessionID,
+ ["Status: 204 No Content" ++ "\r\n\r\n"]),
+ mod_esi:deliver(SessionID, []).
+
+
newformat(SessionID,_,_) ->
mod_esi:deliver(SessionID, "Content-Type:text/html\r\n\r\n"),
mod_esi:deliver(SessionID, top("new esi format test")),
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index 4d419172d0..bf7554bd08 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,9 @@ handle_error(enoent, Op, ModData, Path) ->
handle_error(enotdir, Op, ModData, Path) ->
handle_error(404, Op, ModData, Path,
": A component of the file name is not a directory");
+handle_error(eisdir, Op, ModData, Path) ->
+ handle_error(403, Op, ModData, Path,
+ ":Ilegal operation expected a file not a directory");
handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index 3ee8665a54..bb946664f9 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -61,8 +61,12 @@ generate_and_send_response(#mod{config_db = ConfigDB} = ModData) ->
{StatusCode, Response} -> %% Old way
send_response_old(ModData, StatusCode, Response),
ok;
- undefined ->
- send_status(ModData, 500, none),
+ undefined ->
+ %% Happens when no mod_*
+ %% handles the request
+ send_status(ModData, 501, {ModData#mod.method,
+ ModData#mod.request_uri,
+ ModData#mod.http_version}),
ok
end
end
diff --git a/lib/inets/src/http_server/mod_esi.erl b/lib/inets/src/http_server/mod_esi.erl
index 21aafa7f7b..443b7ee564 100644
--- a/lib/inets/src/http_server/mod_esi.erl
+++ b/lib/inets/src/http_server/mod_esi.erl
@@ -394,7 +394,16 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
Continue;
{Headers, Body} ->
{ok, NewHeaders, StatusCode} = httpd_esi:handle_headers(Headers),
- IsDisableChunkedSend = httpd_response:is_disable_chunked_send(Db),
+ %% All 1xx (informational), 204 (no content), and 304 (not modified)
+ %% responses MUST NOT include a message-body, and thus are always
+ %% terminated by the first empty line after the header fields.
+ %% This implies that chunked encoding MUST NOT be used for these
+ %% status codes.
+ IsDisableChunkedSend =
+ httpd_response:is_disable_chunked_send(Db) orelse
+ StatusCode =:= 204 orelse %% No Content
+ StatusCode =:= 304 orelse %% Not Modified
+ (100 =< StatusCode andalso StatusCode =< 199), %% Informational
case (ModData#mod.http_version =/= "HTTP/1.1") or
(IsDisableChunkedSend) of
true ->
@@ -405,8 +414,8 @@ deliver_webpage_chunk(#mod{config_db = Db} = ModData, Pid, Timeout) ->
send_headers(ModData, StatusCode,
[{"transfer-encoding",
"chunked"} | NewHeaders])
- end,
- handle_body(Pid, ModData, Body, Timeout, length(Body),
+ end,
+ handle_body(Pid, ModData, Body, Timeout, length(Body),
IsDisableChunkedSend);
timeout ->
send_headers(ModData, 504, [{"connection", "close"}]),
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index 0dcf66265e..b197590bfd 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,10 +18,12 @@
%% %CopyrightEnd%
{"%VSN%",
[
+ {<<"7\\..*">>,[{restart_application, inets}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
],
[
+ {<<"7\\..*">>,[{restart_application, inets}]},
{<<"6\\..*">>,[{restart_application, inets}]},
{<<"5\\..*">>,[{restart_application, inets}]}
]
diff --git a/lib/inets/test/http_format_SUITE.erl b/lib/inets/test/http_format_SUITE.erl
index d6b0e5f9f5..0a5aed67d5 100644
--- a/lib/inets/test/http_format_SUITE.erl
+++ b/lib/inets/test/http_format_SUITE.erl
@@ -435,7 +435,7 @@ http_request(Config) when is_list(Config) ->
[<<>>, Length1], HttpBody1)).
%%-------------------------------------------------------------------------
validate_request_line() ->
- [{doc, "Test httpd_request:validate/3. Makes sure you can not get past"
+ [{doc, "Test httpd_request:validate/3. Makes sure you cannot get past"
" the server_root and that the request is recognized by the server"
" and protcol version."}].
validate_request_line(Config) when is_list(Config) ->
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 6e048a4d56..8357e02014 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -156,6 +156,7 @@ only_simulated() ->
multipart_chunks,
get_space,
delete_no_body,
+ post_with_content_type,
stream_fun_server_close
].
@@ -169,7 +170,9 @@ misc() ->
[
server_does_not_exist,
timeout_memory_leak,
- wait_for_whole_response
+ wait_for_whole_response,
+ post_204_chunked,
+ chunkify_fun
].
sim_mixed() ->
@@ -1391,6 +1394,109 @@ wait_for_whole_response(Config) when is_list(Config) ->
ReqSeqNumServer ! shutdown.
%%--------------------------------------------------------------------
+post_204_chunked() ->
+ [{doc,"Test that chunked encoded 204 responses do not freeze the http client"}].
+post_204_chunked(_Config) ->
+ Msg = "HTTP/1.1 204 No Content\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ Chunk = "0\r\n\r\n",
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
+ fun post_204_receive/0) end),
+
+ {ok,Host} = inet:gethostname(),
+ End = "/cgi-bin/erl/httpd_example:post_204",
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End,
+ {ok, _} = httpc:request(post, {URL, [], "text/html", []}, [], []),
+ timer:sleep(500),
+ %% Second request times out in the faulty case.
+ {ok, _} = httpc:request(post, {URL, [], "text/html", []}, [], []).
+
+post_204_receive() ->
+ receive
+ {tcp, _, Msg} ->
+ ct:log("Message received: ~p", [Msg])
+ after
+ 1000 ->
+ ct:fail("Timeout: did not recive packet")
+ end.
+
+%% Custom server is used to test special cases when using chunked encoding
+custom_server(Msg, Chunk, ListenSocket, ReceiveFun) ->
+ {ok, Accept} = gen_tcp:accept(ListenSocket),
+ ReceiveFun(),
+ send_response(Msg, Chunk, Accept),
+ custom_server_loop(Msg, Chunk, Accept, ReceiveFun).
+
+custom_server_loop(Msg, Chunk, Accept, ReceiveFun) ->
+ ReceiveFun(),
+ send_response(Msg, Chunk, Accept),
+ custom_server_loop(Msg, Chunk, Accept, ReceiveFun).
+
+send_response(Msg, Chunk, Socket) ->
+ inet:setopts(Socket, [{active, once}]),
+ gen_tcp:send(Socket, Msg),
+ timer:sleep(250),
+ gen_tcp:send(Socket, Chunk).
+
+%%--------------------------------------------------------------------
+chunkify_fun() ->
+ [{doc,"Test that a chunked encoded request does not include the 'Content-Length header'"}].
+chunkify_fun(_Config) ->
+ Msg = "HTTP/1.1 204 No Content\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ Chunk = "0\r\n\r\n",
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
+ fun chunkify_receive/0) end),
+
+ {ok,Host} = inet:gethostname(),
+ End = "/cgi-bin/erl/httpd_example",
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port) ++ End,
+ Fun = fun(_) -> {ok,<<1>>,eof_body} end,
+ Acc = start,
+
+ {ok, {{_,204,_}, _, _}} =
+ httpc:request(put, {URL, [], "text/html", {chunkify, Fun, Acc}}, [], []).
+
+chunkify_receive() ->
+ Error = "HTTP/1.1 500 Internal Server Error\r\n" ++
+ "Content-Length: 0\r\n\r\n",
+ receive
+ {tcp, Port, Msg} ->
+ case binary:match(Msg, <<"content-length">>) of
+ nomatch ->
+ ct:log("Message received: ~s", [binary_to_list(Msg)]);
+ {_, _} ->
+ ct:log("Message received (negative): ~s", [binary_to_list(Msg)]),
+ %% Signal a testcase failure when the received HTTP request
+ %% contains a 'Content-Length' header.
+ gen_tcp:send(Port, Error),
+ ct:fail("Content-Length present in received headers.")
+ end
+ after
+ 1000 ->
+ ct:fail("Timeout: did not recive packet")
+ end.
+%%--------------------------------------------------------------------
stream_fun_server_close() ->
[{doc, "Test that an error msg is received when using a receiver fun as stream target"}].
stream_fun_server_close(Config) when is_list(Config) ->
@@ -1496,6 +1602,15 @@ delete_no_body(Config) when is_list(Config) ->
httpc:request(delete, {URL, [], "text/plain", "TEST"}, [], []).
%%--------------------------------------------------------------------
+post_with_content_type(doc) ->
+ ["Test that a POST request with explicit 'Content-Type' does not drop the 'Content-Type' header - Solves ERL-736"];
+post_with_content_type(Config) when is_list(Config) ->
+ URL = url(group_name(Config), "/delete_no_body.html", Config),
+ %% Simulated server replies 500 if 'Content-Type' header is present
+ {ok, {{_,500,_}, _, _}} =
+ httpc:request(post, {URL, [], "application/x-www-form-urlencoded", ""}, [], []).
+
+%%--------------------------------------------------------------------
request_options() ->
[{doc, "Test http get request with socket options against local server (IPv6)"}].
request_options(Config) when is_list(Config) ->
diff --git a/lib/inets/test/httpc_proxy_SUITE.erl b/lib/inets/test/httpc_proxy_SUITE.erl
index 198b245399..3ee7981660 100644
--- a/lib/inets/test/httpc_proxy_SUITE.erl
+++ b/lib/inets/test/httpc_proxy_SUITE.erl
@@ -534,7 +534,7 @@ init_local_proxy(Config) ->
ct:fail({local_proxy_start_failed,Error})
end;
_ ->
- {skip,"Platform can not run local proxy start script"}
+ {skip,"Platform cannot run local proxy start script"}
end.
init_local_proxy_string(String, Config) ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 97aca73d6b..5b6740fba3 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -76,6 +76,8 @@ all() ->
{group, http_logging},
{group, http_post},
{group, http_rel_path_script_alias},
+ {group, http_not_sup},
+ {group, https_not_sup},
mime_types_format
].
@@ -103,6 +105,8 @@ groups() ->
{http_reload, [], [{group, reload}]},
{https_reload, [], [{group, reload}]},
{http_post, [], [{group, post}]},
+ {http_not_sup, [], [{group, not_sup}]},
+ {https_not_sup, [], [{group, not_sup}]},
{http_mime_types, [], [alias_1_1, alias_1_0, alias_0_9]},
{limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]},
{custom, [], [customize, add_default]},
@@ -116,7 +120,7 @@ groups() ->
disturbing_0_9,
reload_config_file
]},
- {post, [], [chunked_post, chunked_chunked_encoded_post]},
+ {post, [], [chunked_post, chunked_chunked_encoded_post, post_204]},
{basic_auth, [], [basic_auth_1_1, basic_auth_1_0, basic_auth_0_9]},
{auth_api, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9
]},
@@ -134,7 +138,8 @@ groups() ->
esi_put, esi_post] ++ http_head() ++ http_get() ++ load()},
{http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
{http_0_9, [], http_head() ++ http_get() ++ load()},
- {http_rel_path_script_alias, [], [cgi]}
+ {http_rel_path_script_alias, [], [cgi]},
+ {not_sup, [], [put_not_sup]}
].
basic_groups ()->
@@ -207,7 +212,8 @@ init_per_group(Group, Config0) when Group == https_basic;
Group == https_auth_api_dets;
Group == https_auth_api_mnesia;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
catch crypto:stop(),
try crypto:start() of
@@ -226,6 +232,7 @@ init_per_group(Group, Config0) when Group == http_basic;
Group == http_auth_api_mnesia;
Group == http_security;
Group == http_reload;
+ Group == http_not_sup;
Group == http_post;
Group == http_mime_types
->
@@ -275,6 +282,8 @@ init_per_group(http_logging, Config) ->
init_per_group(http_rel_path_script_alias = Group, Config) ->
ok = start_apps(Group),
init_httpd(Group, [{type, ip_comm},{http_version, "HTTP/1.1"}| Config]);
+init_per_group(not_sup, Config) ->
+ [{http_version, "HTTP/1.1"} | Config];
init_per_group(_, Config) ->
Config.
@@ -448,8 +457,19 @@ get(Config) when is_list(Config) ->
{header, "Content-Type", "text/html"},
{header, "Date"},
{header, "Server"},
+ {version, Version}]),
+
+ ok = httpd_test_lib:verify_request(proplists:get_value(type, Config), Host,
+ proplists:get_value(port, Config),
+ transport_opts(Type, Config),
+ proplists:get_value(node, Config),
+ http_request("GET /open/ ", Version, Host),
+ [{statuscode, 403},
+ {header, "Content-Type", "text/html"},
+ {header, "Date"},
+ {header, "Server"},
{version, Version}]).
-
+
basic_auth_1_1(Config) when is_list(Config) ->
basic_auth([{http_version, "HTTP/1.1"} | Config]).
@@ -733,6 +753,42 @@ chunked_chunked_encoded_post(Config) when is_list(Config) ->
[{http_version, "HTTP/1.1"} | Config],
[{statuscode, 200}]).
+%%-------------------------------------------------------------------------
+post_204() ->
+ [{doc,"Test that 204 responses are not chunk encoded"}].
+post_204(Config) ->
+ Host = proplists:get_value(host, Config),
+ Port = proplists:get_value(port, Config),
+ SockType = proplists:get_value(type, Config),
+ TranspOpts = transport_opts(SockType, Config),
+ Request = "POST /cgi-bin/erl/httpd_example:post_204 ",
+
+ try inets_test_lib:connect_bin(SockType, Host, Port, TranspOpts) of
+ {ok, Socket} ->
+ RequestStr = http_request(Request, "HTTP/1.1", Host),
+ ok = inets_test_lib:send(SockType, Socket, RequestStr),
+ receive
+ {tcp, Socket, Data} ->
+ case binary:match(Data, <<"chunked">>,[]) of
+ nomatch ->
+ ok;
+ {_, _} ->
+ ct:fail("Chunked encoding detected.")
+ end
+ after 2000 ->
+ ct:fail(connection_timed_out)
+ end;
+ ConnectError ->
+ ct:fail({connect_error, ConnectError,
+ [SockType, Host, Port, TranspOpts]})
+ catch
+ T:E ->
+ ct:fail({connect_failure,
+ [{type, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()},
+ {args, [SockType, Host, Port, TranspOpts]}]})
+ end.
%%-------------------------------------------------------------------------
htaccess_1_1(Config) when is_list(Config) ->
@@ -898,6 +954,33 @@ max_clients_0_9() ->
max_clients_0_9(Config) when is_list(Config) ->
do_max_clients([{http_version, "HTTP/0.9"} | Config]).
+
+
+%%-------------------------------------------------------------------------
+put_not_sup() ->
+ [{doc, "Test unhandled request"}].
+
+put_not_sup(Config) when is_list(Config) ->
+ ok = http_status("PUT /index.html ",
+ {"Content-Length:100 \r\n",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"},
+ Config, [{statuscode, 501}]).
%%-------------------------------------------------------------------------
esi() ->
[{doc, "Test mod_esi"}].
@@ -1793,7 +1876,8 @@ start_apps(Group) when Group == https_basic;
Group == https_auth_api_mnesia;
Group == https_htaccess;
Group == https_security;
- Group == https_reload
+ Group == https_reload;
+ Group == https_not_sup
->
inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]);
start_apps(Group) when Group == http_basic;
@@ -1809,7 +1893,9 @@ start_apps(Group) when Group == http_basic;
Group == http_reload;
Group == http_post;
Group == http_mime_types;
- Group == http_rel_path_script_alias ->
+ Group == http_rel_path_script_alias;
+ Group == http_not_sup;
+ Group == http_mime_types->
inets_test_lib:start_apps([inets]).
server_start(_, HttpdConfig) ->
@@ -1844,6 +1930,10 @@ server_config(http_basic, Config) ->
basic_conf() ++ server_config(http, Config);
server_config(https_basic, Config) ->
basic_conf() ++ server_config(https, Config);
+server_config(http_not_sup, Config) ->
+ not_sup_conf() ++ server_config(http, Config);
+server_config(https_not_sup, Config) ->
+ not_sup_conf() ++ server_config(https, Config);
server_config(http_reload, Config) ->
[{keep_alive_timeout, 2}] ++ server_config(http, Config);
server_config(http_post, Config) ->
@@ -1992,7 +2082,10 @@ head_status(_) ->
basic_conf() ->
[{modules, [mod_alias, mod_range, mod_responsecontrol,
- mod_trace, mod_esi, mod_cgi, mod_dir, mod_get, mod_head]}].
+ mod_trace, mod_esi, mod_cgi, mod_get, mod_head]}].
+
+not_sup_conf() ->
+ [{modules, [mod_get]}].
auth_access_conf() ->
[{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]},
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index b76390ad66..26adb854e1 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 7.0
+INETS_VSN = 7.0.2
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/doc/src/Makefile b/lib/jinterface/doc/src/Makefile
index 6f1ecc8dea..d80bb38ec1 100644
--- a/lib/jinterface/doc/src/Makefile
+++ b/lib/jinterface/doc/src/Makefile
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml
index 9aaa8a0840..e4bfddcd17 100644
--- a/lib/jinterface/doc/src/notes.xml
+++ b/lib/jinterface/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Jinterface application.</p>
+<section><title>Jinterface 1.9.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Jinterface 1.9</title>
<section><title>Improvements and New Features</title>
@@ -705,7 +720,7 @@
<item>
<p><c>OtpMbox.receive()</c> and <c>OtpMbox.receive(long timeout)</c> can now throw
<c>OtpErlangDecodeException</c> if the received message
- can not be decoded. <c>null</c> is now only returned from
+ cannot be decoded. <c>null</c> is now only returned from
<c>OtpMbox.receive(long timeout)</c> if a timeout occurs.
<c>OtpMbox.receive()</c> will never return <c>null</c>.</p>
<p>*** POTENTIAL INCOMPATIBILITY ***</p>
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
index 363fdb950a..fffb8475d3 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpEpmd.java
@@ -102,7 +102,7 @@ public class OtpEpmd {
/**
* Set the port number to be used to contact the epmd process. Only needed
* when the default port is not desired and system environment variable
- * ERL_EPMD_PORT can not be read (applet).
+ * ERL_EPMD_PORT cannot be read (applet).
*/
public static void useEpmdPort(final int port) {
EpmdPort.set(port);
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
index ded8f6e1e5..6d81ce630b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
@@ -601,7 +601,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive integer.
*/
public int read_uint() throws OtpErlangDecodeException {
@@ -622,7 +622,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the integer value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as
+ * if the next term in the stream cannot be represented as
* an integer.
*/
public int read_int() throws OtpErlangDecodeException {
@@ -643,7 +643,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive short.
*/
public short read_ushort() throws OtpErlangDecodeException {
@@ -664,7 +664,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the short value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* short.
*/
public short read_short() throws OtpErlangDecodeException {
@@ -685,7 +685,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* positive long.
*/
public long read_ulong() throws OtpErlangDecodeException {
@@ -698,7 +698,7 @@ public class OtpInputStream extends ByteArrayInputStream {
* @return the long value.
*
* @exception OtpErlangDecodeException
- * if the next term in the stream can not be represented as a
+ * if the next term in the stream cannot be represented as a
* long.
*/
public long read_long() throws OtpErlangDecodeException {
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
index 42e178c3f6..29a8bc1540 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java
@@ -156,7 +156,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
@@ -184,7 +184,7 @@ public class OtpMbox {
* of the next message waiting in this mailbox.
*
* @exception OtpErlangDecodeException
- * if the message can not be decoded.
+ * if the message cannot be decoded.
*
* @exception OtpErlangExit
* if a linked {@link OtpErlangPid pid} has exited or has
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index f527a83092..a8dc815145 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.9
+JINTERFACE_VSN = 1.9.1
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml
index aff3e8133c..69ce4da61c 100644
--- a/lib/kernel/doc/src/code.xml
+++ b/lib/kernel/doc/src/code.xml
@@ -538,7 +538,7 @@ zip:create("mnesia-4.4.7.ez",
</item>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
@@ -611,7 +611,7 @@ ok = code:finish_loading(Prepared),
<taglist>
<tag><c>not_purged</c></tag>
<item>
- <p>The object code can not be loaded because an old version
+ <p>The object code cannot be loaded because an old version
of the code already exists.</p>
</item>
<tag><c>sticky_directory</c></tag>
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 737800c6b1..1e08b25f66 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2007</year><year>2016</year>
+ <year>2007</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -331,6 +331,37 @@ connect(Socket, Ip, Port>,
with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large
<seealso marker="inet#option-sndbuf">kernel</seealso> and driver
<seealso marker="inet#option-buffer">buffers</seealso>.</p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">passive</seealso>
+ mode data can be received through the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ calls.
+ </p>
+ <p>
+ If the socket is in
+ <seealso marker="#option-active">active</seealso>
+ mode data received data is delivered to the controlling process
+ as messages:
+ </p>
+ <code type="none">
+{sctp, <anno>Socket</anno>, FromIP, FromPort, {AncData, Data}}
+ </code>
+ <p>
+ See
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ for a description of the message fields.
+ </p>
+ <note>
+ <p>
+ This message format unfortunately differs slightly from the
+ <seealso marker="gen_udp#open/1"><c>gen_udp</c></seealso>
+ message format with ancillary data,
+ and from the
+ <seealso marker="#recv/1"><c>recv/1,2</c></seealso>
+ return tuple format.
+ </p>
+ </note>
</desc>
</func>
@@ -380,6 +411,19 @@ connect(Socket, Ip, Port>,
socket option
<seealso marker="#option-sctp_get_peer_addr_info"><c>sctp_get_peer_addr_info</c></seealso>,
but this does still not produce the stream number).</p>
+ <p>
+ <c><anno>AncData</anno></c> may also contain
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ from the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>,
+ if that is supported by the platform for the socket.
+ </p>
<p>The <c><anno>Data</anno></c> received can be a <c>binary()</c>
or a <c>list()</c> of bytes (integers in the range 0 through 255)
depending on the socket mode, or an SCTP event.</p>
@@ -544,12 +588,25 @@ connect(Socket, Ip, Port>,
<seealso marker="#recv/1"><c>recv</c></seealso> call
to retrieve the available data from the socket.</p>
</item>
+ <item>
+ <p>
+ If <c>true|once|N</c> (active modes)
+ received data or events are sent to the owning process.
+ See <seealso marker="#open/0"><c>open/0..2</c></seealso>
+ for the message format.
+ </p>
+ </item>
<item>
- <p>If <c>true</c> (full active mode), the pending data or events are
- sent to the owning process.</p>
- <p>Notice that this can cause the message queue to overflow,
- as there is no way to throttle the sender in this case
- (no flow control).</p>
+ <p>
+ If <c>true</c> (full active mode) there is no flow control.
+ </p>
+ <note>
+ <p>
+ Note that this can cause the message queue to overflow
+ causing for example the virtual machine
+ to run out of memory and crash.
+ </p>
+ </note>
</item>
<item>
<p>If <c>once</c>, only one message is automatically placed
diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml
index e6104b0c76..24d63693fd 100644
--- a/lib/kernel/doc/src/gen_tcp.xml
+++ b/lib/kernel/doc/src/gen_tcp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -70,6 +70,32 @@ do_recv(Sock, Bs) ->
<name name="option"/>
</datatype>
<datatype>
+ <name name="pktoptions_value"/>
+ <desc>
+ <p>
+ If the platform implements the IPv4 option
+ <c>IP_PKTOPTIONS</c>, or the IPv6 option
+ <c>IPV6_PKTOPTIONS</c> or <c>IPV6_2292PKTOPTIONS</c> for the socket
+ this value is returned from
+ <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>
+ when called with the option name
+ <seealso marker="#type-option_name"><c>pktoptions</c></seealso>.
+ </p>
+ <note>
+ <p>
+ This option appears to be VERY Linux specific,
+ and its existence in future Linux kernel versions
+ is also worrying since the option is part of RFC 2292
+ which is since long (2003) obsoleted by RFC 3542
+ that <em>explicitly</em> removes this possibility to get
+ packet information from a stream socket.
+ For comparision: it has existed in FreeBSD but is now removed,
+ at least since FreeBSD 10.
+ </p>
+ </note>
+ </desc>
+ </datatype>
+ <datatype>
<name name="option_name"/>
</datatype>
<datatype>
diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml
index f79566ef71..840ca3c188 100644
--- a/lib/kernel/doc/src/gen_udp.xml
+++ b/lib/kernel/doc/src/gen_udp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -147,7 +147,21 @@
at the opened port, if the socket is in an active mode, the packets
are delivered as messages to the controlling process:</p>
<code type="none">
-{udp, Socket, IP, InPortNo, Packet}</code>
+{udp, Socket, IP, InPortNo, Packet} % Without ancillary data
+{udp, Socket, IP, InPortNo, AncData, Packet} % With ancillary data
+ </code>
+ <p>
+ The message contains an <c>AncData</c> field
+ if any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, otherwise it does not.
+ </p>
+ <p>
+ </p>
<p>If the socket is not in an active mode, data can be
retrieved through the
<seealso marker="#recv/2"><c>recv/2,3</c></seealso> calls.
@@ -179,9 +193,22 @@
<name name="recv" arity="3"/>
<fsummary>Receive a packet from a passive socket.</fsummary>
<desc>
- <p>Receives a packet from a socket in passive mode. Optional parameter
+ <p>
+ Receives a packet from a socket in passive mode. Optional parameter
<c><anno>Timeout</anno></c> specifies a time-out in milliseconds.
- Defaults to <c>infinity</c>.</p>
+ Defaults to <c>infinity</c>.
+ </p>
+ <p>
+ If any of the socket
+ <seealso marker="#type-option">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ or
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>
+ are active, the <c><anno>RecvData</anno></c> tuple contains an
+ <c><anno>AncData</anno></c> field,
+ otherwise it does not.
+ </p>
</desc>
</func>
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index e6a7962c5a..87b08e4e36 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -177,6 +177,100 @@ fe80::204:acff:fe17:bf38
</desc>
</datatype>
<datatype>
+ <name name="ancillary_data"/>
+ <desc>
+ <p>
+ Ancillary data received with the data packet
+ or read with the socket option
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ from a TCP socket.
+ </p>
+ <p>
+ The value(s) correspond to the currently active socket
+ <seealso marker="#type-socket_setopt">options</seealso>
+ <seealso marker="inet#option-recvtos"><c>recvtos</c></seealso>,
+ <seealso marker="inet#option-recvtclass"><c>recvtclass</c></seealso>
+ and
+ <seealso marker="inet#option-recvttl"><c>recvttl</c></seealso>.
+ </p>
+ </desc>
+ </datatype>
+ <datatype>
+ <name name="getifaddrs_ifopts"/>
+ <desc>
+ <p>
+ Interface address description list returned from
+ <seealso marker="#getifaddrs/0"><c>getifaddrs/0,1</c></seealso>
+ for a named interface, translated from the returned
+ data of the POSIX API function <c>getaddrinfo()</c>.
+ </p>
+ <p>
+ <c><anno>Hwaddr</anno></c> is hardware dependent,
+ for example, on Ethernet interfaces it is
+ the 6-byte Ethernet address (MAC address (EUI-48 address)).
+ </p>
+ <p>
+ The tuples <c>{addr,<anno>Addr</anno>}</c>,
+ <c>{netmask,<anno>Netmask</anno>}</c>, and possibly
+ <c>{broadaddr,<anno>Broadaddr</anno>}</c> or
+ <c>{dstaddr,<anno>Dstaddr</anno>}</c>
+ are repeated in the list
+ if the interface has got multiple addresses.
+ An interface may have multiple <c>{flag,_}</c> tuples
+ for example if it has different flags
+ for different address families.
+ Multiple <c>{hwaddr,<anno>Hwaddr</anno>}</c> tuples
+ is hard to say anything definite about, though.
+ The tuple <c>{flag,<anno>Flags</anno>}</c> is mandatory,
+ all others are optional.
+ </p>
+ <p>
+ Do not rely too much on the order
+ of <c><anno>Flags</anno></c> atoms
+ or the <c><anno>Ifopt</anno></c> tuples.
+ There are however some rules:
+ </p>
+ <list type="bulleted">
+ <item><p>
+ A <c>{flag,_}</c> tuple applies to all other tuples that follow.
+ </p></item>
+ <item><p>
+ Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c>.
+ </p></item>
+ <item><p>
+ Immediately thereafter may <c>{broadaddr,_}</c> follow
+ if <c>broadcast</c> is member of <c><anno>Flags</anno></c>,
+ or <c>{dstaddr,_}</c> if <c>pointtopoint</c>
+ is member of <c><anno>Flags</anno></c>.
+ Both <c>{dstaddr,_}</c> and <c>{broadaddr,_}</c>
+ does not occur for the same <c>{addr,_}</c>.
+ </p></item>
+ <item><p>
+ Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c>, or
+ <c>{dstaddr,_}</c> tuples that follow an
+ <c>{addr,<anno>Addr</anno>}</c>
+ tuple concerns the address <c><anno>Addr</anno></c>.
+ </p></item>
+ </list>
+ <p>
+ The tuple <c>{hwaddr,_}</c> is not returned on Solaris, as the
+ hardware address historically belongs to the link layer
+ and it is not returned by the Solaris API function
+ <c>getaddrinfo()</c>.
+ </p>
+ <warning>
+ <p>
+ On Windows, the data is fetched from different
+ OS API functions, so the <c><anno>Netmask</anno></c>
+ and <c><anno>Broadaddr</anno></c> values may be calculated,
+ just as some <c><anno>Flags</anno></c> values.
+ </p>
+ </warning>
+ </desc>
+ </datatype>
+ <datatype>
<name name="posix"/>
<desc>
<p>An atom that is named from the POSIX error codes used in Unix,
@@ -303,38 +397,64 @@ fe80::204:acff:fe17:bf38
<name name="getifaddrs" arity="0"/>
<fsummary>Return a list of interfaces and their addresses.</fsummary>
<desc>
- <p>Returns a list of 2-tuples containing interface names and the
- interface addresses. <c><anno>Ifname</anno></c> is a Unicode string.
- <c><anno>Hwaddr</anno></c> is hardware dependent, for example, on
- Ethernet interfaces
- it is the 6-byte Ethernet address (MAC address (EUI-48 address)).</p>
- <p>The tuples <c>{addr,<anno>Addr</anno>}</c>, <c>{netmask,_}</c>, and
- <c>{broadaddr,_}</c> are repeated in the result list if the interface
- has multiple addresses. If you come across an interface with
- multiple <c>{flag,_}</c> or <c>{hwaddr,_}</c> tuples, you have
- a strange interface or possibly a bug in this function. The tuple
- <c>{flag,_}</c> is mandatory, all others are optional.</p>
- <p>Do not rely too much on the order of <c><anno>Flag</anno></c> atoms
- or <c><anno>Ifopt</anno></c> tuples. There are however some rules:</p>
- <list type="bulleted">
- <item><p>Immediately after
- <c>{addr,_}</c> follows <c>{netmask,_}</c>.</p></item>
- <item><p>Immediately thereafter follows <c>{broadaddr,_}</c> if flag
- <c>broadcast</c> is <em>not</em> set and flag
- <c>pointtopoint</c> <em>is</em> set.</p></item>
- <item><p>Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c>, or
- <c>{dstaddr,_}</c> tuples that follow an <c>{addr,_}</c>
- tuple concerns that address.</p></item>
- </list>
- <p>The tuple <c>{hwaddr,_}</c> is not returned on Solaris, as the
- hardware address historically belongs to the link layer and only
- the superuser can read such addresses.</p>
- <warning>
- <p>On Windows, the data is fetched from different OS API functions,
- so the <c><anno>Netmask</anno></c> and <c><anno>Broadaddr</anno></c>
- values can be calculated, just as some <c><anno>Flag</anno></c>
- values. Report flagrant bugs.</p>
- </warning>
+ <p>
+ Returns a list of 2-tuples containing interface names and
+ the interfaces' addresses. <c><anno>Ifname</anno></c>
+ is a Unicode string and
+ <c><anno>Ifopts</anno></c> is a list of
+ interface address description tuples.
+ </p>
+ <p>
+ The interface address description tuples
+ are documented under the type of the
+ <seealso marker="#type-getifaddrs_ifopts">
+ <c><anno>Ifopts</anno></c>
+ </seealso>
+ value.
+ </p>
+ </desc>
+ </func>
+
+ <func>
+ <name>getifaddrs(Opts) ->
+ {ok, [{Ifname, Ifopts}]} | {error, Posix}
+ </name>
+ <fsummary>Return a list of interfaces and their addresses.</fsummary>
+ <type>
+ <v>
+ Opts = [{netns, Namespace}]
+ </v>
+ <v>
+ Namespace =
+ <seealso marker="file#type-filename_all">
+ file:filename_all()
+ </seealso>
+ </v>
+ <v>Ifname = string()</v>
+ <v>
+ Ifopts =
+ <seealso marker="#type-getifaddrs_ifopts">
+ getifaddrs_ifopts()
+ </seealso>
+ </v>
+ <v>Posix = <seealso marker="#type-posix">posix()</seealso></v>
+ </type>
+ <desc>
+ <p>
+ The same as
+ <seealso marker="#getifaddrs/0"><c>getifaddrs/0</c></seealso>
+ but the <c>Option</c>
+ <c>{netns, Namespace}</c> sets a network namespace
+ for the OS call, on platforms that supports that feature.
+ </p>
+ <p>
+ See the socket option
+ <seealso marker="#option-netns">
+ <c>{netns, Namespace}</c>
+ </seealso>
+ under
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ </p>
</desc>
</func>
@@ -344,7 +464,11 @@ fe80::204:acff:fe17:bf38
<desc>
<p>Gets one or more options for a socket. For a list of available
options, see
- <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.</p>
+ <seealso marker="#setopts/2"><c>setopts/2</c></seealso>.
+ See also the description for the type
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>gen_tcp:pktoptions_value()</c>
+ </seealso>.</p>
<p>The number of elements in the returned
<c><anno>OptionValues</anno></c>
list does not necessarily correspond to the number of options
@@ -360,7 +484,7 @@ fe80::204:acff:fe17:bf38
socket options not (explicitly) supported by the emulator. The
use of raw socket options makes the code non-portable, but
allows the Erlang programmer to take advantage of unusual features
- present on the current platform.</p>
+ present on a particular platform.</p>
<p><c>RawOptReq</c> consists of tag <c>raw</c> followed
by the protocol level, the option number, and either a binary
or the size, in bytes, of the
@@ -734,22 +858,23 @@ get_tcpi_sacked(Sock) ->
</item>
<tag><c>{buffer, Size}</c></tag>
<item>
- <p>The size of the user-level software buffer used by
- the driver.
- Not to be confused with options <c>sndbuf</c>
+ <p>The size of the user-level buffer used by
+ the driver. Not to be confused with options <c>sndbuf</c>
and <c>recbuf</c>, which correspond to the
- Kernel socket buffers. It is recommended
- to have <c>val(buffer) &gt;= max(val(sndbuf),val(recbuf))</c> to
+ Kernel socket buffers. For TCP it is recommended
+ to have <c>val(buffer) &gt;= val(recbuf)</c> to
avoid performance issues because of unnecessary copying.
+ For UDP the same recommendation applies, but the max should
+ not be larger than the MTU of the network path.
<c>val(buffer)</c> is automatically set to the above
- maximum when values <c>sndbuf</c> or <c>recbuf</c> are set.
- However, as the sizes set for <c>sndbuf</c> and <c>recbuf</c>
+ maximum when <c>recbuf</c> is set.
+ However, as the size set for <c>recbuf</c>
usually become larger, you are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to analyze the behavior of your operating system.</p>
<p>Note that this is also the maximum amount of data that can be
- received from a single recv call. If you are using higher than
- normal MTU consider setting buffer higher.</p>
+ received from a single recv call. If you are using higher than
+ normal MTU consider setting buffer higher.</p>
</item>
<tag><c>{delay_send, Boolean}</c></tag>
<item>
@@ -924,20 +1049,29 @@ get_tcpi_sacked(Sock) ->
</item>
<tag><c>{mode, Mode :: binary | list}</c></tag>
<item>
- <p>Received <c>Packet</c> is delivered as defined by <c>Mode</c>.
+ <p>
+ Received <c>Packet</c> is delivered as defined by <c>Mode</c>.
</p>
</item>
- <tag><c>{netns, Namespace :: file:filename_all()}</c></tag>
+ <tag>
+ <marker id="option-netns"/>
+ <c>{netns, Namespace :: file:filename_all()}</c>
+ </tag>
<item>
- <p>Sets a network namespace for the socket. Parameter
+ <p>
+ Sets a network namespace for the socket. Parameter
<c>Namespace</c> is a filename defining the namespace, for
example, <c>"/var/run/netns/example"</c>, typically created by
command <c>ip netns add example</c>. This option must be used in
a function call that creates a socket, that is,
<seealso marker="gen_tcp#connect/3"><c>gen_tcp:connect/3,4</c></seealso>,
<seealso marker="gen_tcp#listen/2"><c>gen_tcp:listen/2</c></seealso>,
- <seealso marker="gen_udp#open/1"><c>gen_udp:open/1,2</c></seealso>, or
- <seealso marker="gen_sctp#open/0"><c>gen_sctp:open/0,1,2</c></seealso>.</p>
+ <seealso marker="gen_udp#open/1"><c>gen_udp:open/1,2</c></seealso>
+ or
+ <seealso marker="gen_sctp#open/0"><c>gen_sctp:open/0,1,2</c></seealso>,
+ and also
+ <seealso marker="#getifaddrs/1"><c>getifaddrs/1</c></seealso>.
+ </p>
<p>This option uses the Linux-specific syscall
<c>setns()</c>, such as in Linux kernel 3.0 or later,
and therefore only exists when the runtime system
@@ -1013,6 +1147,18 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
is turned on for the socket, which means that also small
amounts of data are sent immediately.</p>
</item>
+ <tag><c>{nopush, Boolean}</c>(TCP/IP sockets)</tag>
+ <item>
+ <p>This translates to <c>TCP_NOPUSH</c> on BSD and
+ to <c>TCP_CORK</c> on Linux.</p>
+ <p>If <c>Boolean == true</c>, the corresponding option
+ is turned on for the socket, which means that small
+ amounts of data are accumulated until a full MSS-worth
+ of data is available or this option is turned off.</p>
+ <p>Note that while <c>TCP_NOPUSH</c> socket option is available on OSX, its semantics
+ is very different (e.g., unsetting it does not cause immediate send
+ of accumulated data). Hence, <c>nopush</c> option is intentionally ignored on OSX.</p>
+ </item>
<tag><c>{packet, PacketType}</c>(TCP/IP sockets)</tag>
<item>
<p><marker id="packet"/>Defines the type of packets to use for a socket.
@@ -1114,6 +1260,100 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp</code>
the socket. You are encouraged to use
<seealso marker="#getopts/2"><c>getopts/2</c></seealso>
to retrieve the size set by your operating system.</p>
+ <marker id="option-recvtclass"></marker>
+ </item>
+ <tag><c>{recvtclass, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TCLASS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IPV6</c>
+ option <c>IPV6_RECVTCLASS</c> or <c>IPV6_2292RECVTCLASS</c>
+ for the socket.
+ The value is returned as a <c>{tclass,TCLASS}</c> tuple
+ regardless of if the platform returns an <c>IPV6_TCLASS</c>
+ or an <c>IPV6_RECVTCLASS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TCLASS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TCLASS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvtos"></marker>
+ </item>
+ <tag><c>{recvtos, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TOS</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTOS</c>
+ for the socket.
+ The value is returned as a <c>{tos,TOS}</c> tuple
+ regardless of if the platform returns an <c>IP_TOS</c>
+ or an <c>IP_RECVTOS</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TOS</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TOS</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
+ <marker id="option-recvttl"></marker>
+ </item>
+ <tag><c>{recvttl, Boolean}</c></tag>
+ <item>
+ <p>
+ If set to <c>true</c> activates returning the received
+ <c>TTL</c> value on platforms that implements
+ the protocol <c>IPPROTO_IP</c> option <c>IP_RECVTTL</c>
+ for the socket.
+ The value is returned as a <c>{ttl,TTL}</c> tuple
+ regardless of if the platform returns an <c>IP_TTL</c>
+ or an <c>IP_RECVTTL</c> CMSG value.
+ </p>
+ <p>
+ For packet oriented sockets that supports receiving
+ ancillary data with the payload data
+ (<c>gen_udp</c> and <c>gen_sctp</c>),
+ the <c>TTL</c> value is returned
+ in an extended return tuple contained in an
+ <seealso marker="inet#type-ancillary_data">
+ ancillary data
+ </seealso>
+ list.
+ For stream oriented sockets (<c>gen_tcp</c>)
+ the only way to get the <c>TTL</c>
+ value is if the platform supports the
+ <seealso marker="gen_tcp#type-pktoptions_value">
+ <c>pktoptions</c>
+ </seealso>
+ option.
+ </p>
</item>
<tag><c>{reuseaddr, Boolean}</c></tag>
<item>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index 3914226a3e..15dbdb47dc 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -192,7 +192,7 @@
<p>To change the primary log level at runtime, use
<seealso marker="logger#set_primary_config/2">
<c>logger:set_primary_config(level, Level)</c></seealso>.</p>
- <p>Defaults to <c>info</c>.</p>
+ <p>Defaults to <c>notice</c>.</p>
</item>
<tag><marker id="logger_sasl_compatible"/>
<c>logger_sasl_compatible = true | false</c></tag>
@@ -310,24 +310,31 @@
<tag><c>net_ticktime = TickTime</c></tag>
<item>
<marker id="net_ticktime"></marker>
- <p>Specifies the <c>net_kernel</c> tick time. <c>TickTime</c>
- is specified in seconds. Once every <c>TickTime/4</c> second, all
- connected nodes are ticked (if anything else is written
- to a node). If nothing is received from another node
- within the last four tick times, that node is considered
- to be down. This ensures that nodes that are not responding,
- for reasons such as hardware errors, are considered to be
- down.</p>
- <p>The time <c>T</c>, in which a node that is not responding is
- detected, is calculated as <c><![CDATA[MinT < T < MaxT]]></c>, where:</p>
+ <p>Specifies the <c>net_kernel</c> tick time in seconds. This is the
+ approximate time a connected node may be unresponsive until it is
+ considered down and thereby disconnected.</p>
+ <p>Once every <c>TickTime/4</c> seconds, each connected node is ticked
+ if nothing has been sent to it during that last <c>TickTime/4</c>
+ interval. A tick is a small package sent on the connection. A connected
+ node is considered to be down if no ticks or payload packages have been
+ received during the last four <c>TickTime/4</c> intervals. This ensures
+ that nodes that are not responding, for reasons such as hardware errors,
+ are considered to be down.</p>
+ <p>As the availability is only checked every <c>TickTime/4</c> seconds,
+ the actual time <c>T</c> a node have been unresponsive when
+ detected may vary between <c>MinT</c> and <c>MaxT</c>,
+ where:</p>
<code type="none">
MinT = TickTime - TickTime / 4
MaxT = TickTime + TickTime / 4</code>
- <p><c>TickTime</c> defaults to <c>60</c> (seconds). Thus,
- <c><![CDATA[45 < T < 75]]></c> seconds.</p>
- <p>Notice that <em>all</em> communicating nodes are to have the <em>same</em>
- <c>TickTime</c> value specified.</p>
- <p>Normally, a terminating node is detected immediately.</p>
+ <p><c>TickTime</c> defaults to <c>60</c> seconds. Thus,
+ <c><![CDATA[45 < T < 75]]></c> seconds.</p>
+ <p>Notice that <em>all</em> communicating nodes are to have the
+ <em>same</em> <c>TickTime</c> value specified, as it determines both the
+ frequency of outgoing ticks and the expected frequency of incominging
+ ticks.</p>
+ <p>Normally, a terminating node is detected immediately by the transport
+ protocol (like TCP/IP).</p>
</item>
<tag><c>shutdown_timeout = integer() | infinity</c></tag>
<item>
diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml
index f1830a8224..2bcf137299 100644
--- a/lib/kernel/doc/src/logger.xml
+++ b/lib/kernel/doc/src/logger.xml
@@ -527,7 +527,7 @@ start(_, []) ->
Error -> Error
end.</code>
<p>This reads the <c>logger</c> configuration parameter from
- the <c>my_all</c> application and starts the configured
+ the <c>my_app</c> application and starts the configured
handlers. The contents of the configuration use the same
rules as the
<seealso marker="logger_chapter#handler-configuration">logger handler configuration</seealso>.
@@ -696,6 +696,17 @@ start(_, []) ->
</func>
<func>
+ <name name="set_application_level" arity="2"/>
+ <fsummary>Set the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Set the log level for all the modules of the specified application.</p>
+ <p>This function is a convenience function that calls
+ <seealso marker="#set_module_level/2">logger:set_module_level/2</seealso>
+ for each module associated with an application.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="set_handler_config" arity="2"/>
<fsummary>Set configuration data for the specified handler.</fsummary>
<desc>
@@ -737,6 +748,14 @@ start(_, []) ->
exists, its associated value will be changed
to the given value. If it does not exist, it will
be added.</p>
+ <p>If the value is incomplete, which for example can be the
+ case for the <c>config</c> key, it is up to the handler
+ implementation how the unspecified parts are set. For all
+ handlers in the Kernel application, unspecified data for
+ the <c>config</c> key is set to default values. To update
+ only specified data, and keep the existing configuration for
+ the rest, use <seealso marker="#update_handler_config-3">
+ <c>update_handler_config/3</c></seealso>.</p>
<p>See the definition of
the <seealso marker="#type-handler_config">
<c>handler_config()</c></seealso> type for more
@@ -782,8 +801,7 @@ start(_, []) ->
<name name="set_module_level" arity="2"/>
<fsummary>Set the log level for the specified modules.</fsummary>
<desc>
- <p>Set the log level for the
- specified modules.</p>
+ <p>Set the log level for the specified modules.</p>
<p>The log level for a module overrides the primary log level
of Logger for log events originating from the module in
question. Notice, however, that it does not override the
@@ -839,6 +857,17 @@ start(_, []) ->
</func>
<func>
+ <name name="unset_application_level" arity="1"/>
+ <fsummary>Unset the log level for all modules in the specified application.</fsummary>
+ <desc>
+ <p>Unset the log level for all the modules of the specified application.</p>
+ <p>This function is a convinience function that calls
+ <seealso marker="#unset_module_level/1">logger:unset_module_level/2</seealso>
+ for each module associated with an application.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="unset_module_level" arity="0"/>
<fsummary>Remove module specific log settings for all modules.</fsummary>
<desc>
@@ -912,6 +941,42 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)).
</func>
<func>
+ <name name="update_handler_config" arity="3" clause_i="1"/>
+ <name name="update_handler_config" arity="3" clause_i="2"/>
+ <name name="update_handler_config" arity="3" clause_i="3"/>
+ <name name="update_handler_config" arity="3" clause_i="4"/>
+ <name name="update_handler_config" arity="3" clause_i="5"/>
+ <fsummary>Add or update configuration data for the specified
+ handler.</fsummary>
+ <type variable="HandlerId"/>
+ <type variable="Level" name_i="1"/>
+ <type variable="FilterDefault" name_i="2"/>
+ <type variable="Filters" name_i="3"/>
+ <type variable="Formatter" name_i="4"/>
+ <type variable="Config" name_i="5"/>
+ <type variable="Return"/>
+ <desc>
+ <p>Add or update configuration data for the specified
+ handler. If the given <c><anno>Key</anno></c> already
+ exists, its associated value will be changed
+ to the given value. If it does not exist, it will
+ be added.</p>
+ <p>If the value is incomplete, which for example can be the
+ case for the <c>config</c> key, it is up to the handler
+ implementation how the unspecified parts are set. For all
+ handlers in the Kernel application, unspecified data for
+ the <c>config</c> key is not changed. To reset unspecified
+ data to default values,
+ use <seealso marker="#set_handler_config-3">
+ <c>set_handler_config/3</c></seealso>.</p>
+ <p>See the definition of
+ the <seealso marker="#type-handler_config">
+ <c>handler_config()</c></seealso> type for more
+ information about the different parameters.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="update_primary_config" arity="1"/>
<fsummary>Update primary configuration data for Logger.</fsummary>
<desc>
@@ -1020,10 +1085,11 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
</func>
<func>
- <name>HModule:changing_config(Config1, Config2) -> {ok, Config3} | {error, Reason}</name>
+ <name>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name>
<fsummary>The configuration for this handler is about to change.</fsummary>
<type>
- <v>Config1 = Config2 = Config3 =
+ <v>SetOrUpdate = set | update</v>
+ <v>OldConfig = NewConfig = Config =
<seealso marker="#type-handler_config">handler_config()</seealso></v>
<v>Reason = term()</v>
</type>
@@ -1032,18 +1098,51 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
<p>The function is called on a temporary process when the
configuration for a handler is about to change. The purpose
is to verify and act on the new configuration.</p>
- <p><c>Config1</c> is the existing configuration
- and <c>Config2</c> is the new configuration.</p>
+ <p><c>OldConfig</c> is the existing configuration
+ and <c>NewConfig</c> is the new configuration.</p>
<p>The handler identity is associated with the <c>id</c> key
- in <c>Config1</c>.</p>
+ in <c>OldConfig</c>.</p>
+ <p><c>SetOrUpdate</c> has the value <c>set</c> if the
+ configuration change originates from a call to
+ <seealso marker="#set_handler_config-2">
+ <c>set_handler_config/2,3</c></seealso>, and <c>update</c>
+ if it originates from <seealso marker="#update_handler_config-2">
+ <c>update_handler_config/2,3</c></seealso>. The handler can
+ use this parameteter to decide how to update the value of
+ the <c>config</c> field, that is, the handler specific
+ configuration data. Typically, if <c>SetOrUpdate</c>
+ equals <c>set</c>, values that are not specified must be
+ given their default values. If <c>SetOrUpdate</c>
+ equals <c>update</c>, the values found in <c>OldConfig</c>
+ must be used instead.</p>
<p>If everything succeeds, the callback function must return a
- possibly adjusted configuration in <c>{ok,Config3}</c>.</p>
+ possibly adjusted configuration in <c>{ok,Config}</c>.</p>
<p>If the configuration is faulty, the callback function must
return <c>{error,Reason}</c>.</p>
</desc>
</func>
<func>
+ <name>HModule:filter_config(Config) -> FilteredConfig</name>
+ <fsummary>Remove internal data from configuration.</fsummary>
+ <type>
+ <v>Config = FilteredConfig =
+ <seealso marker="#type-handler_config">handler_config()</seealso></v>
+ </type>
+ <desc>
+ <p>This callback function is optional.</p>
+ <p>The function is called when one of the Logger API functions
+ for fetching the handler configuration is called, for
+ example
+ <seealso marker="#get_handler_config-1">
+ <c>logger:get_handler_config/1</c></seealso>.</p>
+ <p>It allows the handler to remove internal data fields from
+ its configuration data before it is returned to the
+ caller.</p>
+ </desc>
+ </func>
+
+ <func>
<name>HModule:log(LogEvent, Config) -> void()</name>
<fsummary>Log the given log event.</fsummary>
<type>
@@ -1115,7 +1214,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)).
<item><seealso marker="logger#set_handler_config-2">
<c>logger:set_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_handler_config-2">
- <c>logger:updata_handler_config/2</c></seealso></item>
+ <c>logger:updata_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_formatter_config-2">
<c>logger:update_formatter_config/2</c></seealso></item>
</list>
diff --git a/lib/kernel/doc/src/logger_chapter.xml b/lib/kernel/doc/src/logger_chapter.xml
index 30172f6ca6..8fc52ce0a9 100644
--- a/lib/kernel/doc/src/logger_chapter.xml
+++ b/lib/kernel/doc/src/logger_chapter.xml
@@ -208,11 +208,13 @@
coversion to a string:</p>
<pre>fun((<seealso marker="logger#type-report"><c>logger:report()</c></seealso>,<seealso marker="logger#type-report_cb_config"><c>logger:report_cb_config()</c></seealso>) -> <seealso marker="stdlib:unicode#type-chardata"><c>unicode:chardata()</c></seealso>)
</pre>
- <p>The fun must obey the <c>encoding</c>, <c>depth</c>
- and <c>chars_limit</c> parameters provided in the second
- argument, as the formatter can not do anything useful of these
- parameters with the returned string. This variant is used when
- the formatting of the report depends on the size and encoding
+ <p>The fun must obey the <c>depth</c> and <c>chars_limit</c>
+ parameters provided in the second argument, as the formatter
+ cannot do anything useful of these parameters with the
+ returned string. The extra data also contains a field named
+ <c>single_line</c>, indicating if the printed log message may
+ contain line breaks or not. This variant is used when the
+ formatting of the report depends on the size or single line
parameters.</p>
<p>Example, format string and arguments:</p>
<code>logger:error("The file does not exist: ~ts",[Filename])</code>
@@ -382,8 +384,8 @@ logger:debug(#{got => connection_request, id => Id, state => State},
<p>In addition to the mandatory callback function <c>log/2</c>, a
handler module can export the optional callback
- functions <c>adding_handler/1</c>, <c>changing_config/2</c>
- and <c>removing_handler/1</c>. See
+ functions <c>adding_handler/1</c>, <c>changing_config/3</c>,
+ <c>filter_config/1</c>, and <c>removing_handler/1</c>. See
section <seealso marker="logger#handler_callback_functions">Handler
Callback Functions</seealso> in the logger(3) manual page for
more information about these function.</p>
@@ -507,7 +509,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},
<c>logger_level</c></seealso>. It is changed during
runtime with <seealso marker="logger#set_primary_config-2">
<c>logger:set_primary_config(level,Level)</c></seealso>.</p>
- <p>Defaults to <c>info</c>.</p>
+ <p>Defaults to <c>notice</c>.</p>
</item>
<tag><c>filters = [{FilterId,Filter}]</c></tag>
<item>
@@ -553,7 +555,7 @@ logger:debug(#{got => connection_request, id => Id, state => State},
<item><seealso marker="logger#set_handler_config-2">
<c>set_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#update_handler_config-2">
- <c>update_handler_config/2</c></seealso></item>
+ <c>update_handler_config/2,3</c></seealso></item>
<item><seealso marker="logger#add_handler_filter-3">
<c>add_handler_filter/3</c></seealso></item>
<item><seealso marker="logger#remove_handler_filter-2">
@@ -702,9 +704,13 @@ logger:debug(#{got => connection_request, id => Id, state => State},
<item>
<p>If <c>HandlerId</c> is <c>default</c>, then this entry
modifies the default handler, equivalent to calling</p>
- <pre><seealso marker="logger#set_handler_config-2">
- logger:set_handler_config(default, Module, HandlerConfig)
- </seealso></pre>
+ <pre><seealso marker="logger#remove_handler-1">
+ logger:remove_handler(default)
+ </seealso></pre>
+ <p>followed by</p>
+ <pre><seealso marker="logger#add_handler-3">
+ logger:add_handler(default, Module, HandlerConfig)
+ </seealso></pre>
<p>For all other values of <c>HandlerId</c>, this entry
adds a new handler, equivalent to calling</p>
<pre><seealso marker="logger:add_handler/3">
@@ -1022,7 +1028,8 @@ ok</pre>
<list>
<item><c>adding_handler(Config)</c></item>
<item><c>removing_handler(Config)</c></item>
- <item><c>changing_config(OldConfig, NewConfig)</c></item>
+ <item><c>changing_config(SetOrUpdate, OldConfig, NewConfig)</c></item>
+ <item><c>filter_config(Config)</c></item>
</list>
<p>When a handler is added, by for example a call
to <seealso marker="logger#add_handler-3">
@@ -1041,11 +1048,18 @@ ok</pre>
<p>When <seealso marker="logger#set_handler_config-2">
<c>logger:set_handler_config/2,3</c></seealso>
or <seealso marker="logger#update_handler_config/2">
- <c>logger:update_handler_config/2</c></seealso> is called,
+ <c>logger:update_handler_config/2,3</c></seealso> is called,
Logger
- calls <c>HModule:changing_config(OldConfig, NewConfig)</c>. If
+ calls <c>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig)</c>. If
this function returns <c>{ok,NewConfig1}</c>, Logger
writes <c>NewConfig1</c> to the configuration database.</p>
+ <p>When <seealso marker="logger#get_config-0">
+ <c>logger:get_config/0</c></seealso> or
+ <seealso marker="logger#get_handler_config-0">
+ <c>logger:get_handler_config/0,1</c></seealso> is called,
+ Logger calls <c>HModule:filter_config(Config)</c>. This function
+ must return the handler configuration where internal data is
+ removed.</p>
<p>A simple handler that prints to the terminal can be implemented
as follows:</p>
diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml
index dfe2ab3275..d9b941a0a9 100644
--- a/lib/kernel/doc/src/logger_disk_log_h.xml
+++ b/lib/kernel/doc/src/logger_disk_log_h.xml
@@ -66,6 +66,10 @@
corresponds to the <c>name</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
+ <p>The value is set when the handler is added, and it can not
+ be changed in runtime.</p>
+ <p>Defaults to the same name as the handler identity, in the
+ current directory.</p>
</item>
<tag><c>type</c></tag>
<item>
@@ -73,6 +77,8 @@
corresponds to the <c>type</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
+ <p>The value is set when the handler is added, and it can not
+ be changed in runtime.</p>
<p>Defaults to <c>wrap</c>.</p>
</item>
<tag><c>max_no_files</c></tag>
@@ -82,6 +88,8 @@
corresponds to the <c>MaxNoFiles</c> element in the <c>size</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
+ <p>The value is set when the handler is added, and it can not
+ be changed in runtime.</p>
<p>Defaults to <c>10</c>.</p>
<p>The setting has no effect on a halt log.</p>
</item>
@@ -93,6 +101,8 @@
corresponds to the <c>MaxNoBytes</c> element in the <c>size</c> property in the
<seealso marker="disk_log#open-1"><c>dlog_option()</c></seealso>
datatype.</p>
+ <p>The value is set when the handler is added, and it can not
+ be changed in runtime.</p>
<p>Defaults to <c>1048576</c> bytes for a wrap log, and
<c>infinity</c> for a halt log.</p>
</item>
diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml
index 9226d19834..24772fd6c4 100644
--- a/lib/kernel/doc/src/logger_formatter.xml
+++ b/lib/kernel/doc/src/logger_formatter.xml
@@ -82,13 +82,6 @@
in STDLIB.</p>
<p>Defaults to <c>unlimited</c>.</p>
</item>
- <tag><c>encoding = </c><seealso marker="stdlib:unicode#type-encoding">
- <c>unicode:encoding()</c></seealso></tag>
- <item>
- <p>This parameter must reflect the encoding of the device
- that the handler prints to.</p>
- <p>Defaults to <c>utf8</c></p>
- </item>
<tag><c>legacy_header = boolean()</c></tag>
<item>
<p>If set to <c>true</c> a header field is added to
@@ -130,10 +123,16 @@
</item>
<tag><c>single_line = boolean()</c></tag>
<item>
- <p>If set to <c>true</c>, all newlines in the message are
- replaced with <c>", "</c>, and white spaces following
- directly after newlines are removed. Notice that newlines
- added by the <c>template</c> parameter are not replaced.</p>
+ <p>If set to <c>true</c>, each log event is printed as a
+ single line. To achieve this, <c>logger_formatter</c>
+ sets the field width to <c>0</c> for all <c>~p</c>
+ and <c>~P</c> control sequences in the format a string
+ (see <seealso marker="stdlib:io#format-2">
+ <c>io:format/2</c></seealso>), and replaces all
+ newlines in the message with <c>", "</c>. White spaces
+ following directly after newlines are removed. Notice
+ that newlines added by the <c>template</c> parameter are
+ not replaced.</p>
<p>Defaults to <c>true</c>.</p>
</item>
<tag><marker id="template"/>
diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml
index b526ed037d..e156f5719b 100644
--- a/lib/kernel/doc/src/logger_std_h.xml
+++ b/lib/kernel/doc/src/logger_std_h.xml
@@ -59,13 +59,24 @@
<item>
<p>This has the value <c>standard_io</c>, <c>standard_error</c>,
<c>{file,LogFileName}</c>, or <c>{file,LogFileName,LogFileOpts}</c>.</p>
- <p> Defaults to <c>standard_io</c>.</p>
- <p>It is recommended not to specify <c>LogFileOpts</c> unless absolutely
- necessary. The default options used by the handler to open a file for logging are
- <c>raw</c>, <c>append</c>, and <c>delayed_write</c>. Notice that the standard
- handler does not have support for circular logging. Use the disk_log handler,
- <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>,
- for this.</p>
+ <p>If <c>LogFileOpts</c> is specified, it replaces the default
+ list of options used when opening the log file. The default
+ list is <c>[raw,append,delayed_write]</c>. One reason to do
+ so can be to change <c>append</c> to, for
+ example, <c>write</c>, ensuring that the old log is
+ truncated when a node is restarted. See the reference manual
+ for <seealso marker="file#open-2"><c>file:open/2</c></seealso>
+ for more information about file options.</p>
+ <p>Log files are always UTF-8 encoded. The encoding can not be
+ changed by setting the option <c>{encoding,Encoding}</c>
+ in <c>LogFileOpts</c>.</p>
+ <p>Notice that the standard handler does not have support for
+ circular logging. Use the disk_log handler,
+ <seealso marker="logger_disk_log_h"><c>logger_disk_log_h</c></seealso>,
+ for this.</p>
+ <p>The value is set when the handler is added, and it can not
+ be changed in runtime.</p>
+ <p>Defaults to <c>standard_io</c>.</p>
</item>
<tag><c>filesync_repeat_interval</c></tag>
<item>
@@ -73,12 +84,12 @@
a file sync operation to write buffered data to disk. The handler attempts
the operation repeatedly, but only performs a new sync if something has
actually been logged.</p>
- <p>Defaults to <c>5000</c> milliseconds.</p>
<p>If <c>no_repeat</c> is set as value, the repeated file sync operation
is disabled, and it is the operating system settings that determine
how quickly or slowly data is written to disk. The user can also call
the <seealso marker="logger_std_h#filesync-1"><c>filesync/1</c></seealso>
function to perform a file sync.</p>
+ <p>Defaults to <c>5000</c> milliseconds.</p>
</item>
</taglist>
<p>Other configuration parameters exist, to be used for customizing
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index d3bd7365e2..bfbe7a6470 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 6e88e98c6d..8188ede6a2 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -31,6 +31,128 @@
</header>
<p>This document describes the changes made to the Kernel application.</p>
+<section><title>Kernel 6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The values <c>all</c> and <c>none</c> are documented as
+ valid value for the Kernel configuration parameter
+ <c>logger_level</c>, but would cause a crash during node
+ start. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15143</p>
+ </item>
+ <item>
+ <p>
+ Fix some potential buggy behavior in how ticks are sent
+ on inter node distribution connections. Tick is now sent
+ to c-node even if there are unsent buffered data, as
+ c-nodes need ticks in order to send reply ticks. The
+ amount of sent data was also calculated wrongly when
+ ticks were suppressed due to unsent buffered data.</p>
+ <p>
+ Own Id: OTP-15162 Aux Id: ERIERL-191 </p>
+ </item>
+ <item>
+ <p>
+ Non semantic change in dist_util.erl to silence dialyzer
+ warning.</p>
+ <p>
+ Own Id: OTP-15170</p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>net_kernel:connect_node(node())</c> to return
+ <c>true</c> (and do nothing) as it always has before
+ OTP-21.0. Also documented this successful "self connect"
+ as the expected behavior.</p>
+ <p>
+ Own Id: OTP-15182 Aux Id: ERL-643 </p>
+ </item>
+ <item>
+ <p>
+ The single_line option on logger_formatter would in some
+ cases add an unwanted comma after the association arrows
+ in a map. This is now corrected.</p>
+ <p>
+ Own Id: OTP-15228</p>
+ </item>
+ <item>
+ <p>
+ Improved robustness of distribution connection setup. In
+ OTP-21.0 a truly asynchronous connection setup was
+ introduced. This is further improvement on that work to
+ make the emulator more robust and also be able to recover
+ in cases when involved Erlang processes misbehave.</p>
+ <p>
+ Own Id: OTP-15297 Aux Id: OTP-15279, OTP-15280 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ A new macro, <c>?LOG(Level,...)</c>, is added. This is
+ equivalent to the existing <c>?LOG_&lt;LEVEL&gt;(...)</c>
+ macros.</p>
+ <p>
+ A new variant of Logger report callback is added, which
+ takes an extra argument containing options for size
+ limiting and line breaks. Module <c>proc_lib</c> in
+ <c>STDLIB</c> uses this for crash reports.</p>
+ <p>
+ Logger configuration is now checked a bit more for
+ errors.</p>
+ <p>
+ Own Id: OTP-15132</p>
+ </item>
+ <item>
+ <p>
+ The socket options <c>recvtos</c>, <c>recvttl</c>,
+ <c>recvtclass</c> and <c>pktoptions</c> have been
+ implemented in the socket modules. See the documentation
+ for the <c>gen_tcp</c>, <c>gen_udp</c> and <c>inet</c>
+ modules. Note that support for these in the runtime
+ system is platform dependent. Especially for
+ <c>pktoptions</c> which is very Linux specific and
+ obsoleted by the RFCs that defined it.</p>
+ <p>
+ Own Id: OTP-15145 Aux Id: ERIERL-187 </p>
+ </item>
+ <item>
+ <p>
+ Add <c>logger:set_application_level/2</c> for setting the
+ logger level of all modules in one application.</p>
+ <p>
+ Own Id: OTP-15146</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Kernel 6.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>net_kernel</c> that could cause an
+ emulator crash if certain connection attempts failed. Bug
+ exists since kernel-6.0 (OTP-21.0).</p>
+ <p>
+ Own Id: OTP-15280 Aux Id: ERIERL-226, OTP-15279 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 6.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -314,6 +436,22 @@
</section>
+<section><title>Kernel 5.4.3.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Non semantic change in dist_util.erl to silence dialyzer
+ warning.</p>
+ <p>
+ Own Id: OTP-15170</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Kernel 5.4.3.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl
index ad8c937882..e324be5290 100644
--- a/lib/kernel/src/error_logger.erl
+++ b/lib/kernel/src/error_logger.erl
@@ -147,14 +147,27 @@ do_log(Level,{report,Msg},#{?MODULE:=#{tag:=Tag}}=Meta) ->
_ ->
%% From logger call which added error_logger data to
%% obtain backwards compatibility with error_logger:*_msg/1,2
- RCBFun=maps:get(report_cb,Meta,fun logger:format_report/1),
- try RCBFun(Msg) of
- {F,A} when is_list(F), is_list(A) ->
- {F,A};
- Other ->
- {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
- catch C:R ->
- {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
+ case maps:get(report_cb,Meta,fun logger:format_report/1) of
+ RCBFun when is_function(RCBFun,1) ->
+ try RCBFun(Msg) of
+ {F,A} when is_list(F), is_list(A) ->
+ {F,A};
+ Other ->
+ {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
+ catch C:R ->
+ {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
+ end;
+ RCBFun when is_function(RCBFun,2) ->
+ try RCBFun(Msg,#{depth=>get_format_depth(),
+ chars_limit=>unlimited,
+ single_line=>false}) of
+ Chardata when ?IS_STRING(Chardata) ->
+ {"~ts",[Chardata]};
+ Other ->
+ {"REPORT_CB ERROR: ~tp; Returned: ~tp",[Msg,Other]}
+ catch C:R ->
+ {"REPORT_CB CRASH: ~tp; Reason: ~tp",[Msg,{C,R}]}
+ end
end
end,
notify(Level,Tag,Format,Args,Meta);
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index bf795ee9c6..d893d44079 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -66,7 +66,12 @@
{sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
{sctp_status, #sctp_status{}} |
{sndbuf, non_neg_integer()} |
- {tos, non_neg_integer()}.
+ {tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()}.
-type option_name() ::
active |
buffer |
@@ -97,7 +102,12 @@
sctp_set_peer_primary_addr |
sctp_status |
sndbuf |
- tos.
+ tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl.
-type sctp_socket() :: port().
-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]).
@@ -365,7 +375,7 @@ send(S, AssocChange, Stream, Data) ->
Socket :: sctp_socket(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
@@ -382,7 +392,7 @@ recv(S) ->
Timeout :: timeout(),
FromIP :: inet:ip_address(),
FromPort :: inet:port_number(),
- AncData :: [#sctp_sndrcvinfo{}],
+ AncData :: [#sctp_sndrcvinfo{} | inet:ancillary_data()],
Data :: binary() | string() | #sctp_sndrcvinfo{}
| #sctp_assoc_change{} | #sctp_paddr_change{}
| #sctp_adaptation_event{},
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index c61411e814..7f7833ec23 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -62,7 +62,14 @@
{show_econnreset, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
+-type pktoptions_value() ::
+ {pktoptions, inet:ancillary_data()}.
-type option_name() ::
active |
buffer |
@@ -81,6 +88,7 @@
nodelay |
packet |
packet_size |
+ pktoptions |
priority |
{raw,
Protocol :: non_neg_integer(),
@@ -94,6 +102,12 @@
show_econnreset |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type connect_option() ::
{ip, inet:socket_address()} |
@@ -119,7 +133,7 @@
-type socket() :: port().
-export_type([option/0, option_name/0, connect_option/0, listen_option/0,
- socket/0]).
+ socket/0, pktoptions_value/0]).
%%
%% Connect a socket
diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl
index 44eef9f3c5..d6e8652e77 100644
--- a/lib/kernel/src/gen_udp.erl
+++ b/lib/kernel/src/gen_udp.erl
@@ -51,6 +51,11 @@
{reuseaddr, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
+ {tclass, non_neg_integer()} |
+ {ttl, non_neg_integer()} |
+ {recvtos, boolean()} |
+ {recvtclass, boolean()} |
+ {recvttl, boolean()} |
{ipv6_v6only, boolean()}.
-type option_name() ::
active |
@@ -76,6 +81,12 @@
reuseaddr |
sndbuf |
tos |
+ tclass |
+ ttl |
+ recvtos |
+ recvtclass |
+ recvttl |
+ pktoptions |
ipv6_v6only.
-type socket() :: port().
@@ -147,11 +158,13 @@ send(S, Packet) when is_port(S) ->
end.
-spec recv(Socket, Length) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
@@ -164,12 +177,14 @@ recv(S,Len) when is_port(S), is_integer(Len) ->
end.
-spec recv(Socket, Length, Timeout) ->
- {ok, {Address, Port, Packet}} | {error, Reason} when
+ {ok, RecvData} | {error, Reason} when
Socket :: socket(),
Length :: non_neg_integer(),
Timeout :: timeout(),
+ RecvData :: {Address, Port, Packet} | {Address, Port, AncData, Packet},
Address :: inet:ip_address() | inet:returned_non_ip_address(),
Port :: inet:port_number(),
+ AncData :: inet:ancillary_data(),
Packet :: string() | binary(),
Reason :: not_owner | inet:posix().
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 73c53b9011..9f22eb6aaa 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -76,7 +76,7 @@
-export_type([address_family/0, socket_protocol/0, hostent/0, hostname/0, ip4_address/0,
ip6_address/0, ip_address/0, port_number/0,
local_address/0, socket_address/0, returned_non_ip_address/0,
- socket_setopt/0, socket_getopt/0,
+ socket_setopt/0, socket_getopt/0, ancillary_data/0,
posix/0, socket/0, stat_option/0]).
%% imports
-import(lists, [append/1, duplicate/2, filter/2, foldl/3]).
@@ -154,6 +154,15 @@
'running' | 'multicast' | 'loopback']} |
{'hwaddr', ether_address()}.
+-type getifaddrs_ifopts() ::
+ [Ifopt :: {flags, Flags :: [up | broadcast | loopback |
+ pointtopoint | running | multicast]} |
+ {addr, Addr :: ip_address()} |
+ {netmask, Netmask :: ip_address()} |
+ {broadaddr, Broadaddr :: ip_address()} |
+ {dstaddr, Dstaddr :: ip_address()} |
+ {hwaddr, Hwaddr :: [byte()]}].
+
-type address_family() :: 'inet' | 'inet6' | 'local'.
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
@@ -163,6 +172,9 @@
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
+-type ancillary_data() ::
+ [ {'tos', byte()} | {'tclass', byte()} | {'ttl', byte()} ].
+
%%% ---------------------------------
-spec get_rc() -> [{Par :: atom(), Val :: any()} |
@@ -302,7 +314,7 @@ setopts(Socket, Opts) ->
{'ok', OptionValues} | {'error', posix()} when
Socket :: socket(),
Options :: [socket_getopt()],
- OptionValues :: [socket_setopt()].
+ OptionValues :: [socket_setopt() | gen_tcp:pktoptions_value()].
getopts(Socket, Opts) ->
case prim_inet:getopts(Socket, Opts) of
@@ -318,32 +330,32 @@ getopts(Socket, Opts) ->
Other
end.
--spec getifaddrs(Socket :: socket()) ->
- {'ok', [string()]} | {'error', posix()}.
-
+-spec getifaddrs(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
+ {'ok', [{Ifname :: string(),
+ Ifopts :: getifaddrs_ifopts()}]}
+ | {'error', posix()}.
+getifaddrs(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> prim_inet:getifaddrs(S) end, Opts);
getifaddrs(Socket) ->
prim_inet:getifaddrs(Socket).
--spec getifaddrs() -> {ok, Iflist} | {error, posix()} when
- Iflist :: [{Ifname,[Ifopt]}],
- Ifname :: string(),
- Ifopt :: {flags,[Flag]} | {addr,Addr} | {netmask,Netmask}
- | {broadaddr,Broadaddr} | {dstaddr,Dstaddr}
- | {hwaddr,Hwaddr},
- Flag :: up | broadcast | loopback | pointtopoint
- | running | multicast,
- Addr :: ip_address(),
- Netmask :: ip_address(),
- Broadaddr :: ip_address(),
- Dstaddr :: ip_address(),
- Hwaddr :: [byte()].
-
+-spec getifaddrs() ->
+ {'ok', [{Ifname :: string(),
+ Ifopts :: getifaddrs_ifopts()}]}
+ | {'error', posix()}.
getifaddrs() ->
withsocket(fun(S) -> prim_inet:getifaddrs(S) end).
--spec getiflist(Socket :: socket()) ->
- {'ok', [string()]} | {'error', posix()}.
+-spec getiflist(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
+ {'ok', [string()]} | {'error', posix()}.
+
+getiflist(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> prim_inet:getiflist(S) end, Opts);
getiflist(Socket) ->
prim_inet:getiflist(Socket).
@@ -360,11 +372,19 @@ getiflist() ->
ifget(Socket, Name, Opts) ->
prim_inet:ifget(Socket, Name, Opts).
--spec ifget(Name :: string() | atom(), Opts :: [if_getopt()]) ->
+-spec ifget(
+ Name :: string() | atom(),
+ Opts :: [if_getopt() |
+ {netns, Namespace :: file:filename_all()}]) ->
{'ok', [if_getopt_result()]} | {'error', posix()}.
ifget(Name, Opts) ->
- withsocket(fun(S) -> prim_inet:ifget(S, Name, Opts) end).
+ {NSOpts,IFOpts} =
+ lists:partition(
+ fun ({netns,_}) -> true;
+ (_) -> false
+ end, Opts),
+ withsocket(fun(S) -> prim_inet:ifget(S, Name, IFOpts) end, NSOpts).
-spec ifset(Socket :: socket(),
Name :: string() | atom(),
@@ -374,11 +394,19 @@ ifget(Name, Opts) ->
ifset(Socket, Name, Opts) ->
prim_inet:ifset(Socket, Name, Opts).
--spec ifset(Name :: string() | atom(), Opts :: [if_setopt()]) ->
+-spec ifset(
+ Name :: string() | atom(),
+ Opts :: [if_setopt() |
+ {netns, Namespace :: file:filename_all()}]) ->
'ok' | {'error', posix()}.
ifset(Name, Opts) ->
- withsocket(fun(S) -> prim_inet:ifset(S, Name, Opts) end).
+ {NSOpts,IFOpts} =
+ lists:partition(
+ fun ({netns,_}) -> true;
+ (_) -> false
+ end, Opts),
+ withsocket(fun(S) -> prim_inet:ifset(S, Name, IFOpts) end, NSOpts).
-spec getif() ->
{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
@@ -388,10 +416,14 @@ getif() ->
withsocket(fun(S) -> getif(S) end).
%% backwards compatible getif
--spec getif(Socket :: socket()) ->
+-spec getif(
+ [Option :: {netns, Namespace :: file:filename_all()}]
+ | socket()) ->
{'ok', [{ip_address(), ip_address() | 'undefined', ip_address()}]} |
{'error', posix()}.
+getif(Opts) when is_list(Opts) ->
+ withsocket(fun(S) -> getif(S) end, Opts);
getif(Socket) ->
case prim_inet:getiflist(Socket) of
{ok, IfList} ->
@@ -412,7 +444,10 @@ getif(Socket) ->
end.
withsocket(Fun) ->
- case inet_udp:open(0,[]) of
+ withsocket(Fun, []).
+%%
+withsocket(Fun, Opts) ->
+ case inet_udp:open(0, Opts) of
{ok,Socket} ->
Res = Fun(Socket),
inet_udp:close(Socket),
@@ -722,6 +757,7 @@ stats() ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
connect_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, packet_size, buffer, mode, deliver, line_delimiter,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
@@ -790,6 +826,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
listen_options() ->
[tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
+ recvtos, recvtclass, ttl, recvttl,
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
@@ -870,7 +907,7 @@ tcp_module_1(Opts, Address) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
udp_options() ->
[tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode,
- deliver, ipv6_v6only,
+ recvtos, recvtclass, ttl, recvttl, deliver, ipv6_v6only,
broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop,
add_membership, drop_membership, read_packets,raw,
high_msgq_watermark, low_msgq_watermark, bind_to_device].
@@ -940,8 +977,10 @@ udp_module(Opts) ->
% (*) passing of open FDs ("fdopen") is not supported.
sctp_options() ->
[ % The following are generic inet options supported for SCTP sockets:
- mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf,
- recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
+ mode, active, buffer, tos, tclass, ttl,
+ priority, dontroute, reuseaddr, linger,
+ recvtos, recvtclass, recvttl,
+ sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark,
bind_to_device,
% Other options are SCTP-specific (though they may be similar to their
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index a0d5d3df70..347b8b9a1b 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -167,7 +167,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -175,13 +175,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tclass, recvtclass].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 9f76360b8b..e771461b65 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -98,7 +98,7 @@ init() ->
{win32,WinType} ->
win32_load_from_registry(WinType);
_ ->
- error("can not read win32 system registry~n", [])
+ error("cannot read win32 system registry~n", [])
end
end, CfgFiles),
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index f1f58bc872..6c98d2aab7 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -699,7 +699,7 @@ encode_labels(Bin, Comp0, Pos, [L|Ls]=Labels)
none ->
Comp = if Pos < (3 bsl 14) ->
%% Just in case - compression
- %% pointers can not reach further
+ %% pointers cannot reach further
gb_trees:insert(Labels, Pos, Comp0);
true -> Comp0
end,
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 357e27826c..f6525d7261 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -157,6 +157,12 @@
-define(INET_LOPT_LINE_DELIM, 40).
-define(INET_OPT_TCLASS, 41).
-define(INET_OPT_BIND_TO_DEVICE, 42).
+-define(INET_OPT_RECVTOS, 43).
+-define(INET_OPT_RECVTCLASS, 44).
+-define(INET_OPT_PKTOPTIONS, 45).
+-define(INET_OPT_TTL, 46).
+-define(INET_OPT_RECVTTL, 47).
+-define(TCP_OPT_NOPUSH, 48).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index dac6b3119d..f1e3116856 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -164,7 +164,7 @@ listen(Port, Opts) ->
%% Accept
%%
accept(L) ->
- case prim_inet:accept(L) of
+ case prim_inet:accept(L, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
@@ -172,13 +172,15 @@ accept(L) ->
end.
accept(L, Timeout) ->
- case prim_inet:accept(L, Timeout) of
+ case prim_inet:accept(L, Timeout, accept_family_opts()) of
{ok, S} ->
inet_db:register_socket(S, ?MODULE),
{ok,S};
Error -> Error
end.
+accept_family_opts() -> [tos, ttl, recvtos, recvttl].
+
%%
%% Create a port/socket from a file descriptor
%%
diff --git a/lib/kernel/src/inet_tcp_dist.erl b/lib/kernel/src/inet_tcp_dist.erl
index d1701afdaa..c37212b0f9 100644
--- a/lib/kernel/src/inet_tcp_dist.erl
+++ b/lib/kernel/src/inet_tcp_dist.erl
@@ -450,7 +450,7 @@ get_tcp_address(Driver, Socket) ->
get_address_resolver(EpmdModule) ->
case erlang:function_exported(EpmdModule, address_please, 3) of
true -> {EpmdModule, address_please};
- _ -> {inet, getaddr}
+ _ -> {erl_epmd, address_please}
end.
%% ------------------------------------------------------------
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index 4933eae76f..fe073621c8 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -146,6 +146,6 @@
{logger_sasl_compatible, false}
]},
{mod, {kernel, []}},
- {runtime_dependencies, ["erts-10.0", "stdlib-3.5", "sasl-3.0"]}
+ {runtime_dependencies, ["erts-10.1", "stdlib-3.5", "sasl-3.0"]}
]
}.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 305a1c788c..0c0435e051 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -20,9 +20,11 @@
%% Up from - max one major revision back
[{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0
{<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-21
+ {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
+ {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-21.1
%% Down to - max one major revision back
[{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0
{<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21
+ {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
+ {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21.1
}.
diff --git a/lib/kernel/src/logger.erl b/lib/kernel/src/logger.erl
index ffc90f4fc5..6762998d4f 100644
--- a/lib/kernel/src/logger.erl
+++ b/lib/kernel/src/logger.erl
@@ -39,10 +39,12 @@
remove_primary_filter/1, remove_handler_filter/2,
set_module_level/2,
unset_module_level/1, unset_module_level/0,
+ set_application_level/2, unset_application_level/1,
get_module_level/0, get_module_level/1,
set_primary_config/1, set_primary_config/2,
set_handler_config/2, set_handler_config/3,
- update_primary_config/1, update_handler_config/2,
+ update_primary_config/1,
+ update_handler_config/2, update_handler_config/3,
update_formatter_config/2, update_formatter_config/3,
get_primary_config/0, get_handler_config/1,
get_handler_config/0, get_handler_ids/0, get_config/0,
@@ -76,9 +78,9 @@
-type report() :: map() | [{atom(),term()}].
-type report_cb() :: fun((report()) -> {io:format(),[term()]}) |
fun((report(),report_cb_config()) -> unicode:chardata()).
--type report_cb_config() :: #{encoding := unicode:encoding(),
- depth := pos_integer() | unlimited,
- chars_limit := pos_integer() | unlimited}.
+-type report_cb_config() :: #{depth := pos_integer() | unlimited,
+ chars_limit := pos_integer() | unlimited,
+ single_line := boolean()}.
-type msg_fun() :: fun((term()) -> {io:format(),[term()]} |
report() |
unicode:chardata()).
@@ -115,6 +117,11 @@
-type config_handler() :: {handler, handler_id(), module(), handler_config()}.
+-type config_logger() :: [{handler,default,undefined} |
+ config_handler() |
+ {filters,log | stop,[{filter_id(),filter()}]} |
+ {module_level,level(),[module()]}].
+
-export_type([log_event/0,
level/0,
report/0,
@@ -417,6 +424,29 @@ set_handler_config(HandlerId,Config) ->
update_primary_config(Config) ->
logger_server:update_config(primary,Config).
+-spec update_handler_config(HandlerId,level,Level) -> Return when
+ HandlerId :: handler_id(),
+ Level :: level() | all | none,
+ Return :: ok | {error,term()};
+ (HandlerId,filter_default,FilterDefault) -> Return when
+ HandlerId :: handler_id(),
+ FilterDefault :: log | stop,
+ Return :: ok | {error,term()};
+ (HandlerId,filters,Filters) -> Return when
+ HandlerId :: handler_id(),
+ Filters :: [{filter_id(),filter()}],
+ Return :: ok | {error,term()};
+ (HandlerId,formatter,Formatter) -> Return when
+ HandlerId :: handler_id(),
+ Formatter :: {module(), formatter_config()},
+ Return :: ok | {error,term()};
+ (HandlerId,config,Config) -> Return when
+ HandlerId :: handler_id(),
+ Config :: term(),
+ Return :: ok | {error,term()}.
+update_handler_config(HandlerId,Key,Value) ->
+ logger_server:update_config(HandlerId,Key,Value).
+
-spec update_handler_config(HandlerId,Config) -> ok | {error,term()} when
HandlerId :: handler_id(),
Config :: handler_config().
@@ -434,8 +464,10 @@ get_primary_config() ->
Config :: handler_config().
get_handler_config(HandlerId) ->
case logger_config:get(?LOGGER_TABLE,HandlerId) of
- {ok,{_,Config}} ->
- {ok,Config};
+ {ok,#{module:=Module}=Config} ->
+ {ok,try Module:filter_config(Config)
+ catch _:_ -> Config
+ end};
Error ->
Error
end.
@@ -488,6 +520,27 @@ unset_module_level(Modules) ->
unset_module_level() ->
logger_server:unset_module_level().
+-spec set_application_level(Application,Level) -> ok | {error, not_loaded} when
+ Application :: atom(),
+ Level :: level() | all | none.
+set_application_level(App,Level) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ set_module_level(Modules, Level);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
+-spec unset_application_level(Application) -> ok | {error, not_loaded} when
+ Application :: atom().
+unset_application_level(App) ->
+ case application:get_key(App, modules) of
+ {ok, Modules} ->
+ unset_module_level(Modules);
+ undefined ->
+ {error, {not_loaded, App}}
+ end.
+
-spec get_module_level(Modules) -> [{Module,Level}] when
Modules :: [Module] | Module,
Module :: module(),
@@ -566,19 +619,21 @@ get_config() ->
%% tree is started.
internal_init_logger() ->
try
+ Env = get_logger_env(kernel),
+ check_logger_config(kernel,Env),
ok = logger:set_primary_config(level, get_logger_level()),
- ok = logger:set_primary_config(filter_default, get_primary_filter_default()),
+ ok = logger:set_primary_config(filter_default,
+ get_primary_filter_default(Env)),
[case logger:add_primary_filter(Id, Filter) of
ok -> ok;
{error, Reason} -> throw(Reason)
- end || {Id, Filter} <- get_primary_filters()],
+ end || {Id, Filter} <- get_primary_filters(Env)],
- _ = [[case logger:set_module_level(Module, Level) of
- ok -> ok;
- {error, Reason} -> throw(Reason)
- end || Module <- Modules]
- || {module_level, Level, Modules} <- get_logger_env()],
+ [case logger:set_module_level(Modules, Level) of
+ ok -> ok;
+ {error, Reason} -> throw(Reason)
+ end || {module_level, Level, Modules} <- Env],
case logger:set_handler_config(simple,filters,
get_default_handler_filters()) of
@@ -586,24 +641,24 @@ internal_init_logger() ->
{error,{not_found,simple}} -> ok
end,
- init_kernel_handlers()
+ init_kernel_handlers(Env)
catch throw:Reason ->
?LOG_ERROR("Invalid logger config: ~p", [Reason]),
{error, {bad_config, {kernel, Reason}}}
end.
--spec init_kernel_handlers() -> ok | {error,term()}.
+-spec init_kernel_handlers(config_logger()) -> ok | {error,term()}.
%% Setup the kernel environment variables to be correct
%% The actual handlers are started by a call to add_handlers.
-init_kernel_handlers() ->
+init_kernel_handlers(Env) ->
try
- case get_logger_type() of
+ case get_logger_type(Env) of
{ok,silent} ->
ok = logger:remove_handler(simple);
{ok,false} ->
ok;
{ok,Type} ->
- init_default_config(Type)
+ init_default_config(Type,Env)
end
catch throw:Reason ->
?LOG_ERROR("Invalid default handler config: ~p", [Reason]),
@@ -618,10 +673,13 @@ init_kernel_handlers() ->
%% and then starting the correct handlers. This is done after the
%% kernel supervisor tree has been started as it needs the logger_sup.
add_handlers(App) when is_atom(App) ->
- add_handlers(application:get_env(App, logger, []));
+ add_handlers(App,get_logger_env(App));
add_handlers(HandlerConfig) ->
+ add_handlers(application:get_application(),HandlerConfig).
+
+add_handlers(App,HandlerConfig) ->
try
- check_logger_config(HandlerConfig),
+ check_logger_config(App,HandlerConfig),
DefaultAdded =
lists:foldl(
fun({handler, default = Id, Module, Config}, _)
@@ -635,17 +693,22 @@ add_handlers(HandlerConfig) ->
({handler, Id, Module, Config}, Default) ->
setup_handler(Id, Module, Config),
Default orelse Id == default;
- (_, Default) -> Default
+ (_,Default) -> Default
end, false, HandlerConfig),
%% If a default handler was added we try to remove the simple_logger
%% If the simple logger exists it will replay its log events
%% to the handler(s) added in the fold above.
- _ = [case logger:remove_handler(simple) of
- ok -> ok;
- {error,{not_found,simple}} -> ok
- end || DefaultAdded],
+ [case logger:remove_handler(simple) of
+ ok -> ok;
+ {error,{not_found,simple}} -> ok
+ end || DefaultAdded],
ok
- catch throw:Reason ->
+ catch throw:Reason0 ->
+ Reason =
+ case App of
+ undefined -> Reason0;
+ _ -> {App,Reason0}
+ end,
?LOG_ERROR("Invalid logger handler config: ~p", [Reason]),
{error, {bad_config, {handler, Reason}}}
end.
@@ -656,26 +719,35 @@ setup_handler(Id, Module, Config) ->
{error, Reason} -> throw(Reason)
end.
-check_logger_config(_) ->
- ok.
-
--spec get_logger_type() -> {ok, standard_io | false | silent |
- {file, file:name_all()} |
- {file, file:name_all(), [file:mode()]}}.
-get_logger_type() ->
+check_logger_config(_,[]) ->
+ ok;
+check_logger_config(App,[{handler,_,_,_}|Env]) ->
+ check_logger_config(App,Env);
+check_logger_config(kernel,[{handler,default,undefined}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(kernel,[{filters,_,_}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(kernel,[{module_level,_,_}|Env]) ->
+ check_logger_config(kernel,Env);
+check_logger_config(_,Bad) ->
+ throw(Bad).
+
+-spec get_logger_type(config_logger()) ->
+ {ok, standard_io | false | silent |
+ {file, file:name_all()} |
+ {file, file:name_all(), [file:mode()]}}.
+get_logger_type(Env) ->
case application:get_env(kernel, error_logger) of
{ok, tty} ->
{ok, standard_io};
{ok, {file, File}} when is_list(File) ->
{ok, {file, File}};
- {ok, {file, File, Modes}} when is_list(File), is_list(Modes) ->
- {ok, {file, File, Modes}};
{ok, false} ->
{ok, false};
{ok, silent} ->
{ok, silent};
undefined ->
- case lists:member({handler,default,undefined}, get_logger_env()) of
+ case lists:member({handler,default,undefined}, Env) of
true ->
{ok, false};
false ->
@@ -693,56 +765,55 @@ get_logger_level() ->
throw({logger_level, Level})
end.
-get_primary_filter_default() ->
- case lists:keyfind(filters,1,get_logger_env()) of
+get_primary_filter_default(Env) ->
+ case lists:keyfind(filters,1,Env) of
{filters,Default,_} ->
Default;
false ->
log
end.
-get_primary_filters() ->
- lists:foldl(
- fun({filters, _, Filters}, _Acc) ->
- Filters;
- (_, Acc) ->
- Acc
- end, [], get_logger_env()).
+get_primary_filters(Env) ->
+ case [F || F={filters,_,_} <- Env] of
+ [{filters,_,Filters}] ->
+ case lists:all(fun({_,_}) -> true; (_) -> false end,Filters) of
+ true -> Filters;
+ false -> throw({invalid_filters,Filters})
+ end;
+ [] -> [];
+ _ -> throw({multiple_filters,Env})
+ end.
%% This function looks at the kernel logger environment
%% and updates it so that the correct logger is configured
-init_default_config(Type) when Type==standard_io;
- Type==standard_error;
- element(1,Type)==file ->
- Env = get_logger_env(),
+init_default_config(Type,Env) when Type==standard_io;
+ Type==standard_error;
+ element(1,Type)==file ->
DefaultFormatter = #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}},
DefaultConfig = DefaultFormatter#{config=>#{type=>Type}},
NewLoggerEnv =
case lists:keyfind(default, 2, Env) of
- {handler, default, Module, Config} ->
- lists:map(
- fun({handler, default, logger_std_h, _}) ->
- %% Only want to add the logger_std_h config
- %% if not configured by user AND the default
- %% handler is still the logger_std_h.
- {handler, default, Module, maps:merge(DefaultConfig,Config)};
- ({handler, default, logger_disk_log_h, _}) ->
- %% Add default formatter. The point of this
- %% is to get the expected formatter config
- %% for the default handler, since this
- %% differs from the default values that
- %% logger_formatter itself adds.
- {handler, default, logger_disk_log_h, maps:merge(DefaultFormatter,Config)};
- (Other) ->
- Other
- end, Env);
+ {handler, default, logger_std_h, Config} ->
+ %% Only want to add the logger_std_h config
+ %% if not configured by user AND the default
+ %% handler is still the logger_std_h.
+ lists:keyreplace(default, 2, Env,
+ {handler, default, logger_std_h,
+ maps:merge(DefaultConfig,Config)});
+ {handler, default, Module,Config} ->
+ %% Add default formatter. The point of this
+ %% is to get the expected formatter config
+ %% for the default handler, since this
+ %% differs from the default values that
+ %% logger_formatter itself adds.
+ lists:keyreplace(default, 2, Env,
+ {handler, default, Module,
+ maps:merge(DefaultFormatter,Config)});
_ ->
%% Nothing has been configured, use default
[{handler, default, logger_std_h, DefaultConfig} | Env]
end,
- application:set_env(kernel, logger, NewLoggerEnv, [{timeout,infinity}]);
-init_default_config(Type) ->
- throw({illegal_logger_type,Type}).
+ application:set_env(kernel, logger, NewLoggerEnv, [{timeout,infinity}]).
get_default_handler_filters() ->
case application:get_env(kernel, logger_sasl_compatible, false) of
@@ -752,8 +823,8 @@ get_default_handler_filters() ->
?DEFAULT_HANDLER_FILTERS([otp,sasl])
end.
-get_logger_env() ->
- application:get_env(kernel, logger, []).
+get_logger_env(App) ->
+ application:get_env(App, logger, []).
%%%-----------------------------------------------------------------
%%% Internal
diff --git a/lib/kernel/src/logger_backend.erl b/lib/kernel/src/logger_backend.erl
index 4d7bd6b2a0..432c671afd 100644
--- a/lib/kernel/src/logger_backend.erl
+++ b/lib/kernel/src/logger_backend.erl
@@ -41,7 +41,7 @@ log_allowed(Log, Tid) ->
call_handlers(#{level:=Level}=Log,[Id|Handlers],Tid) ->
case logger_config:get(Tid,Id,Level) of
- {ok,{Module,Config}} ->
+ {ok,#{module:=Module}=Config} ->
Filters = maps:get(filters,Config,[]),
case apply_filters(Id,Log,Filters,Config) of
stop ->
diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
index 55427dce5a..6bfe658552 100644
--- a/lib/kernel/src/logger_config.erl
+++ b/lib/kernel/src/logger_config.erl
@@ -22,8 +22,8 @@
-export([new/1,delete/2,
exist/2,
allow/2,allow/3,
- get/2, get/3, get/1,
- create/3, create/4, set/3,
+ get/2, get/3,
+ create/3, set/3,
set_module_level/3,unset_module_level/2,
get_module_level/1,cache_module_level/2,
level_to_int/1]).
@@ -64,27 +64,19 @@ get(Tid,What) ->
case ets:lookup(Tid,table_key(What)) of
[{_,_,Config}] ->
{ok,Config};
- [{_,_,Config,Module}] ->
- {ok,{Module,Config}};
[] ->
{error,{not_found,What}}
end.
get(Tid,What,Level) ->
- MS = [{{table_key(What),'$1','$2'}, % primary config
+ MS = [{{table_key(What),'$1','$2'},
[{'>=','$1',level_to_int(Level)}],
- ['$2']},
- {{table_key(What),'$1','$2','$3'}, % handler config
- [{'>=','$1',level_to_int(Level)}],
- [{{'$3','$2'}}]}],
+ ['$2']}],
case ets:select(Tid,MS) of
[] -> error;
[Data] -> {ok,Data}
end.
-create(Tid,What,Module,Config) ->
- LevelInt = level_to_int(maps:get(level,Config)),
- ets:insert(Tid,{table_key(What),LevelInt,Config,Module}).
create(Tid,What,Config) ->
LevelInt = level_to_int(maps:get(level,Config)),
ets:insert(Tid,{table_key(What),LevelInt,Config}).
@@ -129,13 +121,6 @@ cache_module_level(Tid,Module) ->
ets:insert_new(Tid,{Module,{GlobalLevelInt,cached}}),
ok.
-get(Tid) ->
- {ok,Primary} = get(Tid,primary),
- HMS = [{{table_key('$1'),'_','$2','$3'},[],[{{'$1','$3','$2'}}]}],
- Handlers = ets:select(Tid,HMS),
- Modules = get_module_level(Tid),
- {Primary,Handlers,Modules}.
-
level_to_int(none) -> ?LOG_NONE;
level_to_int(emergency) -> ?EMERGENCY;
level_to_int(alert) -> ?ALERT;
diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl
index e56531c3cb..2a81458ec8 100644
--- a/lib/kernel/src/logger_disk_log_h.erl
+++ b/lib/kernel/src/logger_disk_log_h.erl
@@ -33,7 +33,8 @@
terminate/2, code_change/3]).
%% logger callbacks
--export([log/2, adding_handler/1, removing_handler/1, changing_config/2]).
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
%% handler internal
-export([log_handler_info/4]).
@@ -114,9 +115,8 @@ reset(Name) ->
%%% Handler being added
adding_handler(#{id:=Name}=Config) ->
case check_config(adding, Config) of
- {ok, Config1} ->
+ {ok, #{config:=HConfig}=Config1} ->
%% create initial handler state by merging defaults with config
- HConfig = maps:get(config, Config1, #{}),
HState = maps:merge(get_init_state(), HConfig),
case logger_h_common:overload_levels_ok(HState) of
true ->
@@ -133,32 +133,40 @@ adding_handler(#{id:=Name}=Config) ->
%%%-----------------------------------------------------------------
%%% Updating handler config
-changing_config(OldConfig = #{id:=Name, config:=OldHConfig},
- NewConfig = #{id:=Name, config:=NewHConfig}) ->
- #{type:=Type, file:=File, max_no_files:=MaxFs,
- max_no_bytes:=MaxBytes} = OldHConfig,
- case NewHConfig of
- #{type:=Type, file:=File, max_no_files:=MaxFs,
- max_no_bytes:=MaxBytes} ->
- changing_config1(OldConfig, NewConfig);
- _ ->
- {error,{illegal_config_change,OldConfig,NewConfig}}
- end;
-changing_config(OldConfig, NewConfig) ->
- {error,{illegal_config_change,OldConfig,NewConfig}}.
+changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
+ WriteOnce = maps:with([type,file,max_no_files,max_no_bytes],OldHConfig),
+ ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig),
+ NewHConfig0 = maps:get(config, NewConfig, #{}),
+ Default =
+ case SetOrUpdate of
+ set ->
+ %% Do not reset write-once fields to defaults
+ maps:merge(get_default_config(),WriteOnce);
+ update ->
+ OldHConfig
+ end,
+
+ %% Allow (accidentially) included read-only fields - just overwrite them
+ NewHConfig = maps:merge(maps:merge(Default,NewHConfig0),ReadOnly),
+
+ %% But fail if write-once fields are changed
+ case maps:with([type,file,max_no_files,max_no_bytes],NewHConfig) of
+ WriteOnce ->
+ changing_config1(maps:get(handler_pid,OldHConfig),
+ OldConfig,
+ NewConfig#{config=>NewHConfig});
+ Other ->
+ {Old,New} = logger_server:diff_maps(WriteOnce,Other),
+ {error,{illegal_config_change,#{config=>Old},#{config=>New}}}
+ end.
-changing_config1(OldConfig=#{config:=OldHConfig}, NewConfig) ->
+changing_config1(HPid, OldConfig, NewConfig) ->
case check_config(changing, NewConfig) of
- {ok,NewConfig1 = #{config:=NewHConfig}} ->
- #{handler_pid:=HPid,
- mode_tab:=ModeTab} = OldHConfig,
- NewHConfig1 = NewHConfig#{handler_pid=>HPid,
- mode_tab=>ModeTab},
- NewConfig2 = NewConfig1#{config=>NewHConfig1},
- try gen_server:call(HPid, {change_config,OldConfig,NewConfig2},
+ Result = {ok,NewConfig1} ->
+ try gen_server:call(HPid, {change_config,OldConfig,NewConfig1},
?DEFAULT_CALL_TIMEOUT) of
- ok -> {ok,NewConfig2};
- HError -> HError
+ ok -> Result;
+ Error -> Error
catch
_:{timeout,_} -> {error,handler_busy}
end;
@@ -168,10 +176,12 @@ changing_config1(OldConfig=#{config:=OldHConfig}, NewConfig) ->
check_config(adding, #{id:=Name}=Config) ->
%% merge handler specific config data
- HConfig = merge_default_logopts(Name, maps:get(config, Config, #{})),
- case check_h_config(maps:to_list(HConfig)) of
+ HConfig1 = maps:get(config, Config, #{}),
+ HConfig2 = maps:merge(get_default_config(), HConfig1),
+ HConfig3 = merge_default_logopts(Name, HConfig2),
+ case check_h_config(maps:to_list(HConfig3)) of
ok ->
- {ok,Config#{config=>HConfig}};
+ {ok,Config#{config=>HConfig3}};
Error ->
Error
end;
@@ -225,7 +235,7 @@ removing_handler(#{id:=Name}) ->
%%%-----------------------------------------------------------------
%%% Log a string or report
--spec log(LogEvent, Config) -> ok | dropped when
+-spec log(LogEvent, Config) -> ok when
LogEvent :: logger:log_event(),
Config :: logger:handler_config().
@@ -238,6 +248,11 @@ log(LogEvent, Config = #{id := Name,
Bin = logger_h_common:log_to_binary(LogEvent, Config),
logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(#{config:=HConfig}=Config) ->
+ Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}.
+
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
@@ -294,7 +309,7 @@ init([Name,
%% initial start
ok
end,
- enter_loop(Config1, State1)
+ gen_server:enter_loop(?MODULE, [], State1)
catch
_:Error ->
unregister(RegName),
@@ -307,9 +322,6 @@ init([Name,
proc_lib:init_ack(Error)
end.
-enter_loop(_Config,State) ->
- gen_server:enter_loop(?MODULE,[],State).
-
%% This is the synchronous log event.
handle_call({log, Bin}, _From, State) ->
{Result,State1} = do_log(Bin, call, State),
@@ -429,8 +441,9 @@ terminate(Reason, State = #{id := Name}) ->
_ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State,
undefined)),
_ = close_disk_log(Name, normal),
+ ok = logger_h_common:stop_or_restart(Name, Reason, State),
unregister(?name_to_reg_name(?MODULE, Name)),
- logger_h_common:stop_or_restart(Name, Reason, State).
+ ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -440,7 +453,7 @@ code_change(_OldVsn, State, _Extra) ->
%%%-----------------------------------------------------------------
%%%
-get_init_state() ->
+get_default_config() ->
#{sync_mode_qlen => ?SYNC_MODE_QLEN,
drop_mode_qlen => ?DROP_MODE_QLEN,
flush_qlen => ?FLUSH_QLEN,
@@ -451,10 +464,12 @@ get_init_state() ->
overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
- dl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN,
filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
+get_init_state() ->
+ #{dl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
+ filesync_ok_qlen => ?FILESYNC_OK_QLEN}.
+
%%%-----------------------------------------------------------------
%%% Add a disk_log handler to the logger.
%%% This starts a dedicated handler process which should always
diff --git a/lib/kernel/src/logger_formatter.erl b/lib/kernel/src/logger_formatter.erl
index a5c6984bc6..ded89bac9f 100644
--- a/lib/kernel/src/logger_formatter.erl
+++ b/lib/kernel/src/logger_formatter.erl
@@ -28,7 +28,6 @@
%%% Types
-type config() :: #{chars_limit => pos_integer() | unlimited,
depth => pos_integer() | unlimited,
- encoding => unicode:encoding(),
legacy_header => boolean(),
max_size => pos_integer() | unlimited,
report_cb => logger:report_cb(),
@@ -84,7 +83,7 @@ format(#{level:=Level,msg:=Msg0,meta:=Meta},Config0)
true ->
""
end,
- truncate(B ++ MsgStr ++ A,maps:get(max_size,Config)).
+ truncate([B,MsgStr,A],maps:get(max_size,Config)).
do_format(Level,Data,[level|Format],Config) ->
[to_string(level,Level,Config)|do_format(Level,Data,Format,Config)];
@@ -147,7 +146,7 @@ printable_list(X) ->
io_lib:printable_list(X).
format_msg({string,Chardata},Meta,Config) ->
- format_msg({s(Config),[Chardata]},Meta,Config);
+ format_msg({"~ts",[Chardata]},Meta,Config);
format_msg({report,_}=Msg,Meta,#{report_cb:=Fun}=Config)
when is_function(Fun,1); is_function(Fun,2) ->
format_msg(Msg,Meta#{report_cb=>Fun},maps:remove(report_cb,Config));
@@ -166,13 +165,13 @@ format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,1
Meta,Config)
end;
format_msg({report,Report},#{report_cb:=Fun}=Meta,Config) when is_function(Fun,2) ->
- try Fun(Report,maps:with([encoding,depth,chars_limit],Config)) of
- String when ?IS_STRING(String) ->
- try unicode:characters_to_list(String)
+ try Fun(Report,maps:with([depth,chars_limit,single_line],Config)) of
+ Chardata when ?IS_STRING(Chardata) ->
+ try chardata_to_list(Chardata) % already size limited by report_cb
catch _:_ ->
P = p(Config),
format_msg({"REPORT_CB/2 ERROR: "++P++"; Returned: "++P,
- [Report,String]},Meta,Config)
+ [Report,Chardata]},Meta,Config)
end;
Other ->
P = p(Config),
@@ -188,41 +187,58 @@ format_msg({report,Report},Meta,Config) ->
format_msg({report,Report},
Meta#{report_cb=>fun logger:format_report/1},
Config);
-format_msg(Msg,_Meta,#{depth:=Depth,chars_limit:=CharsLimit,encoding:=Enc}) ->
- limit_size(Msg, Depth, CharsLimit, Enc).
-
-limit_size(Msg,Depth,unlimited,Enc) ->
- limit_size(Msg,Depth,[],Enc);
-limit_size(Msg,Depth,CharsLimit,Enc) when is_integer(CharsLimit) ->
- limit_size(Msg,Depth,[{chars_limit,CharsLimit}],Enc);
-limit_size({Format,Args},unlimited,Opts,Enc) when is_list(Opts) ->
- try io_lib:format(Format,Args,Opts)
- catch _:_ ->
- P = p(Enc),
- io_lib:format("FORMAT ERROR: "++P++" - "++P,[Format,Args],Opts)
- end;
-limit_size({Format0,Args},Depth,Opts,Enc) when is_integer(Depth) ->
+format_msg(Msg,_Meta,#{depth:=Depth,chars_limit:=CharsLimit,
+ single_line:=Single}) ->
+ Opts = chars_limit_to_opts(CharsLimit),
+ format_msg(Msg, Depth, Opts, Single).
+
+chars_limit_to_opts(unlimited) -> [];
+chars_limit_to_opts(CharsLimit) -> [{chars_limit,CharsLimit}].
+
+format_msg({Format0,Args},Depth,Opts,Single) ->
try
Format1 = io_lib:scan_format(Format0, Args),
- Format = limit_format(Format1, Depth),
+ Format = reformat(Format1, Depth, Single),
io_lib:build_text(Format,Opts)
- catch _:_ ->
- P = p(Enc),
- limit_size({"FORMAT ERROR: "++P++" - "++P,[Format0,Args]},
- Depth,Opts,Enc)
+ catch C:R:S ->
+ P = p(Single),
+ FormatError = "FORMAT ERROR: "++P++" - "++P,
+ case Format0 of
+ FormatError ->
+ %% already been here - avoid failing cyclically
+ erlang:raise(C,R,S);
+ _ ->
+ format_msg({FormatError,[Format0,Args]},Depth,Opts,Single)
+ end
end.
-limit_format([#{control_char:=C0}=M0|T], Depth) when C0 =:= $p;
- C0 =:= $w ->
- C = C0 - ($a - $A), %To uppercase.
- #{args:=Args} = M0,
- M = M0#{control_char:=C,args:=Args++[Depth]},
- [M|limit_format(T, Depth)];
-limit_format([H|T], Depth) ->
- [H|limit_format(T, Depth)];
-limit_format([], _) ->
+reformat(Format,unlimited,false) ->
+ Format;
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $p ->
+ [limit_depth(M#{width => 0}, Depth)|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, true) when C =:= $P ->
+ [M#{width => 0}|reformat(T, Depth, true)];
+reformat([#{control_char:=C}=M|T], Depth, Single) when C =:= $p; C =:= $w ->
+ [limit_depth(M, Depth)|reformat(T, Depth, Single)];
+reformat([H|T], Depth, Single) ->
+ [H|reformat(T, Depth, Single)];
+reformat([], _, _) ->
[].
+limit_depth(M0, unlimited) ->
+ M0;
+limit_depth(#{control_char:=C0, args:=Args}=M0, Depth) ->
+ C = C0 - ($a - $A), %To uppercase.
+ M0#{control_char:=C,args:=Args++[Depth]}.
+
+chardata_to_list(Chardata) ->
+ case unicode:characters_to_list(Chardata,unicode) of
+ List when is_list(List) ->
+ List;
+ Error ->
+ throw(Error)
+ end.
+
truncate(String,unlimited) ->
String;
truncate(String,Size) ->
@@ -268,12 +284,11 @@ maybe_add_legacy_header(Level,
#{time:=Timestamp}=Meta,
#{legacy_header:=true}=Config) ->
#{title:=Title}=MyMeta = add_legacy_title(Level,Meta,Config),
- {{Y,Mo,D},{H,Mi,Sec},Micro,UtcStr} =
+ {{Y,Mo,D},{H,Mi,S},Micro,UtcStr} =
timestamp_to_datetimemicro(Timestamp,Config),
- S = s(Config),
Header =
- io_lib:format("="++S++"==== ~w-~s-~4w::~2..0w:~2..0w:~2..0w.~6..0w ~s===",
- [Title,D,month(Mo),Y,H,Mi,Sec,Micro,UtcStr]),
+ io_lib:format("=~ts==== ~w-~s-~4w::~2..0w:~2..0w:~2..0w.~6..0w ~s===",
+ [Title,D,month(Mo),Y,H,Mi,S,Micro,UtcStr]),
Meta#{?MODULE=>MyMeta#{header=>Header}};
maybe_add_legacy_header(_,Meta,_) ->
Meta.
@@ -314,7 +329,6 @@ month(12) -> "Dec".
add_default_config(Config0) ->
Default =
#{chars_limit=>unlimited,
- encoding=>utf8,
error_logger_notice_header=>info,
legacy_header=>false,
single_line=>true,
@@ -492,16 +506,9 @@ check_timezone(Tz) ->
error
end.
-p(#{encoding:=Enc}) ->
- p(Enc);
-p(latin1) ->
- "~p";
-p(_) ->
+p(#{single_line:=Single}) ->
+ p(Single);
+p(true) ->
+ "~0tp";
+p(false) ->
"~tp".
-
-s(#{encoding:=Enc}) ->
- s(Enc);
-s(latin1) ->
- "~s";
-s(_) ->
- "~ts".
diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl
index 854e5479b9..94c640cb92 100644
--- a/lib/kernel/src/logger_h_common.erl
+++ b/lib/kernel/src/logger_h_common.erl
@@ -40,7 +40,7 @@
info_notify/1]).
%%%-----------------------------------------------------------------
-%%% Covert log data on any form to binary
+%%% Convert log data on any form to binary
-spec log_to_binary(LogEvent,Config) -> LogString when
LogEvent :: logger:log_event(),
Config :: logger:handler_config(),
@@ -57,13 +57,14 @@ do_log_to_binary(Log,Config) ->
{Formatter,FormatterConfig} =
maps:get(formatter,Config,{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}),
String = try_format(Log,Formatter,FormatterConfig),
- try unicode:characters_to_binary(String)
- catch _:_ ->
+ try string_to_binary(String)
+ catch C2:R2:S2 ->
?LOG_INTERNAL(debug,[{formatter_error,Formatter},
{config,FormatterConfig},
{log_event,Log},
- {bad_return_value,String}]),
- <<"FORMATTER ERROR: bad_return_value">>
+ {bad_return_value,String},
+ {catched,{C2,R2,S2}}]),
+ <<"FORMATTER ERROR: bad return value">>
end.
try_format(Log,Formatter,FormatterConfig) ->
@@ -85,6 +86,15 @@ try_format(Log,Formatter,FormatterConfig) ->
end
end.
+string_to_binary(String) ->
+ case unicode:characters_to_binary(String) of
+ Binary when is_binary(Binary) ->
+ Binary;
+ Error ->
+ throw(Error)
+ end.
+
+
%%%-----------------------------------------------------------------
%%% Check that the configuration term is valid
check_common_config({mode_tab,_Tid}) ->
@@ -284,6 +294,7 @@ stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
%% and set a restart timer. A separate process must perform this
%% in order to avoid deadlock.
HandlerPid = self(),
+ ConfigResult = logger:get_handler_config(Name),
RemoveAndRestart =
fun() ->
MRef = erlang:monitor(process, HandlerPid),
@@ -294,9 +305,12 @@ stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}},
error_notify(Reason),
exit(HandlerPid, kill)
end,
- case logger:get_handler_config(Name) of
- {ok,#{module:=HMod}=HConfig} when is_integer(RestartAfter) ->
+ case ConfigResult of
+ {ok,#{module:=HMod}=HConfig0} when is_integer(RestartAfter) ->
_ = logger:remove_handler(Name),
+ HConfig = try HMod:filter_config(HConfig0)
+ catch _:_ -> HConfig0
+ end,
_ = timer:apply_after(RestartAfter, logger, add_handler,
[Name,HMod,HConfig]);
{ok,_} ->
diff --git a/lib/kernel/src/logger_server.erl b/lib/kernel/src/logger_server.erl
index 28e31d46ea..b7735dbcf7 100644
--- a/lib/kernel/src/logger_server.erl
+++ b/lib/kernel/src/logger_server.erl
@@ -27,9 +27,13 @@
add_filter/2, remove_filter/2,
set_module_level/2, unset_module_level/0,
unset_module_level/1, cache_module_level/1,
- set_config/2, set_config/3, update_config/2,
+ set_config/2, set_config/3,
+ update_config/2, update_config/3,
update_formatter_config/2]).
+%% Helper
+-export([diff_maps/2]).
+
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2]).
@@ -83,7 +87,7 @@ set_module_level(Modules,Level) when is_list(Modules) ->
Error -> Error
end;
false ->
- {error,{not_a_list_of_modles,Modules}}
+ {error,{not_a_list_of_modules,Modules}}
end;
set_module_level(Modules,_) ->
{error,{not_a_list_of_modules,Modules}}.
@@ -96,7 +100,7 @@ unset_module_level(Modules) when is_list(Modules) ->
true ->
call({unset_module_level,Modules});
false ->
- {error,{not_a_list_of_modles,Modules}}
+ {error,{not_a_list_of_modules,Modules}}
end;
unset_module_level(Modules) ->
{error,{not_a_list_of_modules,Modules}}.
@@ -105,12 +109,25 @@ cache_module_level(Module) ->
gen_server:cast(?SERVER,{cache_module_level,Module}).
set_config(Owner,Key,Value) ->
- update_config(Owner,#{Key=>Value}).
+ case sanity_check(Owner,Key,Value) of
+ ok ->
+ call({change_config,set,Owner,Key,Value});
+ Error ->
+ Error
+ end.
set_config(Owner,Config) ->
case sanity_check(Owner,Config) of
ok ->
- call({set_config,Owner,Config});
+ call({change_config,set,Owner,Config});
+ Error ->
+ Error
+ end.
+
+update_config(Owner,Key,Value) ->
+ case sanity_check(Owner,Key,Value) of
+ ok ->
+ call({change_config,update,Owner,Key,Value});
Error ->
Error
end.
@@ -118,7 +135,7 @@ set_config(Owner,Config) ->
update_config(Owner, Config) ->
case sanity_check(Owner,Config) of
ok ->
- call({update_config,Owner,Config});
+ call({change_config,update,Owner,Config});
Error ->
Error
end.
@@ -146,7 +163,7 @@ init([]) ->
filters=>?DEFAULT_HANDLER_FILTERS}),
%% If this fails, then the node should crash
{ok,SimpleConfig} = logger_simple_h:adding_handler(SimpleConfig0),
- logger_config:create(Tid,simple,logger_simple_h,SimpleConfig),
+ logger_config:create(Tid,simple,SimpleConfig),
{ok, #state{tid=Tid, async_req_queue = queue:new()}}.
handle_call({add_handler,Id,Module,HConfig}, From, #state{tid=Tid}=State) ->
@@ -165,11 +182,11 @@ handle_call({add_handler,Id,Module,HConfig}, From, #state{tid=Tid}=State) ->
%% to find out if this is a valid handler
case erlang:function_exported(Module, log, 2) of
true ->
- logger_config:create(Tid,Id,Module,HConfig1),
- {ok,Config} = do_get_config(Tid,primary),
+ logger_config:create(Tid,Id,HConfig1),
+ {ok,Config} = logger_config:get(Tid,primary),
Handlers = maps:get(handlers,Config,[]),
- do_set_config(Tid,primary,
- Config#{handlers=>[Id|Handlers]});
+ logger_config:set(Tid,primary,
+ Config#{handlers=>[Id|Handlers]});
false ->
{error,{invalid_handler,
{function_not_exported,
@@ -181,8 +198,8 @@ handle_call({add_handler,Id,Module,HConfig}, From, #state{tid=Tid}=State) ->
end;
handle_call({remove_handler,HandlerId}, From, #state{tid=Tid}=State) ->
case logger_config:get(Tid,HandlerId) of
- {ok,{Module,HConfig}} ->
- {ok,Config} = do_get_config(Tid,primary),
+ {ok,#{module:=Module}=HConfig} ->
+ {ok,Config} = logger_config:get(Tid,primary),
Handlers0 = maps:get(handlers,Config,[]),
Handlers = lists:delete(HandlerId,Handlers0),
call_h_async(
@@ -191,7 +208,7 @@ handle_call({remove_handler,HandlerId}, From, #state{tid=Tid}=State) ->
call_h(Module,removing_handler,[HConfig],ok)
end,
fun(_Res) ->
- do_set_config(Tid,primary,Config#{handlers=>Handlers}),
+ logger_config:set(Tid,primary,Config#{handlers=>Handlers}),
logger_config:delete(Tid,HandlerId),
ok
end,From,State);
@@ -204,36 +221,72 @@ handle_call({add_filter,Id,Filter}, _From,#state{tid=Tid}=State) ->
handle_call({remove_filter,Id,FilterId}, _From, #state{tid=Tid}=State) ->
Reply = do_remove_filter(Tid,Id,FilterId),
{reply,Reply,State};
-handle_call({update_config,Id,NewConfig}, From, #state{tid=Tid}=State) ->
- case logger_config:get(Tid,Id) of
- {ok,{_Module,OldConfig}} ->
- Config = maps:merge(OldConfig,NewConfig),
- handle_call({set_config,Id,Config}, From, State);
- {ok,OldConfig} ->
- Config = maps:merge(OldConfig,NewConfig),
- {reply,do_set_config(Tid,Id,Config),State};
- Error ->
- {reply,Error,State}
- end;
-handle_call({set_config,primary,Config0}, _From, #state{tid=Tid}=State) ->
- Config = maps:merge(default_config(primary),Config0),
- {ok,#{handlers:=Handlers}} = logger_config:get(Tid,primary),
- Reply = do_set_config(Tid,primary,Config#{handlers=>Handlers}),
+handle_call({change_config,SetOrUpd,primary,Config0}, _From,
+ #state{tid=Tid}=State) ->
+ {ok,#{handlers:=Handlers}=OldConfig} = logger_config:get(Tid,primary),
+ Default =
+ case SetOrUpd of
+ set -> default_config(primary);
+ update -> OldConfig
+ end,
+ Config = maps:merge(Default,Config0),
+ Reply = logger_config:set(Tid,primary,Config#{handlers=>Handlers}),
{reply,Reply,State};
-handle_call({set_config,HandlerId,Config0}, From, #state{tid=Tid}=State) ->
+handle_call({change_config,_SetOrUpd,primary,Key,Value}, _From,
+ #state{tid=Tid}=State) ->
+ {ok,OldConfig} = logger_config:get(Tid,primary),
+ Reply = logger_config:set(Tid,primary,OldConfig#{Key=>Value}),
+ {reply,Reply,State};
+handle_call({change_config,SetOrUpd,HandlerId,Config0}, From,
+ #state{tid=Tid}=State) ->
case logger_config:get(Tid,HandlerId) of
- {ok,{Module,OldConfig}} ->
- Config = maps:merge(default_config(HandlerId,Module),Config0),
- call_h_async(
- fun() ->
- call_h(Module,changing_config,[OldConfig,Config],
- {ok,Config})
- end,
- fun({ok,Config1}) ->
- do_set_config(Tid,HandlerId,Config1);
- (Error) ->
- Error
- end,From,State);
+ {ok,#{module:=Module}=OldConfig} ->
+ Default =
+ case SetOrUpd of
+ set -> default_config(HandlerId,Module);
+ update -> OldConfig
+ end,
+ Config = maps:merge(Default,Config0),
+ case check_config_change(OldConfig,Config) of
+ ok ->
+ call_h_async(
+ fun() ->
+ call_h(Module,changing_config,
+ [SetOrUpd,OldConfig,Config],
+ {ok,Config})
+ end,
+ fun({ok,Config1}) ->
+ logger_config:set(Tid,HandlerId,Config1);
+ (Error) ->
+ Error
+ end,From,State);
+ Error ->
+ {reply,Error,State}
+ end;
+ _ ->
+ {reply,{error,{not_found,HandlerId}},State}
+ end;
+handle_call({change_config,SetOrUpd,HandlerId,Key,Value}, From,
+ #state{tid=Tid}=State) ->
+ case logger_config:get(Tid,HandlerId) of
+ {ok,#{module:=Module}=OldConfig} ->
+ Config = OldConfig#{Key=>Value},
+ case check_config_change(OldConfig,Config) of
+ ok ->
+ call_h_async(
+ fun() ->
+ call_h(Module,changing_config,
+ [SetOrUpd,OldConfig,Config],
+ {ok,Config})
+ end,
+ fun({ok,Config1}) ->
+ logger_config:set(Tid,HandlerId,Config1);
+ (Error) ->
+ Error
+ end,From,State);
+ Error ->
+ {reply,Error,State}
+ end;
_ ->
{reply,{error,{not_found,HandlerId}},State}
end;
@@ -241,12 +294,12 @@ handle_call({update_formatter_config,HandlerId,NewFConfig},_From,
#state{tid=Tid}=State) ->
Reply =
case logger_config:get(Tid,HandlerId) of
- {ok,{_Mod,#{formatter:={FMod,OldFConfig}}=Config}} ->
+ {ok,#{formatter:={FMod,OldFConfig}}=Config} ->
try
FConfig = maps:merge(OldFConfig,NewFConfig),
check_formatter({FMod,FConfig}),
- do_set_config(Tid,HandlerId,
- Config#{formatter=>{FMod,FConfig}})
+ logger_config:set(Tid,HandlerId,
+ Config#{formatter=>{FMod,FConfig}})
catch throw:Reason -> {error,Reason}
end;
_ ->
@@ -309,33 +362,34 @@ call(Request) ->
case get(?LOGGER_SERVER_TAG) of
true when
Action == add_handler; Action == remove_handler;
- Action == update_config; Action == set_config ->
+ Action == add_filter; Action == remove_filter;
+ Action == change_config ->
{error,{attempting_syncronous_call_to_self,Request}};
_ ->
gen_server:call(?SERVER,Request,?DEFAULT_LOGGER_CALL_TIMEOUT)
end.
do_add_filter(Tid,Id,{FId,_} = Filter) ->
- case do_get_config(Tid,Id) of
+ case logger_config:get(Tid,Id) of
{ok,Config} ->
Filters = maps:get(filters,Config,[]),
case lists:keymember(FId,1,Filters) of
true ->
{error,{already_exist,FId}};
false ->
- do_set_config(Tid,Id,Config#{filters=>[Filter|Filters]})
+ logger_config:set(Tid,Id,Config#{filters=>[Filter|Filters]})
end;
Error ->
Error
end.
do_remove_filter(Tid,Id,FilterId) ->
- case do_get_config(Tid,Id) of
+ case logger_config:get(Tid,Id) of
{ok,Config} ->
Filters0 = maps:get(filters,Config,[]),
case lists:keytake(FilterId,1,Filters0) of
{value,_,Filters} ->
- do_set_config(Tid,Id,Config#{filters=>Filters});
+ logger_config:set(Tid,Id,Config#{filters=>Filters});
false ->
{error,{not_found,FilterId}}
end;
@@ -343,20 +397,6 @@ do_remove_filter(Tid,Id,FilterId) ->
Error
end.
-do_get_config(Tid,Id) ->
- case logger_config:get(Tid,Id) of
- {ok,{_,Config}} ->
- {ok,Config};
- {ok,Config} ->
- {ok,Config};
- Error ->
- Error
- end.
-
-do_set_config(Tid,Id,Config) ->
- logger_config:set(Tid,Id,Config),
- ok.
-
default_config(primary) ->
#{level=>notice,
filters=>[],
@@ -376,7 +416,7 @@ sanity_check(Owner,Key,Value) ->
sanity_check(HandlerId,Config) when is_map(Config) ->
sanity_check_1(HandlerId,maps:to_list(Config));
sanity_check(_,Config) ->
- {error,{invalid_handler_config,Config}}.
+ {error,{invalid_config,Config}}.
sanity_check_1(Owner,Config) when is_list(Config) ->
try
@@ -421,8 +461,6 @@ check_mod(Mod) when is_atom(Mod) ->
check_mod(Mod) ->
throw({invalid_module,Mod}).
-check_level({LevelInt,cached}) when LevelInt>=?EMERGENCY, LevelInt=<?DEBUG ->
- ok;
check_level(Level) ->
case lists:member(Level,?LEVELS) of
true ->
@@ -463,6 +501,15 @@ check_formatter({Mod,Config}) ->
check_formatter(Formatter) ->
throw({invalid_formatter,Formatter}).
+%% When changing configuration for a handler, the id and module fields
+%% can not be changed.
+check_config_change(#{id:=Id,module:=Module},#{id:=Id,module:=Module}) ->
+ ok;
+check_config_change(OldConfig,NewConfig) ->
+ {Old,New} = logger_server:diff_maps(maps:with([id,module],OldConfig),
+ maps:with([id,module],NewConfig)),
+ {error,{illegal_config_change,Old,New}}.
+
call_h(Module, Function, Args, DefRet) ->
%% Not calling code:ensure_loaded + erlang:function_exported here,
%% since in some rare terminal cases, the code_server might not
@@ -471,6 +518,11 @@ call_h(Module, Function, Args, DefRet) ->
catch
C:R:S ->
case {C,R,S} of
+ {error,undef,[{Module,Function=changing_config,Args,_}|_]}
+ when length(Args)=:=3 ->
+ %% Backwards compatible call, if changing_config/3
+ %% did not exist.
+ call_h(Module, Function, tl(Args), DefRet);
{error,undef,[{Module,Function,Args,_}|_]} ->
DefRet;
_ ->
@@ -530,3 +582,14 @@ call_h_reply(Unexpected,State) ->
{process,?SERVER},
{message,Unexpected}]),
{noreply,State}.
+
+%% Return two maps containing only the fields that differ.
+diff_maps(M1,M2) ->
+ diffs(lists:sort(maps:to_list(M1)),lists:sort(maps:to_list(M2)),#{},#{}).
+
+diffs([H|T1],[H|T2],D1,D2) ->
+ diffs(T1,T2,D1,D2);
+diffs([{K,V1}|T1],[{K,V2}|T2],D1,D2) ->
+ diffs(T1,T2,D1#{K=>V1},D2#{K=>V2});
+diffs([],[],D1,D2) ->
+ {D1,D2}.
diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl
index 9a2a1443b3..42e0f5caf4 100644
--- a/lib/kernel/src/logger_std_h.erl
+++ b/lib/kernel/src/logger_std_h.erl
@@ -35,7 +35,8 @@
terminate/2, code_change/3]).
%% logger callbacks
--export([log/2, adding_handler/1, removing_handler/1, changing_config/2]).
+-export([log/2, adding_handler/1, removing_handler/1, changing_config/3,
+ filter_config/1]).
%% handler internal
-export([log_handler_info/4]).
@@ -116,9 +117,8 @@ reset(Name) ->
%%% Handler being added
adding_handler(#{id:=Name}=Config) ->
case check_config(adding, Config) of
- {ok, Config1} ->
+ {ok, #{config:=HConfig}=Config1} ->
%% create initial handler state by merging defaults with config
- HConfig = maps:get(config, Config1, #{}),
HState = maps:merge(get_init_state(), HConfig),
case logger_h_common:overload_levels_ok(HState) of
true ->
@@ -135,22 +135,31 @@ adding_handler(#{id:=Name}=Config) ->
%%%-----------------------------------------------------------------
%%% Updating handler config
-changing_config(OldConfig=#{id:=Name, config:=OldHConfig},
- NewConfig=#{id:=Name}) ->
- #{type:=Type, handler_pid:=HPid, mode_tab:=ModeTab} = OldHConfig,
- NewHConfig = maps:get(config, NewConfig, #{}),
- case maps:get(type, NewHConfig, Type) of
- Type ->
- NewHConfig1 = NewHConfig#{type=>Type,
- handler_pid=>HPid,
- mode_tab=>ModeTab},
- changing_config1(HPid, OldConfig,
- NewConfig#{config=>NewHConfig1});
- _ ->
- {error,{illegal_config_change,OldConfig,NewConfig}}
- end;
-changing_config(OldConfig, NewConfig) ->
- {error,{illegal_config_change,OldConfig,NewConfig}}.
+changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) ->
+ WriteOnce = maps:with([type],OldHConfig),
+ ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig),
+ NewHConfig0 = maps:get(config, NewConfig, #{}),
+ Default =
+ case SetOrUpdate of
+ set ->
+ %% Do not reset write-once fields to defaults
+ maps:merge(get_default_config(),WriteOnce);
+ update ->
+ OldHConfig
+ end,
+
+ %% Allow (accidentially) included read-only fields - just overwrite them
+ NewHConfig = maps:merge(maps:merge(Default, NewHConfig0),ReadOnly),
+
+ %% But fail if write-once fields are changed
+ case maps:with([type],NewHConfig) of
+ WriteOnce ->
+ changing_config1(maps:get(handler_pid,OldHConfig),
+ OldConfig,
+ NewConfig#{config=>NewHConfig});
+ Other ->
+ {error,{illegal_config_change,#{config=>WriteOnce},#{config=>Other}}}
+ end.
changing_config1(HPid, OldConfig, NewConfig) ->
case check_config(changing, NewConfig) of
@@ -169,8 +178,7 @@ changing_config1(HPid, OldConfig, NewConfig) ->
check_config(adding, Config) ->
%% Merge in defaults on handler level
HConfig0 = maps:get(config, Config, #{}),
- HConfig = maps:merge(#{type => standard_io},
- HConfig0),
+ HConfig = maps:merge(get_default_config(),HConfig0),
case check_h_config(maps:to_list(HConfig)) of
ok ->
{ok,Config#{config=>HConfig}};
@@ -210,7 +218,7 @@ removing_handler(#{id:=Name}) ->
%%%-----------------------------------------------------------------
%%% Log a string or report
--spec log(LogEvent, Config) -> ok | dropped when
+-spec log(LogEvent, Config) -> ok when
LogEvent :: logger:log_event(),
Config :: logger:handler_config().
@@ -223,6 +231,11 @@ log(LogEvent, Config = #{id := Name,
Bin = logger_h_common:log_to_binary(LogEvent, Config),
logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin).
+%%%-----------------------------------------------------------------
+%%% Remove internal fields from configuration
+filter_config(#{config:=HConfig}=Config) ->
+ Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}.
+
%%%===================================================================
%%% gen_server callbacks
%%%===================================================================
@@ -259,7 +272,7 @@ init([Name, Config = #{config := HConfig},
mode_tab => ModeTab}},
proc_lib:init_ack({ok,self(),Config1}),
gen_server:cast(self(), repeated_filesync),
- enter_loop(Config1, State1)
+ gen_server:enter_loop(?MODULE, [], State1)
catch
_:Error ->
unregister(RegName),
@@ -290,9 +303,6 @@ do_init(Name, Type) ->
Error
end.
-enter_loop(_Config,State) ->
- gen_server:enter_loop(?MODULE,[],State).
-
%% This is the synchronous log event.
handle_call({log, Bin}, _From, State) ->
{Result,State1} = do_log(Bin, call, State),
@@ -418,8 +428,9 @@ terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid,
false ->
ok
end,
+ ok = logger_h_common:stop_or_restart(Name, Reason, State),
unregister(?name_to_reg_name(?MODULE, Name)),
- logger_h_common:stop_or_restart(Name, Reason, State).
+ ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
@@ -430,8 +441,9 @@ code_change(_OldVsn, State, _Extra) ->
%%%-----------------------------------------------------------------
%%%
-get_init_state() ->
- #{sync_mode_qlen => ?SYNC_MODE_QLEN,
+get_default_config() ->
+ #{type => standard_io,
+ sync_mode_qlen => ?SYNC_MODE_QLEN,
drop_mode_qlen => ?DROP_MODE_QLEN,
flush_qlen => ?FLUSH_QLEN,
burst_limit_enable => ?BURST_LIMIT_ENABLE,
@@ -441,10 +453,12 @@ get_init_state() ->
overload_kill_qlen => ?OVERLOAD_KILL_QLEN,
overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER,
- file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
- filesync_ok_qlen => ?FILESYNC_OK_QLEN,
filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}.
+get_init_state() ->
+ #{file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL,
+ filesync_ok_qlen => ?FILESYNC_OK_QLEN}.
+
%%%-----------------------------------------------------------------
%%% Add a standard handler to the logger.
%%% This starts a dedicated handler process which should always
@@ -827,4 +841,3 @@ sync_dev(Fd, DevName, PrevSyncResult, HandlerName) ->
logger_h_common:error_notify({HandlerName,filesync,DevName,Error}),
Error
end.
-
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index bea08242d8..01d809b566 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -279,24 +279,18 @@ passive_connect_monitor(From, Node) ->
ok = monitor_nodes(true,[{node_type,all}]),
Reply = case lists:member(Node,nodes([connected])) of
true ->
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]),
true;
_ ->
receive
{nodeup,Node,_} ->
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]),
true
after connecttime() ->
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]),
false
end
end,
ok = monitor_nodes(false,[{node_type,all}]),
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]),
{Pid, Tag} = From,
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]),
- erlang:send(Pid, {Tag, Reply}),
- io:format("~p: passive_connect_monitor ~p\n", [self(), ?LINE]).
+ erlang:send(Pid, {Tag, Reply}).
%% If the net_kernel isn't running we ignore all requests to the
@@ -358,20 +352,34 @@ init({Name, LongOrShortNames, TickT, CleanHalt}) ->
{stop, Error}
end.
-
-do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State) ->
- ConnLookup = ets:lookup(sys_dist, Node),
-
- case ConnLookup of
+do_auto_connect_1(Node, ConnId, From, State) ->
+ case ets:lookup(sys_dist, Node) of
[#barred_connection{}] ->
- case WaitForBarred of
- false ->
- {reply, false, State};
- true ->
+ case ConnId of
+ passive_cnct ->
spawn(?MODULE,passive_connect_monitor,[From,Node]),
- {noreply, State}
+ {noreply, State};
+ _ ->
+ erts_internal:abort_connection(Node, ConnId),
+ {reply, false, State}
end;
+ ConnLookup ->
+ do_auto_connect_2(Node, ConnId, From, State, ConnLookup)
+ end.
+
+do_auto_connect_2(Node, passive_cnct, From, State, ConnLookup) ->
+ try erts_internal:new_connection(Node) of
+ ConnId ->
+ do_auto_connect_2(Node, ConnId, From, State, ConnLookup)
+ catch
+ _:_ ->
+ error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
+ [Node]),
+ {reply, false, State}
+ end;
+do_auto_connect_2(Node, ConnId, From, State, ConnLookup) ->
+ case ConnLookup of
[#connection{conn_id=ConnId, state = up}] ->
{reply, true, State};
[#connection{conn_id=ConnId, waiting=Waiting}=Conn] ->
@@ -385,6 +393,7 @@ do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State) ->
case application:get_env(kernel, dist_auto_connect) of
{ok, never} ->
?connect_failure(Node,{dist_auto_connect,never}),
+ erts_internal:abort_connection(Node, ConnId),
{reply, false, State};
%% This might happen due to connection close
@@ -394,14 +403,16 @@ do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State) ->
(hd(ConnLookup))#connection.state =:= up ->
?connect_failure(Node,{barred_connection,
ets:lookup(sys_dist, Node)}),
+ erts_internal:abort_connection(Node, ConnId),
{reply, false, State};
_ ->
- case setup(ConnLookup, Node,ConnId,Type,From,State) of
+ case setup(Node, ConnId, normal, From, State) of
{ok, SetupPid} ->
Owners = [{SetupPid, Node} | State#state.conn_owners],
{noreply,State#state{conn_owners=Owners}};
_Error ->
?connect_failure(Node, {setup_call, failed, _Error}),
+ erts_internal:abort_connection(Node, ConnId),
{reply, false, State}
end
end
@@ -419,8 +430,8 @@ do_explicit_connect([#connection{conn_id = ConnId}=Conn], _, _, ConnId, From, St
do_explicit_connect([#barred_connection{}], Type, Node, ConnId, From , State) ->
%% Barred connection only affects auto_connect, ignore it.
do_explicit_connect([], Type, Node, ConnId, From , State);
-do_explicit_connect(ConnLookup, Type, Node, ConnId, From , State) ->
- case setup(ConnLookup, Node,ConnId,Type,From,State) of
+do_explicit_connect(_ConnLookup, Type, Node, ConnId, From , State) ->
+ case setup(Node,ConnId,Type,From,State) of
{ok, SetupPid} ->
Owners = [{SetupPid, Node} | State#state.conn_owners],
{noreply,State#state{conn_owners=Owners}};
@@ -429,18 +440,6 @@ do_explicit_connect(ConnLookup, Type, Node, ConnId, From , State) ->
{reply, false, State}
end.
--define(ERTS_DIST_CON_ID_MASK, 16#ffffff). % also in external.h
-
-verify_new_conn_id([], {Nr,_DHandle})
- when (Nr band (bnot ?ERTS_DIST_CON_ID_MASK)) =:= 0 ->
- true;
-verify_new_conn_id([#connection{conn_id = {Old,_}}], {New,_})
- when New =:= ((Old+1) band ?ERTS_DIST_CON_ID_MASK) ->
- true;
-verify_new_conn_id(_, _) ->
- false.
-
-
%% ------------------------------------------------------------
%% handle_call.
@@ -454,18 +453,7 @@ handle_call({passive_cnct, Node}, From, State) when Node =:= node() ->
async_reply({reply, true, State}, From);
handle_call({passive_cnct, Node}, From, State) ->
verbose({passive_cnct, Node}, 1, State),
- Type = normal,
- WaitForBarred = true,
- R = case (catch erts_internal:new_connection(Node)) of
- {Nr,_DHandle}=ConnId when is_integer(Nr) ->
- do_auto_connect(Type, Node, ConnId, WaitForBarred, From, State);
-
- _Error ->
- error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
- [Node]),
- {reply, false, State}
- end,
-
+ R = do_auto_connect_1(Node, passive_cnct, From, State),
return_call(R, From);
%%
@@ -477,11 +465,21 @@ handle_call({connect, _, Node}, From, State) when Node =:= node() ->
handle_call({connect, Type, Node}, From, State) ->
verbose({connect, Type, Node}, 1, State),
ConnLookup = ets:lookup(sys_dist, Node),
- R = case (catch erts_internal:new_connection(Node)) of
- {Nr,_DHandle}=ConnId when is_integer(Nr) ->
- do_explicit_connect(ConnLookup, Type, Node, ConnId, From, State);
+ R = try erts_internal:new_connection(Node) of
+ ConnId ->
+ R1 = do_explicit_connect(ConnLookup, Type, Node, ConnId, From, State),
+ case R1 of
+ {reply, true, _S} -> %% already connected
+ ok;
+ {noreply, _S} -> %% connection pending
+ ok;
+ {reply, false, _S} -> %% connection refused
+ erts_internal:abort_connection(Node, ConnId)
+ end,
+ R1
- _Error ->
+ catch
+ _:_ ->
error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
[Node]),
{reply, false, State}
@@ -699,11 +697,11 @@ terminate(_Reason, State) ->
%%
%% Asynchronous auto connect request
%%
-handle_info({auto_connect,Node, Nr, DHandle}, State) ->
- verbose({auto_connect, Node, Nr, DHandle}, 1, State),
- ConnId = {Nr, DHandle},
+handle_info({auto_connect,Node, DHandle}, State) ->
+ verbose({auto_connect, Node, DHandle}, 1, State),
+ ConnId = DHandle,
NewState =
- case do_auto_connect(normal, Node, ConnId, false, noreply, State) of
+ case do_auto_connect_1(Node, ConnId, noreply, State) of
{noreply, S} -> %% Pending connection
S;
@@ -711,7 +709,6 @@ handle_info({auto_connect,Node, Nr, DHandle}, State) ->
S;
{reply, false, S} -> %% Connection refused
- erts_internal:abort_connection(Node, ConnId),
S
end,
{noreply, NewState};
@@ -796,8 +793,8 @@ handle_info({AcceptPid, {accept_pending,MyNode,Node,Address,Type}}, State) ->
AcceptPid ! {self(), {accept_pending, already_pending}},
{noreply, State};
_ ->
- case (catch erts_internal:new_connection(Node)) of
- {Nr,_DHandle}=ConnId when is_integer(Nr) ->
+ try erts_internal:new_connection(Node) of
+ ConnId ->
ets:insert(sys_dist, #connection{node = Node,
conn_id = ConnId,
state = pending,
@@ -806,9 +803,9 @@ handle_info({AcceptPid, {accept_pending,MyNode,Node,Address,Type}}, State) ->
type = Type}),
AcceptPid ! {self(),{accept_pending,ok}},
Owners = [{AcceptPid,Node} | State#state.conn_owners],
- {noreply, State#state{conn_owners = Owners}};
-
- _ ->
+ {noreply, State#state{conn_owners = Owners}}
+ catch
+ _:_ ->
error_logger:error_msg("~n** Cannot get connection id for node ~w~n",
[Node]),
AcceptPid ! {self(),{accept_pending,nok_pending}}
@@ -1275,8 +1272,8 @@ spawn_func(_,{From,Tag},M,F,A,Gleader) ->
%% Set up connection to a new node.
%% -----------------------------------------------------------
-setup(ConnLookup, Node,ConnId,Type,From,State) ->
- case setup_check(ConnLookup, Node, ConnId, State) of
+setup(Node, ConnId, Type, From, State) ->
+ case setup_check(Node, State) of
{ok, L} ->
Mod = L#listen.module,
LAddr = L#listen.address,
@@ -1305,7 +1302,7 @@ setup(ConnLookup, Node,ConnId,Type,From,State) ->
Error
end.
-setup_check(ConnLookup, Node, ConnId, State) ->
+setup_check(Node, State) ->
Allowed = State#state.allowed,
case lists:member(Node, Allowed) of
false when Allowed =/= [] ->
@@ -1313,16 +1310,9 @@ setup_check(ConnLookup, Node, ConnId, State) ->
"disallowed node ~w ** ~n", [Node]),
{error, bad_node};
_ ->
- case verify_new_conn_id(ConnLookup, ConnId) of
- false ->
- error_msg("** Connection attempt to ~w with "
- "bad connection id ~w ** ~n", [Node, ConnId]),
- {error, bad_conn_id};
- true ->
- case select_mod(Node, State#state.listen) of
- {ok, _L}=OK -> OK;
- Error -> Error
- end
+ case select_mod(Node, State#state.listen) of
+ {ok, _L}=OK -> OK;
+ Error -> Error
end
end.
@@ -1442,7 +1432,7 @@ validate_hostname([$@|HostPart] = Host) ->
end.
valid_name_head(Head) ->
- {ok, MP} = re:compile("^[0-9A-Za-z_\\-]*$", [unicode]),
+ {ok, MP} = re:compile("^[0-9A-Za-z_\\-]+$", [unicode]),
case re:run(Head, MP) of
{match, _} ->
true;
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 1314316c13..abb22b5035 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -525,7 +525,7 @@ upgrade(Config) ->
T = [beam, hipe],
[upgrade_do(DataDir, Client, T) || Client <- T],
- case hipe:llvm_support_available() of
+ case hipe:erllvm_is_supported() of
false -> ok;
true ->
T2 = [beam, hipe_llvm],
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index 0709a6e766..9704c3b28c 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -1750,7 +1750,7 @@ block_queue(Conf) when is_list(Conf) ->
true = [{1,a},{2,b},{3,c},{4,d},{5,e},{6,f},{7,g},{8,h}] == Terms,
del(File, 2),
Q = qlen(),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
%% OTP-4880. Blocked processes did not get disk_log_stopped message.
@@ -1782,7 +1782,7 @@ block_queue2(Conf) when is_list(Conf) ->
{ok,<<>>} = file:read_file(File ++ ".1"),
del(File, No),
Q = qlen(),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
@@ -2119,7 +2119,7 @@ close_block(Conf) when is_list(Conf) ->
0 = sync_do(Pid2, users),
sync_do(Pid2, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Users terminate (no link...).
Pid3 = spawn_link(?MODULE, lserv, [n]),
@@ -2137,7 +2137,7 @@ close_block(Conf) when is_list(Conf) ->
disk_log:close(n),
disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner terminates.
Pid5 = spawn_link(?MODULE, lserv, [n]),
@@ -2154,7 +2154,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user terminates.
Pid6 = spawn_link(?MODULE, lserv, [n]),
@@ -2174,7 +2174,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner terminates.
Pid7 = spawn_link(?MODULE, lserv, [n]),
@@ -2192,7 +2192,7 @@ close_block(Conf) when is_list(Conf) ->
1 = users(n),
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Two owners, the blocking one terminates.
Pid8 = spawn_link(?MODULE, lserv, [n]),
@@ -2207,7 +2207,7 @@ close_block(Conf) when is_list(Conf) ->
0 = sync_do(Pid9, users),
sync_do(Pid9, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user closes.
Pid10 = spawn_link(?MODULE, lserv, [n]),
@@ -2225,7 +2225,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
sync_do(Pid10, terminate),
{error, no_such_log} = disk_log:info(n),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking user unblocks and closes.
Pid11 = spawn_link(?MODULE, lserv, [n]),
@@ -2244,7 +2244,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid11, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner closes.
Pid12 = spawn_link(?MODULE, lserv, [n]),
@@ -2263,7 +2263,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid12, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
%% Blocking owner unblocks and closes.
Pid13 = spawn_link(?MODULE, lserv, [n]),
@@ -2283,7 +2283,7 @@ close_block(Conf) when is_list(Conf) ->
ok = disk_log:close(n),
{error, no_such_log} = disk_log:info(n),
sync_do(Pid13, terminate),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No), % cleanup
ok.
@@ -2487,7 +2487,7 @@ error_repair(Conf) when is_list(Conf) ->
P0 = pps(),
{error, {file_error, _, _}} =
disk_log:open([{name, n}, {file, File}, {type, wrap}, {size,{40,4}}]),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No),
ok = file:del_dir(Dir),
@@ -2506,7 +2506,7 @@ error_repair(Conf) when is_list(Conf) ->
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {40,No}}]),
ok = disk_log:close(n),
- true = (P1 == pps()),
+ check_pps(P1),
del(File, No),
receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
after 1000 -> ct:fail(failed) end,
@@ -2524,7 +2524,7 @@ error_repair(Conf) when is_list(Conf) ->
disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, internal}, {size, {4000,No}}]),
ok = disk_log:close(n),
- true = (P2 == pps()),
+ check_pps(P2),
del(File, No),
receive {info_msg, _, "disk_log: repairing" ++ _, _} -> ok
after 1000 -> ct:fail(failed) end,
@@ -2633,7 +2633,7 @@ error_log(Conf) when is_list(Conf) ->
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, wrap},
{format, external},{size, {100, No}}]),
{error, {file_error, _, _}} = disk_log:truncate(n),
- true = (P0 == pps()),
+ check_pps(P0),
del(File, No),
%% OTP-4880.
@@ -2641,7 +2641,7 @@ error_log(Conf) when is_list(Conf) ->
{ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt},
{format, external},{size, 100000}]),
{error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir),
- true = (P0 == pps()),
+ check_pps(P0),
file:delete(File),
B = mk_bytes(60),
@@ -3003,7 +3003,7 @@ error_index(Conf) when is_list(Conf) ->
{error, {invalid_index_file, _}} = disk_log:open(Args),
del(File, No),
- true = (P0 == pps()),
+ check_pps(P0),
true = (Q == qlen()),
ok.
@@ -4436,7 +4436,7 @@ dist_open2(Conf) when is_list(Conf) ->
timer:sleep(500),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
%% This time the first process has a naughty head_func. This test
%% does not add very much. Perhaps it should be removed. However,
@@ -4482,7 +4482,7 @@ dist_open2(Conf) when is_list(Conf) ->
timer:sleep(100),
{error, no_such_log} = disk_log:close(Log),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
No = 2,
Log2 = n2,
@@ -4511,7 +4511,7 @@ dist_open2(Conf) when is_list(Conf) ->
file:delete(File2),
del(File, No),
- true = (P0 == pps()),
+ check_pps(P0),
R.
@@ -4556,7 +4556,7 @@ dist_open2_1(Conf, Delay) ->
{error, no_such_log} = disk_log:info(Log),
file:delete(File),
- true = (P0 == pps()),
+ check_pps(P0),
ok.
@@ -4613,7 +4613,7 @@ dist_open2_2(Conf, Delay) ->
{[{Node1,{repaired,_,_,_}}],[]}} -> ok
end,
- true = (P0 == pps()),
+ check_pps(P0),
stop_node(Node1),
file:delete(File),
ok.
@@ -4791,10 +4791,59 @@ log(Name, N) ->
format_error(E) ->
lists:flatten(disk_log:format_error(E)).
+check_pps({Ports0,Procs0} = P0) ->
+ case pps() of
+ P0 ->
+ ok;
+ _ ->
+ timer:sleep(500),
+ case pps() of
+ P0 ->
+ ok;
+ {Ports1,Procs1} = P1 ->
+ case {Ports1 -- Ports0, Procs1 -- Procs0} of
+ {[], []} -> ok;
+ {PortsDiff,ProcsDiff} ->
+ io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
+ show("Old port", Ports0 -- Ports1),
+ show("New port", PortsDiff),
+ show("Old proc", Procs0 -- Procs1),
+ show("New proc", ProcsDiff),
+ ct:fail(failed)
+ end
+ end
+ end.
+
+show(_S, []) ->
+ ok;
+show(S, [{Pid, Name, InitCall}|Pids]) when is_pid(Pid) ->
+ io:format("~s: ~w (~w), ~w: ~p~n",
+ [S, Pid, proc_reg_name(Name), InitCall,
+ erlang:process_info(Pid)]),
+ show(S, Pids);
+show(S, [{Port, _}|Ports]) when is_port(Port)->
+ io:format("~s: ~w: ~p~n", [S, Port, erlang:port_info(Port)]),
+ show(S, Ports).
+
pps() ->
timer:sleep(100),
- {erlang:ports(), lists:filter(fun(P) -> erlang:is_process_alive(P) end,
- processes())}.
+ {port_list(), process_list()}.
+
+port_list() ->
+ [{P,safe_second_element(erlang:port_info(P, name))} ||
+ P <- erlang:ports()].
+
+process_list() ->
+ [{P,process_info(P, registered_name),
+ safe_second_element(process_info(P, initial_call))} ||
+ P <- processes(), erlang:is_process_alive(P)].
+
+proc_reg_name({registered_name, Name}) -> Name;
+proc_reg_name([]) -> no_reg_name.
+
+safe_second_element({_,Info}) -> Info;
+safe_second_element(Other) -> Other.
+
qlen() ->
{_, {_, N}} = lists:keysearch(message_queue_len, 1, process_info(self())),
diff --git a/lib/kernel/test/erl_distribution_SUITE.erl b/lib/kernel/test/erl_distribution_SUITE.erl
index 0e13f0383e..5a8bbd56c4 100644
--- a/lib/kernel/test/erl_distribution_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_SUITE.erl
@@ -89,6 +89,7 @@ init_per_suite(Config) ->
Config.
end_per_suite(_Config) ->
+ [slave:stop(N) || N <- nodes()],
ok.
init_per_group(_GroupName, Config) ->
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 23913ac56a..a51025cba6 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -100,7 +100,7 @@
-export([unicode_mode/1]).
--export([volume_relative_paths/1]).
+-export([volume_relative_paths/1,unc_paths/1]).
-export([tiny_writes/1, tiny_writes_delayed/1,
large_writes/1, large_writes_delayed/1,
@@ -129,7 +129,7 @@ suite() ->
all() ->
[unicode, altname, read_write_file, {group, dirs},
- {group, files}, delete, rename, names, volume_relative_paths,
+ {group, files}, delete, rename, names, volume_relative_paths, unc_paths,
{group, errors}, {group, compression}, {group, links}, copy,
delayed_write, read_ahead, segment_read, segment_write,
ipread, pid2name, interleaved_read_write, otp_5814, otp_10852,
@@ -1367,6 +1367,10 @@ file_info_basic_file(Config) when is_list(Config) ->
io:put_chars(Fd1, "foo bar"),
ok = ?FILE_MODULE:close(Fd1),
+ %% Don't crash the file server when passing incorrect arguments.
+ {error,badarg} = ?FILE_MODULE:read_file_info(Name, [{time, gurka}]),
+ {error,badarg} = ?FILE_MODULE:read_file_info([#{} | gaffel]),
+
%% Test that the file has the expected attributes.
%% The times are tricky, so we will save them to a separate test case.
{ok,FileInfo} = ?FILE_MODULE:read_file_info(Name),
@@ -2178,6 +2182,30 @@ volume_relative_paths(Config) when is_list(Config) ->
{skip, "This test is Windows-specific."}
end.
+unc_paths(Config) when is_list(Config) ->
+ case os:type() of
+ {win32, _} ->
+ %% We assume administrative shares are set up and reachable, and we
+ %% settle for testing presence as some of the returned data is
+ %% different.
+ {ok, _} = file:read_file_info("C:\\Windows\\explorer.exe"),
+ {ok, _} = file:read_file_info("\\\\localhost\\c$\\Windows\\explorer.exe"),
+
+ {ok, Cwd} = file:get_cwd(),
+
+ try
+ ok = file:set_cwd("\\\\localhost\\c$\\Windows\\"),
+ {ok, _} = file:read_file_info("explorer.exe")
+ after
+ file:set_cwd(Cwd)
+ end,
+
+ [] = flush(),
+ ok;
+ _ ->
+ {skip, "This test is Windows-specific."}
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2206,7 +2234,8 @@ e_delete(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
%% Remove a character device.
- {error, eacces} = ?FILE_MODULE:delete("nul");
+ expect({error, eacces}, {error, einval},
+ ?FILE_MODULE:delete("nul"));
_ ->
?FILE_MODULE:write_file_info(
Base, #file_info {mode=0}),
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 950f5bea6f..04c0c48e3a 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -41,6 +41,7 @@
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
partial_recv_and_close_2/1,partial_recv_and_close_3/1,so_priority/1,
+ recvtos/1, recvttl/1, recvtosttl/1, recvtclass/1,
%% Accept tests
primitive_accept/1,multi_accept_close_listen/1,accept_timeout/1,
accept_timeouts_in_order/1,accept_timeouts_in_order2/1,
@@ -51,7 +52,8 @@
several_accepts_in_one_go/1, accept_system_limit/1,
active_once_closed/1, send_timeout/1, send_timeout_active/1,
otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1,
- wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1]).
+ wrapping_oct/0, wrapping_oct/1, otp_9389/1, otp_13939/1,
+ otp_12242/1]).
%% Internal exports.
-export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1,
@@ -83,7 +85,8 @@ all() ->
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
partial_recv_and_close_2, partial_recv_and_close_3,
- so_priority, primitive_accept,
+ so_priority, recvtos, recvttl, recvtosttl,
+ recvtclass, primitive_accept,
multi_accept_close_listen, accept_timeout,
accept_timeouts_in_order, accept_timeouts_in_order2,
accept_timeouts_in_order3, accept_timeouts_in_order4,
@@ -93,7 +96,8 @@ all() ->
killing_multi_acceptors2, several_accepts_in_one_go, accept_system_limit,
active_once_closed, send_timeout, send_timeout_active, otp_7731,
wrapping_oct,
- zombie_sockets, otp_7816, otp_8102, otp_9389].
+ zombie_sockets, otp_7816, otp_8102, otp_9389,
+ otp_12242].
groups() ->
[].
@@ -1914,6 +1918,232 @@ so_priority(Config) when is_list(Config) ->
end
end.
+
+
+%% IP_RECVTOS and IP_RECVTCLASS for IP_PKTOPTIONS
+%% does not seem to be implemented in Linux until kernel 3.1
+%%
+%% It seems pktoptions does not return valid values
+%% for IPv4 connect sockets. On the accept socket
+%% we get valid values, but on the connect socket we get
+%% the default values for TOS and TTL.
+%%
+%% Therefore the argument CheckConnect that enables
+%% checking the returned values for the connect socket.
+%% It is only used for recvtclass that is an IPv6 option
+%% and there we get valid values from both socket ends.
+
+recvtos(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2,
+ false).
+
+recvtosttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end,
+ false).
+
+recvttl(_Config) ->
+ test_pktoptions(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2,
+ false).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_pktoptions(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2,
+ true);
+ [] ->
+ {skip,{ipv6_not_supported,IFs}}
+ end.
+
+%% These version numbers are the highest noted in daily tests
+%% where the test fails for a plausible reason, so
+%% skip on that platform.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+%% Or maybe we should change to only test on known good
+%% platforms - change {unix,_} to false?
+
+%% pktoptions is not supported for IPv4
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Does not return any value - not implemented for pktoptions
+recvtos_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+%% pktoptions is not supported for IPv4
+recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
+recvttl_ok({unix,linux}, _) -> true;
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% pktoptions is not supported for IPv6
+recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0});
+%% Does not return any value - not implemented for pktoptions
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {3,1,0});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_pktoptions(Family, Spec, OSFilter, CheckConnect) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_pktoptions(Family, Spec, CheckConnect, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_pktoptions(Family, Spec, CheckConnect, OSType, OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ Address =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ %% Set RecvOpts on listen socket
+ {ok,L} =
+ gen_tcp:listen(
+ 0,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts]),
+ {ok,P} = inet:port(L),
+ {ok,TrueRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts and Option values on connect socket
+ {ok,S2} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts ++ OptsVals],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S2, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S1} = gen_tcp:accept(L, Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S1, Opts),
+%%% %%
+%%% %% Handshake
+%%% ok = gen_tcp:send(S1, <<"hello">>),
+%%% {ok,<<"hello">>} = gen_tcp:recv(S2, 5, Timeout),
+%%% ok = gen_tcp:send(S2, <<"hi">>),
+%%% {ok,<<"hi">>} = gen_tcp:recv(S1, 2, Timeout),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,OptsVals1}]} = inet:getopts(S1, [pktoptions]),
+ {ok,[{pktoptions,OptsVals2}]} = inet:getopts(S2, [pktoptions]),
+ (Result1 = sets_eq(OptsVals1, OptsVals))
+ orelse io:format(
+ "Accept differs: ~p neq ~p~n", [OptsVals1,OptsVals]),
+ (Result2 = sets_eq(OptsVals2, OptsValsDefault))
+ orelse io:format(
+ "Connect differs: ~p neq ~p~n",
+ [OptsVals2,OptsValsDefault]),
+ %%
+ ok = gen_tcp:close(S2),
+ ok = gen_tcp:close(S1),
+ %%
+ %%
+ %% Clear RecvOpts on listen socket and set Option values
+ ok = inet:setopts(L, FalseRecvOpts ++ OptsVals),
+ {ok,FalseRecvOpts} = inet:getopts(L, RecvOpts),
+ {ok,OptsVals} = inet:getopts(L, Opts),
+ %%
+ %% Set RecvOpts on connecting socket
+ %%
+ {ok,S4} =
+ gen_tcp:connect(
+ Address, P,
+ [Family,binary,{active,false},{send_timeout,Timeout}
+ |TrueRecvOpts],
+ Timeout),
+ {ok,TrueRecvOpts} = inet:getopts(S4, RecvOpts),
+ {ok,OptsValsDefault} = inet:getopts(S4, Opts),
+ %%
+ %% Accept socket inherits the options from listen socket
+ {ok,S3} = gen_tcp:accept(L, Timeout),
+ {ok,FalseRecvOpts} = inet:getopts(S3, RecvOpts),
+ {ok,OptsVals} = inet:getopts(S3, Opts),
+ %%
+ %% Verify returned remote options
+ {ok,[{pktoptions,[]}]} = inet:getopts(S3, [pktoptions]),
+ {ok,[{pktoptions,OptsVals4}]} = inet:getopts(S4, [pktoptions]),
+ (Result3 = sets_eq(OptsVals4, OptsVals))
+ orelse io:format(
+ "Accept2 differs: ~p neq ~p~n", [OptsVals4,OptsVals]),
+ %%
+ ok = gen_tcp:close(S4),
+ ok = gen_tcp:close(S3),
+ ok = gen_tcp:close(L),
+ (Result1 and ((not CheckConnect) or (Result2 and Result3)))
+ orelse
+ exit({failed,
+ [{OptsVals1,OptsVals4,OptsVals},
+ {OptsVals2,OptsValsDefault}],
+ {OSType,OSVer}}),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+sets_eq(L1, L2) ->
+ lists:sort(L1) == lists:sort(L2).
+
+
+
%% Accept test utilities (suites are below)
millis() ->
@@ -2205,7 +2435,7 @@ wait_until_accepting(Proc,0) ->
exit({timeout_waiting_for_accepting,Proc});
wait_until_accepting(Proc,N) ->
case process_info(Proc,current_function) of
- {current_function,{prim_inet,accept0,2}} ->
+ {current_function,{prim_inet,accept0,3}} ->
case process_info(Proc,status) of
{status,waiting} ->
ok;
@@ -3056,3 +3286,143 @@ otp_13939(Config) when is_list(Config) ->
exit(Pid, normal),
ct:fail("Server process blocked on send.")
end.
+
+otp_12242(Config) when is_list(Config) ->
+ case os:type() of
+ {win32,_} ->
+ %% Even if we set sndbuf and recbuf to small sizes
+ %% Windows either happily accepts to send GBytes of data
+ %% in no time, so the second send below that is supposed
+ %% to time out just succedes, or the first send that
+ %% is supposed to fill the inet_drv I/O queue and
+ %% start waiting for when more data can be sent
+ %% instead sends all data but suffers a send
+ %% failure that closes the socket
+ {skipped,backpressure_broken_on_win32};
+ _ ->
+ %% Find the IPv4 address of an up and running interface
+ %% that is not loopback nor pointtopoint
+ {ok,IFList} = inet:getifaddrs(),
+ ct:pal("IFList ~p~n", [IFList]),
+ case
+ lists:flatten(
+ [lists:filtermap(
+ fun ({addr,Addr}) when tuple_size(Addr) =:= 4 ->
+ {true,Addr};
+ (_) ->
+ false
+ end, Opts)
+ || {_,Opts} <- IFList,
+ case lists:keyfind(flags, 1, Opts) of
+ {_,Flags} ->
+ lists:member(up, Flags)
+ andalso
+ lists:member(running, Flags)
+ andalso
+ not lists:member(loopback, Flags)
+ andalso
+ not lists:member(pointtopoint, Flags);
+ false ->
+ false
+ end])
+ of
+ [Addr|_] ->
+ otp_12242(Addr);
+ Other ->
+ {skipped,{no_external_address,Other}}
+ end
+ end;
+%%
+otp_12242(Addr) when tuple_size(Addr) =:= 4 ->
+ ct:timetrap(30000),
+ ct:pal("Using address ~p~n", [Addr]),
+ Bufsize = 16 * 1024,
+ Datasize = 128 * 1024 * 1024, % At least 1 s on GBit interface
+ Blob = binary:copy(<<$x>>, Datasize),
+ LOpts =
+ [{backlog,4},{reuseaddr,true},{ip,Addr},
+ binary,{active,false},
+ {recbuf,Bufsize},{sndbuf,Bufsize},{buffer,Bufsize}],
+ COpts =
+ [binary,{active,false},{ip,Addr},
+ {linger,{true,1}}, % 1 s
+ {send_timeout,500},
+ {recbuf,Bufsize},{sndbuf,Bufsize},{buffer,Bufsize}],
+ Dir = filename:dirname(code:which(?MODULE)),
+ {ok,ListenerNode} =
+ test_server:start_node(
+ ?UNIQ_NODE_NAME, slave, [{args,"-pa " ++ Dir}]),
+ Tester = self(),
+ Listener =
+ spawn(
+ ListenerNode,
+ fun () ->
+ {ok,L} = gen_tcp:listen(0, LOpts),
+ {ok,LPort} = inet:port(L),
+ Tester ! {self(),port,LPort},
+ {ok,A} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ receive
+ {Tester,stop} ->
+ ok = gen_tcp:close(A)
+ end
+ end),
+ ListenerMref = monitor(process, Listener),
+ LPort = receive {Listener,port,P} -> P end,
+ {ok,C} = gen_tcp:connect(Addr, LPort, COpts, infinity),
+ {ok,ReadCOpts} = inet:getopts(C, [recbuf,sndbuf,buffer]),
+ ct:pal("ReadCOpts ~p~n", [ReadCOpts]),
+ %%
+ %% Fill the buffers
+ ct:pal("Sending ~p bytes~n", [Datasize]),
+ ok = gen_tcp:send(C, Blob),
+ ct:pal("Sent ~p bytes~n", [Datasize]),
+ %% Spawn the Closer,
+ %% try to ensure that the close call is in progress
+ %% before the owner proceeds with sending
+ Owner = self(),
+ {_Closer,CloserMref} =
+ spawn_opt(
+ fun () ->
+ Owner ! {tref, erlang:start_timer(50, Owner, closing)},
+ ct:pal("Calling gen_tcp:close(C)~n"),
+ try gen_tcp:close(C) of
+ Result ->
+ ct:pal("gen_tcp:close(C) -> ~p~n", [Result]),
+ ok = Result
+ catch
+ Class:Reason:Stacktrace ->
+ ct:pal(
+ "gen_tcp:close(C) >< ~p:~p~n ~p~n",
+ [Class,Reason,Stacktrace]),
+ erlang:raise(Class, Reason, Stacktrace)
+ end
+ end, [link,monitor]),
+ receive
+ {tref,Tref} ->
+ receive {timeout,Tref,_} -> ok end,
+ ct:pal("Sending ~p bytes again~n", [Datasize]),
+ %% Now should the close be in progress...
+ %% All buffers are full, remote end is not reading,
+ %% and the send timeout is 1 s so this will timeout:
+ {error,timeout} = gen_tcp:send(C, Blob),
+ ct:pal("Sending ~p bytes again timed out~n", [Datasize]),
+ ok = inet:setopts(C, [{send_timeout,10000}]),
+ %% There is a hidden timeout here. Port close is sampled
+ %% every 5 s by prim_inet:send_recv_reply.
+ %% Linger is 3 s so the Closer will finish this send:
+ ct:pal("Sending ~p bytes with 10 s timeout~n", [Datasize]),
+ {error,closed} = gen_tcp:send(C, Blob),
+ ct:pal("Sending ~p bytes with 10 s timeout was closed~n",
+ [Datasize]),
+ normal = wait(CloserMref),
+ ct:pal("The Closer has exited~n"),
+ Listener ! {Tester,stop},
+ receive {'DOWN',ListenerMref,_,_,_} -> ok end,
+ ct:pal("The Listener has exited~n"),
+ test_server:stop_node(ListenerNode),
+ ok
+ end.
+
+wait(Mref) ->
+ receive {'DOWN',Mref,_,_,Reason} -> Reason end.
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index b39399b18a..af9985de45 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -34,8 +34,9 @@
-export([init_per_testcase/2, end_per_testcase/2]).
-export([send_to_closed/1, active_n/1,
- buffer_size/1, binary_passive_recv/1, bad_address/1,
+ buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
local_basic/1, local_unbound/1,
local_fdopen/1, local_fdopen_unbound/1, local_abstract/1]).
@@ -44,9 +45,10 @@ suite() ->
{timetrap,{minutes,1}}].
all() ->
- [send_to_closed, buffer_size, binary_passive_recv,
+ [send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
bad_address, read_packets, open_fd, connect,
implicit_inet6, active_n,
+ recvtos, recvtosttl, recvttl, recvtclass,
{group, local}].
groups() ->
@@ -237,6 +239,14 @@ buffer_size_server_recv(Socket, IP, Port, Cnt) ->
end.
+%%-------------------------------------------------------------
+%% OTP-15206: Keep buffer small for udp
+%%-------------------------------------------------------------
+max_buffer_size(Config) when is_list(Config) ->
+ {ok, Socket} = gen_udp:open(0, [binary]),
+ ok = inet:setopts(Socket,[{recbuf, 1 bsl 20}]),
+ {ok, [{buffer, 65536}]} = inet:getopts(Socket,[buffer]),
+ gen_udp:close(Socket).
%%-------------------------------------------------------------
%% OTP-3823 gen_udp:recv does not return address in binary mode
@@ -564,6 +574,168 @@ active_n(Config) when is_list(Config) ->
ok.
+
+recvtos(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96}],
+ fun recvtos_ok/2).
+
+recvtosttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvtos,tos,96},{recvttl,ttl,33}],
+ fun (OSType, OSVer) ->
+ recvtos_ok(OSType, OSVer) andalso recvttl_ok(OSType, OSVer)
+ end).
+
+recvttl(_Config) ->
+ test_recv_opts(
+ inet, [{recvttl,ttl,33}],
+ fun recvttl_ok/2).
+
+recvtclass(_Config) ->
+ {ok,IFs} = inet:getifaddrs(),
+ case
+ [Name ||
+ {Name,Opts} <- IFs,
+ lists:member({addr,{0,0,0,0,0,0,0,1}}, Opts)]
+ of
+ [_] ->
+ test_recv_opts(
+ inet6, [{recvtclass,tclass,224}],
+ fun recvtclass_ok/2);
+ [] ->
+ {skip,ipv6_not_supported,IFs}
+ end.
+
+%% These version numbers are just above the highest noted in daily tests
+%% where the test fails for a plausible reason, that is the lowest
+%% where we can expect that the test mighe succeed, so
+%% skip on platforms lower than this.
+%%
+%% On newer versions it might be fixed, but we'll see about that
+%% when machines with newer versions gets installed...
+%% If the test still fails for a plausible reason these
+%% version numbers simply should be increased.
+%% Or maybe we should change to only test on known good platforms?
+
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0});
+%% Using the option returns einval, so it is not implemented.
+recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0});
+%%
+recvtos_ok({unix,_}, _) -> true;
+recvtos_ok(_, _) -> false.
+
+recvttl_ok({unix,_}, _) -> true;
+recvttl_ok(_, _) -> false.
+
+%% Using the option returns einval, so it is not implemented.
+recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {9,9,0});
+recvtclass_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,6,11});
+%%
+recvtclass_ok({unix,_}, _) -> true;
+recvtclass_ok(_, _) -> false.
+
+semver_lt({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ if
+ X1 > X2 -> false;
+ X1 < X2 -> true;
+ Y1 > Y2 -> false;
+ Y1 < Y2 -> true;
+ Z1 > Z2 -> false;
+ Z1 < Z2 -> true;
+ true -> false
+ end;
+semver_lt(_, {_,_,_}) -> false.
+
+test_recv_opts(Family, Spec, OSFilter) ->
+ OSType = os:type(),
+ OSVer = os:version(),
+ case OSFilter(OSType, OSVer) of
+ true ->
+ io:format("Os: ~p, ~p~n", [OSType,OSVer]),
+ test_recv_opts(Family, Spec, OSType, OSVer);
+ false ->
+ {skip,{not_supported_for_os_version,{OSType,OSVer}}}
+ end.
+%%
+test_recv_opts(Family, Spec, _OSType, _OSVer) ->
+ Timeout = 5000,
+ RecvOpts = [RecvOpt || {RecvOpt,_,_} <- Spec],
+ TrueRecvOpts = [{RecvOpt,true} || {RecvOpt,_,_} <- Spec],
+ FalseRecvOpts = [{RecvOpt,false} || {RecvOpt,_,_} <- Spec],
+ Opts = [Opt || {_,Opt,_} <- Spec],
+ OptsVals = [{Opt,Val} || {_,Opt,Val} <- Spec],
+ TrueRecvOpts_OptsVals = TrueRecvOpts ++ OptsVals,
+ Addr =
+ case Family of
+ inet ->
+ {127,0,0,1};
+ inet6 ->
+ {0,0,0,0,0,0,0,1}
+ end,
+ %%
+ {ok,S1} =
+ gen_udp:open(0, [Family,binary,{active,false}|TrueRecvOpts]),
+ {ok,P1} = inet:port(S1),
+ {ok,TrueRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S1, TrueRecvOpts_OptsVals),
+ {ok,TrueRecvOpts_OptsVals} = inet:getopts(S1, RecvOpts ++ Opts),
+ %%
+ {ok,S2} =
+ gen_udp:open(0, [Family,binary,{active,true}|FalseRecvOpts]),
+ {ok,P2} = inet:port(S2),
+ {ok,FalseRecvOpts_OptsVals2} = inet:getopts(S2, RecvOpts ++ Opts),
+ OptsVals2 = FalseRecvOpts_OptsVals2 -- FalseRecvOpts,
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"abcde">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"fghij">>),
+ {ok,{_,P2,OptsVals3,<<"abcde">>}} = gen_udp:recv(S1, 0, Timeout),
+ verify_sets_eq(OptsVals3, OptsVals2),
+ receive
+ {udp,S2,_,P1,<<"fghij">>} ->
+ ok;
+ Other1 ->
+ exit({unexpected,Other1})
+ after Timeout ->
+ exit(timeout)
+ end,
+ %%
+ ok = inet:setopts(S1, FalseRecvOpts),
+ {ok,FalseRecvOpts} = inet:getopts(S1, RecvOpts),
+ ok = inet:setopts(S2, TrueRecvOpts),
+ {ok,TrueRecvOpts} = inet:getopts(S2, RecvOpts),
+ %%
+ ok = gen_udp:send(S2, Addr, P1, <<"klmno">>),
+ ok = gen_udp:send(S1, Addr, P2, <<"pqrst">>),
+ {ok,{_,P2,<<"klmno">>}} = gen_udp:recv(S1, 0, Timeout),
+ receive
+ {udp,S2,_,P1,OptsVals4,<<"pqrst">>} ->
+ verify_sets_eq(OptsVals4, OptsVals);
+ Other2 ->
+ exit({unexpected,Other2})
+ after Timeout ->
+ exit(timeout)
+ end,
+ ok = gen_udp:close(S1),
+ ok = gen_udp:close(S2),
+%% exit({{OSType,OSVer},success}), % In search for the truth
+ ok.
+
+verify_sets_eq(L1, L2) ->
+ L = lists:sort(L1),
+ case lists:sort(L2) of
+ L ->
+ ok;
+ _ ->
+ exit({sets_neq,L1,L2})
+ end.
+
+
local_basic(_Config) ->
SFile = local_filename(server),
SAddr = {local,bin_filename(SFile)},
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index 0e7b7adc47..8eab36e308 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -1383,7 +1383,7 @@ ring(Config) when is_list(Config) ->
rpc_cast(Cp8, ?MODULE, single_node, [Time, Cp7, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1466,7 +1466,7 @@ simple_ring(Config) when is_list(Config) ->
rpc_cast(Cp5, ?MODULE, single_node, [Time, Cp4, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1542,7 +1542,7 @@ line(Config) when is_list(Config) ->
rpc_cast(Cp8, ?MODULE, single_node, [Time, Cp7, Config]),
%% Sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -1626,7 +1626,7 @@ simple_line(Config) when is_list(Config) ->
rpc_cast(Cp5, ?MODULE, single_node, [Time, Cp4, Config]),
%% sleep to make the partitioned net ready
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
pong = net_adm:ping(Cp0),
pong = net_adm:ping(Cp1),
@@ -3555,7 +3555,7 @@ single_node(Time, Node, Config) ->
lists:foreach(fun(N) -> _ = erlang:disconnect_node(N) end, nodes()),
?UNTIL(get_known(node()) =:= [node()]),
spawn(?MODULE, init_2, []),
- ct:sleep(Time - msec()),
+ sleep(Time - msec()),
net_adm:ping(Node).
init_2() ->
@@ -4009,13 +4009,6 @@ collect_nodes(N, Max) ->
[Node | collect_nodes(N+1, Max)]
end.
-only_element(_E, []) ->
- true;
-only_element(E, [E|R]) ->
- only_element(E, R);
-only_element(_E, _) ->
- false.
-
exit_p(Pid) ->
Ref = erlang:monitor(process, Pid),
Pid ! die,
@@ -4038,6 +4031,11 @@ wait_for_exit_fast(Pid) ->
ok
end.
+sleep(Time) when Time > 0 ->
+ ct:sleep(Time);
+sleep(_Time) ->
+ ok.
+
check_everywhere(Nodes, Name, Config) ->
?UNTIL(begin
case rpc:multicall(Nodes, global, whereis_name, [Name]) of
@@ -4162,10 +4160,10 @@ rpc_cast(Node, Module, Function, Args, File) ->
%% The emulator now ensures that the node has been removed from
%% nodes().
-rpc_disconnect_node(Node, DisconnectedNode, _Config) ->
- True = rpc:call(Node, erlang, disconnect_node, [DisconnectedNode]),
- False = lists:member(DisconnectedNode, rpc:call(Node, erlang, nodes, [])),
- {true, false} = {True, False}.
+rpc_disconnect_node(Node, DisconnectedNode, Config) ->
+ true = rpc:call(Node, erlang, disconnect_node, [DisconnectedNode]),
+ ?UNTIL
+ (not lists:member(DisconnectedNode, rpc:call(Node, erlang, nodes, []))).
%%%
%%% Utility
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index 2e5f8c7d2c..8b33f4a679 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -97,7 +97,7 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(lookup_bad_search_option, Config) ->
Db = inet_db,
Key = res_lookup,
- %% The bad option can not enter through inet_db:set_lookup/1,
+ %% The bad option cannot enter through inet_db:set_lookup/1,
%% but through e.g .inetrc.
Prev = ets:lookup(Db, Key),
ets:delete(Db, Key),
@@ -1060,28 +1060,26 @@ getservbyname_overflow(Config) when is_list(Config) ->
getifaddrs(Config) when is_list (Config) ->
{ok,IfAddrs} = inet:getifaddrs(),
io:format("IfAddrs = ~p.~n", [IfAddrs]),
- case
- {os:type(),
- [If ||
- {If,Opts} <- IfAddrs,
- lists:keymember(hwaddr, 1, Opts)]} of
- {{unix,sunos},[]} -> ok;
- {OT,[]} ->
- ct:fail({should_have_hwaddr,OT});
- _ -> ok
+ case [If || {If,Opts} <- IfAddrs, lists:keymember(hwaddr, 1, Opts)] of
+ [] ->
+ case os:type() of
+ {unix,sunos} -> ok;
+ OT ->
+ ct:fail({should_have_hwaddr,OT})
+ end;
+ [_|_] -> ok
end,
- Addrs =
- [element(1, A) || A <- ifaddrs(IfAddrs)],
+ Addrs = ifaddrs(IfAddrs),
io:format("Addrs = ~p.~n", [Addrs]),
[check_addr(Addr) || Addr <- Addrs],
ok.
-check_addr({addr,Addr})
+check_addr(Addr)
when tuple_size(Addr) =:= 8,
element(1, Addr) band 16#FFC0 =:= 16#FE80 ->
io:format("Addr: ~p link local; SKIPPED!~n", [Addr]),
ok;
-check_addr({addr,Addr}) ->
+check_addr(Addr) ->
io:format("Addr: ~p.~n", [Addr]),
Ping = "ping",
Pong = "pong",
@@ -1097,78 +1095,86 @@ check_addr({addr,Addr}) ->
ok = gen_tcp:close(S2),
ok = gen_tcp:close(L).
--record(ifopts, {name,flags,addrs=[],hwaddr}).
-
-ifaddrs([]) -> [];
-ifaddrs([{If,Opts}|IOs]) ->
- #ifopts{flags=F} = Ifopts = check_ifopts(Opts, #ifopts{name=If}),
- case F of
- {flags,Flags} ->
- case lists:member(running, Flags) of
- true -> Ifopts#ifopts.addrs;
- false -> []
- end ++ ifaddrs(IOs);
- undefined ->
- ifaddrs(IOs)
+ifaddrs(IfOpts) ->
+ IfMap = collect_ifopts(IfOpts),
+ ChkFun =
+ fun Self({{_,Flags} = Key, Opts}, ok) ->
+ Broadcast = lists:member(broadcast, Flags),
+ P2P = lists:member(pointtopoint, Flags),
+ case Opts of
+ [{addr,_},{netmask,_},{broadaddr,_}|Os]
+ when Broadcast ->
+ Self({Key, Os}, ok);
+ [{addr,_},{netmask,_},{dstaddr,_}|Os]
+ when P2P ->
+ Self({Key, Os}, ok);
+ [{addr,_},{netmask,_}|Os] ->
+ Self({Key, Os}, ok);
+ [{hwaddr,_}|Os] ->
+ Self({Key, Os}, ok);
+ [] ->
+ ok
+ end
+ end,
+ fold_ifopts(ChkFun, ok, IfMap),
+ AddrsFun =
+ fun ({{_,Flags}, Opts}, Acc) ->
+ case
+ lists:member(running, Flags)
+ andalso (not lists:member(pointtopoint, Flags))
+ of
+ true ->
+ lists:reverse(
+ [Addr || {addr,Addr} <- Opts],
+ Acc);
+ false ->
+ Acc
+ end
+ end,
+ fold_ifopts(AddrsFun, [], IfMap).
+
+collect_ifopts(IfOpts) ->
+ collect_ifopts(IfOpts, #{}).
+%%
+collect_ifopts(IfOpts, IfMap) ->
+ case IfOpts of
+ [{If,[{flags,Flags}|Opts]}|IfOs] ->
+ Key = {If,Flags},
+ case maps:is_key(Key, IfMap) of
+ true ->
+ ct:fail({unexpected_ifopts,IfOpts,IfMap});
+ false ->
+ collect_ifopts(IfOs, IfMap, Opts, Key, [])
+ end;
+ [] ->
+ IfMap;
+ _ ->
+ ct:fail({unexpected_ifopts,IfOpts,IfMap})
+ end.
+%%
+collect_ifopts(IfOpts, IfMap, Opts, Key, R) ->
+ case Opts of
+ [{flags,_}|_] ->
+ {If,_} = Key,
+ collect_ifopts(
+ [{If,Opts}|IfOpts], maps:put(Key, lists:reverse(R), IfMap));
+ [OptVal|Os] ->
+ collect_ifopts(IfOpts, IfMap, Os, Key, [OptVal|R]);
+ [] ->
+ collect_ifopts(IfOpts, maps:put(Key, lists:reverse(R), IfMap))
end.
-check_ifopts([], #ifopts{flags=F,addrs=Raddrs}=Ifopts) ->
- Addrs = lists:reverse(Raddrs),
- R = Ifopts#ifopts{addrs=Addrs},
- io:format("~p.~n", [R]),
- %% See how we did...
- {flags,Flags} = F,
- case lists:member(broadcast, Flags) of
- true ->
- [case A of
- {{addr,_},{netmask,_},{broadaddr,_}} ->
- A;
- {{addr,T},{netmask,_}} when tuple_size(T) =:= 8 ->
- A
- end || A <- Addrs];
- false ->
- case lists:member(pointtopoint, Flags) of
- true ->
- [case A of
- {{addr,_},{netmask,_},{dstaddr,_}} ->
- A
- end || A <- Addrs];
- false ->
- [case A of
- {{addr,_},{netmask,_}} ->
- A
- end || A <- Addrs]
- end
- end,
- R;
-check_ifopts([{flags,_}=F|Opts], #ifopts{flags=undefined}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{flags=F});
-check_ifopts([{flags,_}=F|Opts], #ifopts{flags=Flags}=Ifopts) ->
- case F of
- Flags ->
- check_ifopts(Opts, Ifopts);
- _ ->
- ct:fail({multiple_flags,F,Ifopts})
- end;
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N,{dstaddr,_}=D|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,D}|Addrs]});
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N,{broadaddr,_}=B|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N,B}|Addrs]});
-check_ifopts(
- [{addr,_}=A,{netmask,_}=N|Opts],
- #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A,N}|Addrs]});
-check_ifopts([{addr,_}=A|Opts], #ifopts{addrs=Addrs}=Ifopts) ->
- check_ifopts(Opts, Ifopts#ifopts{addrs=[{A}|Addrs]});
-check_ifopts([{hwaddr,Hwaddr}=H|Opts], #ifopts{hwaddr=undefined}=Ifopts)
- when is_list(Hwaddr) ->
- check_ifopts(Opts, Ifopts#ifopts{hwaddr=H});
-check_ifopts([{hwaddr,_}=H|_], #ifopts{}=Ifopts) ->
- ct:fail({multiple_hwaddrs,H,Ifopts}).
+fold_ifopts(Fun, Acc, IfMap) ->
+ fold_ifopts(Fun, Acc, IfMap, maps:keys(IfMap)).
+%%
+fold_ifopts(Fun, Acc, IfMap, Keys) ->
+ case Keys of
+ [Key|Ks] ->
+ Opts = maps:get(Key, IfMap),
+ fold_ifopts(Fun, Fun({Key,Opts}, Acc), IfMap, Ks);
+ [] ->
+ Acc
+ end.
%% Works just like lists:member/2, except that any {127,_,_,_} tuple
%% matches any other {127,_,_,_}. We do this to handle Linux systems
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index df6e48abae..cbec8d430c 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -531,7 +531,7 @@ edns0(Config) when is_list(Config) ->
case os:version() of
{M,V,_} when M < 5; M == 5, V =< 8 ->
%% In our test park only known platform
- %% with an DNS resolver that can not do
+ %% with an DNS resolver that cannot do
%% EDNS0.
{comment,"No EDNS0"}
end
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
index ada9c2689c..27ff74e309 100644
--- a/lib/kernel/test/inet_sockopt_SUITE.erl
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -110,9 +110,14 @@ simple(Config) when is_list(Config) ->
{S1,S2} = create_socketpair(Opt, Opt),
{ok,Opt} = inet:getopts(S1,OptTags),
{ok,Opt} = inet:getopts(S2,OptTags),
- COpt = [{X,case X of nodelay -> false;_ -> Y end} || {X,Y} <- Opt],
+ NoPushOpt = case os:type() of
+ {unix, Osname} when Osname =:= linux; Osname =:= freebsd -> {nopush, true};
+ {_,_} -> {nopush, false}
+ end,
+ COpt = [{X,case X of nodelay -> false;_ -> Y end} || {X,Y} <- [NoPushOpt|Opt]],
+ COptTags = [X || {X,_} <- COpt],
inet:setopts(S1,COpt),
- {ok,COpt} = inet:getopts(S1,OptTags),
+ {ok,COpt} = inet:getopts(S1,COptTags),
{ok,Opt} = inet:getopts(S2,OptTags),
gen_tcp:close(S1),
gen_tcp:close(S2),
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index 6a006cdc01..7828cc4716 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -451,7 +451,7 @@ find_system_procs([], SysProcs) ->
SysProcs#sys_procs.dirty_sig_handler_max];
find_system_procs([P|Ps], SysProcs) ->
case process_info(P, [initial_call, priority]) of
- [{initial_call,{otp_ring0,start,2}},_] ->
+ [{initial_call,{erl_init,start,2}},_] ->
undefined = SysProcs#sys_procs.init,
find_system_procs(Ps, SysProcs#sys_procs{init = P});
[{initial_call,{erts_code_purger,start,0}},_] ->
diff --git a/lib/kernel/test/logger_SUITE.erl b/lib/kernel/test/logger_SUITE.erl
index 8f74ebdc47..d831d0d108 100644
--- a/lib/kernel/test/logger_SUITE.erl
+++ b/lib/kernel/test/logger_SUITE.erl
@@ -37,7 +37,8 @@
suite() ->
- [{timetrap,{seconds,30}}].
+ [{timetrap,{seconds,30}},
+ {ct_hooks,[logger_test_lib]}].
init_per_suite(Config) ->
case logger:get_handler_config(?STANDARD_HANDLER) of
@@ -87,6 +88,7 @@ all() ->
macros,
set_level,
set_module_level,
+ set_application_level,
cache_module_level,
format_report,
filter_failed,
@@ -97,7 +99,9 @@ all() ->
via_logger_process,
other_node,
compare_levels,
- process_metadata].
+ process_metadata,
+ app_config,
+ kernel_config].
start_stop(_Config) ->
S = whereis(logger),
@@ -210,6 +214,7 @@ add_remove_filter(cleanup,_Config) ->
change_config(_Config) ->
%% Overwrite handler config - check that defaults are added
+ {error,{not_found,h1}} = logger:set_handler_config(h1,#{}),
ok = logger:add_handler(h1,?MODULE,#{level=>notice,custom=>custom}),
{ok,#{module:=?MODULE,level:=notice,filter_default:=log,custom:=custom}} =
logger:get_handler_config(h1),
@@ -241,6 +246,18 @@ change_config(_Config) ->
{ok,C4} = logger:get_handler_config(h1),
C4 = C3#{custom:=new_custom},
+ %% Change handler config: Id and module can not be changed
+ {error,{illegal_config_change,Old,New}} =
+ logger:set_handler_config(h1,id,newid),
+ %% Check that only the faulty field is included in return
+ [{id,h1}] = maps:to_list(Old),
+ [{id,newid}] = maps:to_list(New),
+ %% Check that both fields are included when both are changed
+ {error,{illegal_config_change,
+ #{id:=h1,module:=?MODULE},
+ #{id:=newid,module:=newmodule}}} =
+ logger:set_handler_config(h1,#{id=>newid,module=>newmodule}),
+
%% Change primary config: Single key
PConfig0 = logger:get_primary_config(),
ok = logger:set_primary_config(level,warning),
@@ -258,7 +275,7 @@ change_config(_Config) ->
logger:get_primary_config(),
3 = maps:size(PC1),
%% Check that internal 'handlers' field has not been changed
- MS = [{{{?HANDLER_KEY,'$1'},'_','_','_'},[],['$1']}],
+ MS = [{{{?HANDLER_KEY,'$1'},'_','_'},[],['$1']}],
HIds1 = lists:sort(ets:select(?LOGGER_TABLE,MS)), % dirty, internal data
HIds2 = lists:sort(logger:get_handler_ids()),
HIds1 = HIds2,
@@ -388,6 +405,8 @@ set_module_level(_Config) ->
{error,{invalid_level,bad}} = logger:set_module_level(?MODULE,bad),
{error,{not_a_list_of_modules,{bad}}} =
logger:set_module_level({bad},warning),
+ {error,{not_a_list_of_modules,[{bad}]}} =
+ logger:set_module_level([{bad}],warning),
ok = logger:set_module_level(?MODULE,warning),
[{?MODULE,warning}] = logger:get_module_level([?MODULE,other]),
[{?MODULE,warning}] = logger:get_module_level(?MODULE),
@@ -404,6 +423,7 @@ set_module_level(_Config) ->
ok = check_logged(notice,M2,?MY_LOC(1)),
{error,{not_a_list_of_modules,{bad}}} = logger:unset_module_level({bad}),
+ {error,{not_a_list_of_modules,[{bad}]}} = logger:unset_module_level([{bad}]),
ok = logger:unset_module_level(?MODULE),
[] = logger:get_module_level([?MODULE,other]),
[] = logger:get_module_level(?MODULE),
@@ -423,6 +443,39 @@ set_module_level(cleanup,_Config) ->
logger:unset_module_level(?MODULE),
ok.
+set_application_level(_Config) ->
+
+ {error,{not_loaded,mnesia}} = logger:set_application_level(mnesia, warning),
+ {error,{not_loaded,mnesia}} = logger:unset_application_level(mnesia),
+
+ case application:load(mnesia) of
+ ok ->
+ {ok, Modules} = application:get_key(mnesia, modules),
+ [] = logger:get_module_level(Modules),
+
+ {error,{invalid_level,warn}} =
+ logger:set_application_level(mnesia, warn),
+
+ ok = logger:set_application_level(mnesia, debug),
+ DebugModules = lists:sort([{M,debug} || M <- Modules]),
+ DebugModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:set_application_level(mnesia, warning),
+
+ WarnModules = lists:sort([{M,warning} || M <- Modules]),
+ WarnModules = lists:sort(logger:get_module_level(Modules)),
+
+ ok = logger:unset_application_level(mnesia),
+ [] = logger:get_module_level(Modules);
+ {error,{"no such file or directory","mnesia.app"}} ->
+ {skip, "Cannot load mnesia, does not exist"}
+ end.
+
+set_application_level(cleanup,_Config) ->
+ _ = logger:unset_application_level(mnesia),
+ _ = application:unload(mnesia),
+ ok.
+
cache_module_level(_Config) ->
ok = logger:unset_module_level(?MODULE),
[] = ets:lookup(?LOGGER_TABLE,?MODULE), %dirty - add API in logger_config?
@@ -518,7 +571,7 @@ handler_failed(_Config) ->
register(callback_receiver,self()),
{error,{invalid_id,1}} = logger:add_handler(1,?MODULE,#{}),
{error,{invalid_module,"nomodule"}} = logger:add_handler(h1,"nomodule",#{}),
- {error,{invalid_handler_config,bad}} = logger:add_handler(h1,?MODULE,bad),
+ {error,{invalid_config,bad}} = logger:add_handler(h1,?MODULE,bad),
{error,{invalid_filters,false}} =
logger:add_handler(h1,?MODULE,#{filters=>false}),
{error,{invalid_filter_default,true}} =
@@ -593,7 +646,8 @@ handler_failed(cleanup,_Config) ->
ok.
config_sanity_check(_Config) ->
- %% Logger config
+ %% Primary config
+ {error,{invalid_config,bad}} = logger:set_primary_config(bad),
{error,{invalid_filter_default,bad}} =
logger:set_primary_config(filter_default,bad),
{error,{invalid_level,bad}} = logger:set_primary_config(level,bad),
@@ -866,12 +920,227 @@ process_metadata(_Config) ->
ok = logger:unset_process_metadata(),
undefined = logger:get_process_metadata(),
+ ok = logger:update_process_metadata(#{custom=>added_again}),
+ {error,badarg} = ?TRY(logger:update_process_metadata(bad)),
+ #{custom:=added_again} = logger:get_process_metadata(),
+
ok.
process_metadata(cleanup,_Config) ->
logger:remove_handler(h1),
ok.
+app_config(Config) ->
+ %% Start a node with default configuration
+ {ok,_,Node} = logger_test_lib:setup(Config,[]),
+
+ App1Name = app1,
+ App1 = {application, App1Name,
+ [{description, "Test of app with logger config"},
+ {applications, [kernel]}]},
+ ok = rpc:call(Node,application,load,[App1]),
+ ok = rpc:call(Node,application,set_env,
+ [App1Name,logger,[{handler,default,logger_std_h,#{}}]]),
+
+ %% Try to add an own default handler
+ {error,{bad_config,{handler,{app1,{already_exist,default}}}}} =
+ rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ %% Add a different handler
+ ok = rpc:call(Node,application,set_env,[App1Name,logger,
+ [{handler,myh,logger_std_h,#{}}]]),
+ ok = rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ {ok,#{filters:=DF}} = rpc:call(Node,logger,get_handler_config,[default]),
+ {ok,#{filters:=[]}} = rpc:call(Node,logger,get_handler_config,[myh]),
+
+ true = test_server:stop_node(Node),
+
+ %% Start a node with no default handler, then add an own default handler
+ {ok,#{handlers:=[#{id:=simple}]},Node} =
+ logger_test_lib:setup(Config,[{logger,[{handler,default,undefined}]}]),
+
+ ok = rpc:call(Node,application,load,[App1]),
+ ok = rpc:call(Node,application,set_env,
+ [App1Name,logger,[{handler,default,logger_std_h,#{}}]]),
+ ok = rpc:call(Node,logger,add_handlers,[App1Name]),
+
+ #{handlers:=[#{id:=default,filters:=DF}]} =
+ rpc:call(Node,logger,get_config,[]),
+
+ true = test_server:stop_node(Node),
+
+ %% Start a silent node, then add an own default handler
+ {ok,#{handlers:=[]},Node} =
+ logger_test_lib:setup(Config,[{error_logger,silent}]),
+
+ {error,{bad_config,{handler,[{some,bad,config}]}}} =
+ rpc:call(Node,logger,add_handlers,[[{some,bad,config}]]),
+ ok = rpc:call(Node,logger,add_handlers,
+ [[{handler,default,logger_std_h,#{}}]]),
+
+ #{handlers:=[#{id:=default,filters:=DF}]} =
+ rpc:call(Node,logger,get_config,[]),
+
+ ok.
+
+%% This test case is maintly to see code coverage. Note that
+%% logger_env_var_SUITE tests a lot of the same, and checks the
+%% functionality more thoroughly, but since it all happens at node
+%% start, it is not possible to see code coverage in that test.
+kernel_config(Config) ->
+ %% Start a node with simple handler only, then simulate kernel
+ %% start by calling internally exported
+ %% internal_init_logger(). This is to test all variants of kernel
+ %% config, including bad config, and see the code coverage.
+ {ok,#{handlers:=[#{id:=simple,filters:=DF}]}=LC,Node} =
+ logger_test_lib:setup(Config,[{error_logger,false}]),
+
+ %% Same once more, to get coverage
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ LC = rpc:call(Node,logger,get_config,[]),
+
+ %% This shall mean the same as above, but using 'logger' parameter
+ %% instead of 'error_logger'
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{handler,default,undefined}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ LC = rpc:call(Node,logger,get_config,[]),
+
+ %% Silent
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,silent]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Default
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% error_logger=tty (same as default)
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,tty]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:=standard_io}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% error_logger={file,File}
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ F = filename:join(?config(priv_dir,Config),
+ atom_to_list(?FUNCTION_NAME)++".log"),
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,{file,F}]),
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:={file,F}}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Same, but using 'logger' parameter instead of 'error_logger'
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_std_h,
+ #{config=>#{type=>{file,F}}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:={file,F}}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Same, but with type={file,File,Modes}
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ M = [raw,write,delayed_write],
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_std_h,
+ #{config=>#{type=>{file,F,M}}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{type:={file,F,M}}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Same, but with disk_log handler
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ M = [raw,write,delayed_write],
+ ok = rpc:call(Node,application,set_env,[kernel,logger,
+ [{handler,default,logger_disk_log_h,
+ #{config=>#{file=>F}}}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=log,filters:=[]},
+ handlers:=[#{id:=default,filters:=DF,config:=#{file:=F}}],
+ module_levels:=[]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Set primary filters and module level. No default handler.
+ ok = rpc:call(Node,logger,remove_handler,[default]),% so it can be added again
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{handler,default,undefined},
+ {filters,stop,[{f1,{fun(_,_) -> log end,ok}}]},
+ {module_level,debug,[?MODULE]}]]),
+ ok = rpc:call(Node,logger,internal_init_logger,[]),
+ ok = rpc:call(Node,logger,add_handlers,[kernel]),
+ #{primary:=#{filter_default:=stop,filters:=[_]},
+ handlers:=[],
+ module_levels:=[{?MODULE,debug}]} = rpc:call(Node,logger,get_config,[]),
+
+ %% Bad config
+ ok = rpc:call(Node,application,unset_env,[kernel,logger]),
+
+ ok = rpc:call(Node,application,set_env,[kernel,error_logger,bad]),
+ {error,{bad_config,{kernel,{error_logger,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,unset_env,[kernel,error_logger]),
+ ok = rpc:call(Node,application,set_env,[kernel,logger_level,bad]),
+ {error,{bad_config,{kernel,{logger_level,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,unset_env,[kernel,logger_level]),
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[bad]}]]),
+ {error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[bad]}]]),
+ {error,{bad_config,{kernel,{invalid_filters,[bad]}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{filters,stop,[{f1,bad}]}]]),
+ {error,{bad_config,{kernel,{invalid_filter,{f1,bad}}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,MF=[{filters,stop,[]},{filters,log,[]}]]),
+ {error,{bad_config,{kernel,{multiple_filters,MF}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok = rpc:call(Node,application,set_env,
+ [kernel,logger,[{module_level,bad,[?MODULE]}]]),
+ {error,{bad_config,{kernel,{invalid_level,bad}}}} =
+ rpc:call(Node,logger,internal_init_logger,[]),
+
+ ok.
+
%%%-----------------------------------------------------------------
%%% Internal
check_logged(Level,Format,Args,Meta) ->
diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl
index a4b15c841b..905c2c52c5 100644
--- a/lib/kernel/test/logger_disk_log_h_SUITE.erl
+++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl
@@ -92,6 +92,7 @@ all() ->
disk_log_opts,
default_formatter,
logging,
+ filter_config,
errors,
formatter_fail,
config_fail,
@@ -302,6 +303,20 @@ logging(cleanup, _Config) ->
Name = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
remove_and_stop(Name).
+filter_config(_Config) ->
+ ok = logger:add_handler(?MODULE,logger_disk_log_h,#{}),
+ {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE),
+ HConfig = maps:without([handler_pid,mode_tab],HConfig),
+
+ FakeFullHConfig = HConfig#{handler_pid=>self(),mode_tab=>erlang:make_ref()},
+ #{config:=HConfig} =
+ logger_disk_log_h:filter_config(Config#{config=>FakeFullHConfig}),
+ ok.
+
+filter_config(cleanup,_Config) ->
+ logger:remove_handler(?MODULE),
+ ok.
+
errors(Config) ->
PrivDir = ?config(priv_dir,Config),
Name1 = list_to_atom(lists:concat([?FUNCTION_NAME,"_1"])),
@@ -316,13 +331,29 @@ errors(Config) ->
%%! TODO:
%%! Check how bad log_opts are handled!
- {error,{illegal_config_change,_,_}} =
- logger:set_handler_config(Name1,
- config,
- #{file=>LogFile1,
- type=>halt}),
- {error,{illegal_config_change,_,_}} =
- logger:set_handler_config(Name1,id,new),
+ {error,{illegal_config_change,
+ #{config:=#{type:=wrap}},
+ #{config:=#{type:=halt}}}} =
+ logger:update_handler_config(Name1,
+ config,
+ #{type=>halt,
+ file=>LogFile1}),
+
+ {error,{illegal_config_change,
+ #{config:=#{file:=LogFile1}},
+ #{config:=#{file:="newfilename"}}}} =
+ logger:update_handler_config(Name1,
+ config,
+ #{file=>"newfilename"}),
+
+ %% Read-only fields may (accidentially) be included in the change,
+ %% but it won't take effect
+ {ok,C} = logger:get_handler_config(Name1),
+ ok = logger:set_handler_config(Name1,config,
+ #{handler_pid=>self(),
+ mode_tab=>erlang:make_ref()}),
+ {ok,C} = logger:get_handler_config(Name1),
+
ok = logger:remove_handler(Name1),
{error,{not_found,Name1}} = logger:remove_handler(Name1),
@@ -367,7 +398,7 @@ formatter_fail(Config) ->
ok = logger:set_handler_config(Name,formatter,{?MODULE,bad_return}),
logger:notice(?msg,?domain),
try_match_file(?log_no(LogFile,1),
- escape(Got3)++"FORMATTER ERROR: bad_return_value",
+ escape(Got3)++"FORMATTER ERROR: bad return value",
5000),
%% Check that handler is still alive and was never dead
@@ -403,21 +434,21 @@ config_fail(_Config) ->
formatter=>{?MODULE,self()}}),
%% can't change the disk log options for a log already in use
{error,{illegal_config_change,_,_}} =
- logger:set_handler_config(?MODULE,config,
- #{max_no_files=>2}),
+ logger:update_handler_config(?MODULE,config,
+ #{max_no_files=>2}),
%% can't change name of an existing handler
{error,{illegal_config_change,_,_}} =
- logger:set_handler_config(?MODULE,id,bad),
+ logger:update_handler_config(?MODULE,id,bad),
%% incorrect values of OP params
{ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
{error,{invalid_levels,_}} =
- logger:set_handler_config(?MODULE,config,
- HConfig#{sync_mode_qlen=>100,
- flush_qlen=>99}),
+ logger:update_handler_config(?MODULE,config,
+ HConfig#{sync_mode_qlen=>100,
+ flush_qlen=>99}),
%% invalid name of config parameter
{error,{invalid_config,logger_disk_log_h,{filesync_rep_int,2000}}} =
- logger:set_handler_config(?MODULE, config,
- HConfig#{filesync_rep_int => 2000}),
+ logger:update_handler_config(?MODULE, config,
+ HConfig#{filesync_rep_int => 2000}),
ok.
config_fail(cleanup,_Config) ->
logger:remove_handler(?MODULE).
@@ -459,10 +490,26 @@ reconfig(Config) ->
log_opts := #{type := ?DISK_LOG_TYPE,
max_no_files := ?DISK_LOG_MAX_NO_FILES,
max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
- file := _DiskLogFile}} =
+ file := DiskLogFile}} =
logger_disk_log_h:info(?MODULE),
+ {ok,#{config :=
+ #{sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
+ filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL,
+ file := DiskLogFile,
+ max_no_files := ?DISK_LOG_MAX_NO_FILES,
+ max_no_bytes := ?DISK_LOG_MAX_NO_BYTES,
+ type := wrap} = HConfig0}} =
+ logger:get_handler_config(?MODULE),
- {ok,#{config := HConfig0}} = logger:get_handler_config(?MODULE),
HConfig1 = HConfig0#{sync_mode_qlen => 1,
drop_mode_qlen => 2,
flush_qlen => 3,
@@ -488,6 +535,29 @@ reconfig(Config) ->
overload_kill_restart_after := infinity,
filesync_repeat_interval := no_repeat} =
logger_disk_log_h:info(?MODULE),
+ {ok,#{config:=HConfig1}} = logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, config,
+ #{flush_qlen => ?FLUSH_QLEN}),
+ {ok,#{config:=C1}} = logger:get_handler_config(?MODULE),
+ ct:log("C1: ~p",[C1]),
+ C1 = HConfig1#{flush_qlen => ?FLUSH_QLEN},
+
+ ok = logger:set_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C2}} = logger:get_handler_config(?MODULE),
+ ct:log("C2: ~p",[C2]),
+ C2 = HConfig0#{sync_mode_qlen => 1},
+
+ ok = logger:set_handler_config(?MODULE, config, #{drop_mode_qlen => 100}),
+ {ok,#{config:=C3}} = logger:get_handler_config(?MODULE),
+ ct:log("C3: ~p",[C3]),
+ C3 = HConfig0#{drop_mode_qlen => 100},
+
+ ok = logger:update_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C4}} = logger:get_handler_config(?MODULE),
+ ct:log("C4: ~p",[C4]),
+ C4 = HConfig0#{sync_mode_qlen => 1,
+ drop_mode_qlen => 100},
ok = logger:remove_handler(?MODULE),
@@ -507,6 +577,43 @@ reconfig(Config) ->
max_no_bytes := 1024,
file := File}} =
logger_disk_log_h:info(?MODULE),
+ {ok,#{config :=
+ #{type := halt,
+ max_no_files := 1,
+ max_no_bytes := 1024,
+ file := File}=HaltHConfig} = Config2} =
+ logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, level, notice),
+ {ok,C5} = logger:get_handler_config(?MODULE),
+ ct:log("C5: ~p",[C5]),
+ C5 = Config2#{level => notice},
+
+ ok = logger:set_handler_config(?MODULE, level, info),
+ {ok,C6} = logger:get_handler_config(?MODULE),
+ ct:log("C6: ~p",[C6]),
+ C6 = Config2#{level => info},
+
+ %% You are not allowed to actively set the write once fields
+ %% (type, max_no_files, max_no_bytes, file) in runtime.
+ {error, {illegal_config_change,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{type=>wrap}),
+ {error, {illegal_config_change,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{max_no_files=>2}),
+ {error, {illegal_config_change,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{max_no_bytes=>2048}),
+ {error, {illegal_config_change,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{file=>"otherfile.log"}),
+ {ok,C7} = logger:get_handler_config(?MODULE),
+ ct:log("C7: ~p",[C7]),
+ C7 = C6,
+
+ %% ... but if you don't specify the write once fields, then
+ %% set_handler_config shall NOT reset them to their default value
+ ok = logger:set_handler_config(?MODULE,config,#{sync_mode_qlen=>1}),
+ {ok,#{config:=C8}} = logger:get_handler_config(?MODULE),
+ ct:log("C8: ~p",[C8]),
+ C8 = HaltHConfig#{sync_mode_qlen=>1},
ok.
reconfig(cleanup, _Config) ->
@@ -524,49 +631,41 @@ sync(Config) ->
formatter=>{?MODULE,nl}}),
start_tracer([{disk_log,blog,2},
- {disk_log,sync,1}],
+ {logger_disk_log_h,disk_log_sync,2}],
[{disk_log,blog,<<"first\n">>},
- {disk_log,sync}]),
+ {logger_disk_log_h,disk_log_sync}]),
logger:notice("first", ?domain),
%% wait for automatic disk_log_sync
check_tracer(?FILESYNC_REPEAT_INTERVAL*2),
- start_tracer([{disk_log,blog,2},
- {disk_log,sync,1}],
- [{disk_log,blog,<<"second\n">>},
- {disk_log,blog,<<"third\n">>},
- {disk_log,sync}]),
- %% two log requests in fast succession will make the handler skip
- %% an automatic disk log sync
- logger:notice("second", ?domain),
- logger:notice("third", ?domain),
- %% do explicit sync
- logger_disk_log_h:filesync(?MODULE),
- check_tracer(100),
-
%% check that if there's no repeated disk_log_sync active,
%% a disk_log_sync is still performed when handler goes idle
{ok,#{config := HConfig}} = logger:get_handler_config(?MODULE),
HConfig1 = HConfig#{filesync_repeat_interval => no_repeat},
- ok = logger:set_handler_config(?MODULE, config, HConfig1),
+ ok = logger:update_handler_config(?MODULE, config, HConfig1),
no_repeat = maps:get(filesync_repeat_interval,
logger_disk_log_h:info(?MODULE)),
+ %% The following timer is to make sure the time from last log
+ %% ("first") to next ("second") is long enough, so the a flush is
+ %% triggered by the idle timeout between "fourth" and "fifth".
+ timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
start_tracer([{disk_log,blog,2},
- {disk_log,sync,1}],
- [{disk_log,blog,<<"fourth\n">>},
- {disk_log,blog,<<"fifth\n">>},
- {disk_log,sync}]),
+ {logger_disk_log_h,disk_log_sync,2}],
+ [{disk_log,blog,<<"second\n">>},
+ {logger_disk_log_h,disk_log_sync},
+ {disk_log,blog,<<"third\n">>},
+ {logger_disk_log_h,disk_log_sync}]),
- logger:notice("fourth", ?domain),
+ logger:notice("second", ?domain),
timer:sleep(?IDLE_DETECT_TIME_MSEC*2),
- logger:notice("fifth", ?domain),
+ logger:notice("third", ?domain),
%% wait for automatic disk_log_sync
check_tracer(?IDLE_DETECT_TIME_MSEC*2),
- try_read_file(Log, {ok,<<"first\nsecond\nthird\nfourth\nfifth\n">>}, 1000),
+ try_read_file(Log, {ok,<<"first\nsecond\nthird\n">>}, 1000),
%% switch repeated disk_log_sync on and verify that the looping works
SyncInt = 1000,
@@ -577,13 +676,13 @@ sync(Config) ->
[OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
HConfig2 = HConfig#{filesync_repeat_interval => SyncInt},
- ok = logger:set_handler_config(?MODULE, config, HConfig2),
+ ok = logger:update_handler_config(?MODULE, config, HConfig2),
SyncInt = maps:get(filesync_repeat_interval,
logger_disk_log_h:info(?MODULE)),
timer:sleep(WaitT),
HConfig3 = HConfig#{filesync_repeat_interval => no_repeat},
- ok = logger:set_handler_config(?MODULE, config, HConfig3),
+ ok = logger:update_handler_config(?MODULE, config, HConfig3),
check_tracer(100),
ok.
sync(cleanup,_Config) ->
@@ -805,7 +904,7 @@ sync_failure(Config) ->
LogOpts = maps:get(log_opts, HState),
SyncInt = 500,
- ok = rpc:call(Node, logger, set_handler_config,
+ ok = rpc:call(Node, logger, update_handler_config,
[?STANDARD_HANDLER, config,
#{filesync_repeat_interval => SyncInt}]),
Info = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]),
@@ -880,7 +979,7 @@ op_switch_to_sync(Config) ->
drop_mode_qlen => NumOfReqs+1,
flush_qlen => 2*NumOfReqs,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Lines = count_lines(Log),
NumOfReqs = Lines,
@@ -905,7 +1004,7 @@ op_switch_to_drop(Config) ->
drop_mode_qlen => 2,
flush_qlen => Procs*NumOfReqs*Bursts,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
%% It sometimes happens that the handler either gets
%% the requests in a slow enough pace so that dropping
%% never occurs. Therefore, lets generate a number of
@@ -951,7 +1050,7 @@ op_switch_to_flush(Config) ->
drop_mode_qlen => 300,
flush_qlen => 300,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 1500,
Procs = 10,
Bursts = 10,
@@ -993,7 +1092,7 @@ limit_burst_disabled(Config) ->
burst_limit_window_time => 2000,
drop_mode_qlen => 200,
flush_qlen => 300}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -1013,7 +1112,7 @@ limit_burst_enabled_one(Config) ->
burst_limit_window_time => 2000,
drop_mode_qlen => 200,
flush_qlen => 300}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -1034,7 +1133,7 @@ limit_burst_enabled_period(Config) ->
burst_limit_window_time => BurstTWin,
drop_mode_qlen => 20000,
flush_qlen => 20001}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
Windows = 3,
Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
@@ -1054,7 +1153,7 @@ kill_disabled(Config) ->
HConfig#{config=>DLHConfig#{overload_kill_enable=>false,
overload_kill_qlen=>10,
overload_kill_mem_size=>100}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -1076,7 +1175,7 @@ qlen_kill_new(Config) ->
overload_kill_qlen=>10,
overload_kill_mem_size=>Mem0+50000,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
Procs = 4,
@@ -1113,7 +1212,7 @@ mem_kill_new(Config) ->
overload_kill_qlen=>50000,
overload_kill_mem_size=>Mem0+500,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
Procs = 4,
@@ -1147,7 +1246,7 @@ restart_after(Config) ->
HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
overload_kill_qlen=>10,
overload_kill_restart_after=>infinity}},
- ok = logger:set_handler_config(?MODULE, NewHConfig1),
+ ok = logger:update_handler_config(?MODULE, NewHConfig1),
MRef1 = erlang:monitor(process, whereis(h_proc_name())),
%% kill handler
send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
@@ -1169,7 +1268,7 @@ restart_after(Config) ->
HConfig#{config=>DLHConfig#{overload_kill_enable=>true,
overload_kill_qlen=>10,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig2),
+ ok = logger:update_handler_config(?MODULE, NewHConfig2),
Pid0 = whereis(h_proc_name()),
MRef2 = erlang:monitor(process, Pid0),
%% kill handler
@@ -1194,7 +1293,7 @@ restart_after(cleanup, _Config) ->
%% during high load to verify that sync, dropping and flushing is
%% handled correctly.
handler_requests_under_load() ->
- [{timetrap,{minutes,3}}].
+ [{timetrap,{minutes,5}}].
handler_requests_under_load(Config) ->
{Log,HConfig,DLHConfig} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
NewHConfig =
@@ -1202,7 +1301,7 @@ handler_requests_under_load(Config) ->
drop_mode_qlen => 1000,
flush_qlen => 2000,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]},
{info,[]},
{reset,[]},
@@ -1235,9 +1334,9 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
Result =
case Req of
change_config ->
- logger:set_handler_config(HName, logger_disk_log_h,
- #{overload_kill_enable =>
- false});
+ logger:update_handler_config(HName, logger_disk_log_h,
+ #{overload_kill_enable =>
+ false});
Func ->
logger_disk_log_h:Func(HName)
end,
@@ -1494,7 +1593,7 @@ start_tracer(Trace,Expected) ->
ok.
tpl([{M,F,A}|Trace]) ->
- {ok,Match} = dbg:tpl(M,F,A,[]),
+ {ok,Match} = dbg:tpl(M,F,A,c),
case lists:keyfind(matched,1,Match) of
{_,_,1} ->
ok;
@@ -1507,23 +1606,23 @@ tpl([{M,F,A}|Trace]) ->
tpl([]) ->
ok.
-tracer({trace,_,call,{logger_disk_log_h,handle_cast,[Op|_]}},
+tracer({trace,_,call,{logger_disk_log_h,handle_cast,[Op|_]},Caller},
{Pid,[{Mod,Func,Op}|Expected]}) ->
- maybe_tracer_done(Pid,Expected,{Mod,Func,Op});
-tracer({trace,_,call,{Mod=disk_log,Func=blog,[_,Data]}}, {Pid,[{Mod,Func,Data}|Expected]}) ->
- maybe_tracer_done(Pid,Expected,{Mod,Func,Data});
-tracer({trace,_,call,{Mod,Func,_}}, {Pid,[{Mod,Func}|Expected]}) ->
- maybe_tracer_done(Pid,Expected,{Mod,Func});
-tracer({trace,_,call,Call}, {Pid,Expected}) ->
- ct:log("Tracer got unexpected: ~p~nExpected: ~p~n",[Call,Expected]),
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Op},Caller);
+tracer({trace,_,call,{Mod=disk_log,Func=blog,[_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func,Data},Caller);
+tracer({trace,_,call,{Mod,Func,_},Caller}, {Pid,[{Mod,Func}|Expected]}) ->
+ maybe_tracer_done(Pid,Expected,{Mod,Func},Caller);
+tracer({trace,_,call,Call,Caller}, {Pid,Expected}) ->
+ ct:log("Tracer got unexpected: ~p~nCaller: ~p~nExpected: ~p~n",[Call,Caller,Expected]),
Pid ! {tracer_got_unexpected,Call,Expected},
{Pid,Expected}.
-maybe_tracer_done(Pid,[],Got) ->
- ct:log("Tracer got: ~p~n",[Got]),
+maybe_tracer_done(Pid,[],Got,Caller) ->
+ ct:log("Tracer got: ~p~nCaller: ~p~n",[Got,Caller]),
Pid ! tracer_done;
-maybe_tracer_done(Pid,Expected,Got) ->
- ct:log("Tracer got: ~p~n",[Got]),
+maybe_tracer_done(Pid,Expected,Got,Caller) ->
+ ct:log("Tracer got: ~p~nCaller: ~p~n",[Got,Caller]),
{Pid,Expected}.
check_tracer(T) ->
diff --git a/lib/kernel/test/logger_formatter_SUITE.erl b/lib/kernel/test/logger_formatter_SUITE.erl
index aa8dc42691..8c13f0f908 100644
--- a/lib/kernel/test/logger_formatter_SUITE.erl
+++ b/lib/kernel/test/logger_formatter_SUITE.erl
@@ -166,6 +166,56 @@ single_line(_Config) ->
" info:\nterm\n" = string:prefix(String2,ExpectedTimestamp),
String2 = format(info,{"~p",[term]},#{time=>Time},#{single_line=>bad}),
+
+
+ %% Test that no extra commas/spaces are added when removing
+ %% newlines, especially not after "=>" in a map association (as
+ %% was the case in OTP-21.0, when the only single_line adjustment
+ %% was done by regexp replacement of "\n" by ", ").
+ Prefix =
+ "Some characters to fill the line ------------------------------------- ",
+ String3 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>true}),
+ ct:log(String3),
+ match = re:run(String3,"\\[1,2,3,4,5,6,7,8,9,10\\]",[{capture,none}]),
+ match = re:run(String3,
+ "#{a => map,few => accociations,with => a}",
+ [{capture,none}]),
+
+ %% This part is added to make sure that the previous test made
+ %% sense, i.e. that there would actually be newlines inside the
+ %% list and map.
+ String4 = format(info,{"~s~p~n~s~p~n",[Prefix,
+ lists:seq(1,10),
+ Prefix,
+ #{a=>map,with=>a,few=>accociations}]},
+ #{time=>Time},
+ #{single_line=>false}),
+ ct:log(String4),
+ match = re:run(String4,"\\[1,2,3,\n",[global,{capture,none}]),
+ {match,Match4} = re:run(String4,"=>\n",[global,{capture,all}]),
+ 3 = length(Match4),
+
+ %% Test that big metadata fields do not get line breaks
+ String5 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>true,template=>[mymeta,"\n"]}),
+ ct:log(String5),
+ [_] = string:lexemes(String5,"\n"),
+
+ %% Ensure that the previous test made sense, i.e. that the
+ %% metadata field does produce multiple lines if
+ %% single_line==false.
+ String6 = format(info,"",
+ #{mymeta=>lists:seq(1,100)},
+ #{single_line=>false,template=>[mymeta,"\n"]}),
+ ct:log(String6),
+ [_,_|_] = string:lexemes(String6,"\n"),
+
ok.
template(_Config) ->
@@ -715,6 +765,8 @@ check_config(_Config) ->
%% Test that formatter config can be changed, and that the default
%% template is updated accordingly
update_config(_Config) ->
+ {error,{not_found,?MODULE}} = logger:update_formatter_config(?MODULE,#{}),
+
logger:add_handler_filter(default,silence,{fun(_,_) -> stop end,ok}),
ok = logger:add_handler(?MODULE,?MODULE,#{}),
D = lists:seq(1,1000),
@@ -767,6 +819,11 @@ update_config(_Config) ->
ct:log("~p",[C6]),
["=NOTICE REPORT==== "++_,_D6] = Lines6,
+ {error,{invalid_formatter_config,bad}} =
+ logger:update_formatter_config(?MODULE,bad),
+ {error,{invalid_formatter_config,logger_formatter,{depth,bad}}} =
+ logger:update_formatter_config(?MODULE,depth,bad),
+
ok.
update_config(cleanup,_Config) ->
diff --git a/lib/kernel/test/logger_simple_h_SUITE.erl b/lib/kernel/test/logger_simple_h_SUITE.erl
index 79e5c057ad..e0ad792bdb 100644
--- a/lib/kernel/test/logger_simple_h_SUITE.erl
+++ b/lib/kernel/test/logger_simple_h_SUITE.erl
@@ -117,8 +117,7 @@ replace_default(Config) ->
log(Node, critical, [?str,[?keyval_rep]]),
log(Node, notice, [["fake",string,"line:",?LINE]]),
- Env = rpc:call(Node, application, get_env, [kernel, logger, []]),
- ok = rpc:call(Node, logger, add_handlers, [Env]),
+ ok = rpc:call(Node, logger, add_handlers, [kernel]),
ok.
diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl
index 0930cd4211..b6a09f4980 100644
--- a/lib/kernel/test/logger_std_h_SUITE.erl
+++ b/lib/kernel/test/logger_std_h_SUITE.erl
@@ -108,6 +108,7 @@ all() ->
add_remove_instance_file1,
add_remove_instance_file2,
default_formatter,
+ filter_config,
errors,
formatter_fail,
config_fail,
@@ -204,6 +205,20 @@ default_formatter(_Config) ->
match = re:run(Msg,"=NOTICE REPORT====.*\n"++M1,[{capture,none}]),
ok.
+filter_config(_Config) ->
+ ok = logger:add_handler(?MODULE,logger_std_h,#{}),
+ {ok,#{config:=HConfig}=Config} = logger:get_handler_config(?MODULE),
+ HConfig = maps:without([handler_pid,mode_tab],HConfig),
+
+ FakeFullHConfig = HConfig#{handler_pid=>self(),mode_tab=>erlang:make_ref()},
+ #{config:=HConfig} =
+ logger_std_h:filter_config(Config#{config=>FakeFullHConfig}),
+ ok.
+
+filter_config(cleanup,_Config) ->
+ logger:remove_handler(?MODULE),
+ ok.
+
errors(Config) ->
Dir = ?config(priv_dir,Config),
Log = filename:join(Dir,?FUNCTION_NAME),
@@ -280,7 +295,7 @@ formatter_fail(Config) ->
ok = logger:set_handler_config(?MODULE,formatter,{?MODULE,bad_return}),
logger:notice(?msg,?domain),
try_match_file(Log,
- escape(Got3)++"FORMATTER ERROR: bad_return_value",
+ escape(Got3)++"FORMATTER ERROR: bad return value",
5000),
%% Check that handler is still alive and was never dead
@@ -319,11 +334,10 @@ config_fail(_Config) ->
ok = logger:add_handler(?MODULE,logger_std_h,
#{filter_default=>log,
formatter=>{?MODULE,self()}}),
- {error,{illegal_config_change,_,_}} =
+ {error,{illegal_config_change,#{config:=#{type:=_}},#{config:=#{type:=_}}}} =
logger:set_handler_config(?MODULE,config,
#{type=>{file,"file"}}),
- {error,{illegal_config_change,_,_}} =
- logger:set_handler_config(?MODULE,id,bad),
+
{error,{invalid_levels,_}} =
logger:set_handler_config(?MODULE,config,
#{sync_mode_qlen=>100,
@@ -331,6 +345,15 @@ config_fail(_Config) ->
{error,{invalid_config,logger_std_h,{filesync_rep_int,2000}}} =
logger:set_handler_config(?MODULE, config,
#{filesync_rep_int => 2000}),
+
+ %% Read-only fields may (accidentially) be included in the change,
+ %% but it won't take effect
+ {ok,C} = logger:get_handler_config(?MODULE),
+ ok = logger:set_handler_config(?MODULE,config,
+ #{handler_pid=>self(),
+ mode_tab=>erlang:make_ref()}),
+ {ok,C} = logger:get_handler_config(?MODULE),
+
ok.
config_fail(cleanup,_Config) ->
@@ -457,9 +480,26 @@ reconfig(Config) ->
overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
- filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} =
+ filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} = DefaultInfo =
logger_std_h:info(?MODULE),
+ {ok,
+ #{config:=
+ #{type := standard_io,
+ sync_mode_qlen := ?SYNC_MODE_QLEN,
+ drop_mode_qlen := ?DROP_MODE_QLEN,
+ flush_qlen := ?FLUSH_QLEN,
+ burst_limit_enable := ?BURST_LIMIT_ENABLE,
+ burst_limit_max_count := ?BURST_LIMIT_MAX_COUNT,
+ burst_limit_window_time := ?BURST_LIMIT_WINDOW_TIME,
+ overload_kill_enable := ?OVERLOAD_KILL_ENABLE,
+ overload_kill_qlen := ?OVERLOAD_KILL_QLEN,
+ overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE,
+ overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER,
+ filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} =
+ DefaultHConf}}
+ = logger:get_handler_config(?MODULE),
+
ok = logger:set_handler_config(?MODULE, config,
#{sync_mode_qlen => 1,
drop_mode_qlen => 2,
@@ -485,7 +525,77 @@ reconfig(Config) ->
overload_kill_qlen := 100000,
overload_kill_mem_size := 10000000,
overload_kill_restart_after := infinity,
- filesync_repeat_interval := no_repeat} = logger_std_h:info(?MODULE),
+ filesync_repeat_interval := no_repeat} = Info = logger_std_h:info(?MODULE),
+
+ {ok,#{config :=
+ #{type := standard_io,
+ sync_mode_qlen := 1,
+ drop_mode_qlen := 2,
+ flush_qlen := 3,
+ burst_limit_enable := false,
+ burst_limit_max_count := 10,
+ burst_limit_window_time := 10,
+ overload_kill_enable := true,
+ overload_kill_qlen := 100000,
+ overload_kill_mem_size := 10000000,
+ overload_kill_restart_after := infinity,
+ filesync_repeat_interval := no_repeat} = HConf}} =
+ logger:get_handler_config(?MODULE),
+
+ ok = logger:update_handler_config(?MODULE, config,
+ #{flush_qlen => ?FLUSH_QLEN}),
+ {ok,#{config:=C1}} = logger:get_handler_config(?MODULE),
+ ct:log("C1: ~p",[C1]),
+ C1 = HConf#{flush_qlen => ?FLUSH_QLEN},
+
+ ok = logger:set_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C2}} = logger:get_handler_config(?MODULE),
+ ct:log("C2: ~p",[C2]),
+ C2 = DefaultHConf#{sync_mode_qlen => 1},
+
+ ok = logger:set_handler_config(?MODULE, config, #{drop_mode_qlen => 100}),
+ {ok,#{config:=C3}} = logger:get_handler_config(?MODULE),
+ ct:log("C3: ~p",[C3]),
+ C3 = DefaultHConf#{drop_mode_qlen => 100},
+
+ ok = logger:update_handler_config(?MODULE, config, #{sync_mode_qlen => 1}),
+ {ok,#{config:=C4}} = logger:get_handler_config(?MODULE),
+ ct:log("C4: ~p",[C4]),
+ C4 = DefaultHConf#{sync_mode_qlen => 1,
+ drop_mode_qlen => 100},
+
+ ok = logger:remove_handler(?MODULE),
+
+ File = filename:join(Dir,lists:concat([?FUNCTION_NAME,".log"])),
+ ok = logger:add_handler(?MODULE,
+ logger_std_h,
+ #{config => #{type => {file,File}},
+ filter_default=>log,
+ filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]),
+ formatter=>{?MODULE,self()}}),
+
+ {ok,#{config:=#{filesync_repeat_interval:=FSI}=FileHConfig}} =
+ logger:get_handler_config(?MODULE),
+ ok = logger:update_handler_config(?MODULE,config,
+ #{filesync_repeat_interval=>FSI+2000}),
+ {ok,#{config:=C5}} = logger:get_handler_config(?MODULE),
+ ct:log("C5: ~p",[C5]),
+ C5 = FileHConfig#{filesync_repeat_interval=>FSI+2000},
+
+ %% You are not allowed to actively set 'type' in runtime, since
+ %% this is a write once field.
+ {error, {illegal_config_change,_,_}} =
+ logger:set_handler_config(?MODULE,config,#{type=>standard_io}),
+ {ok,#{config:=C6}} = logger:get_handler_config(?MODULE),
+ ct:log("C6: ~p",[C6]),
+ C6 = C5,
+
+ %% ... but if you don't specify 'type', then set_handler_config shall
+ %% NOT reset it to its default value
+ ok = logger:set_handler_config(?MODULE,config,#{sync_mode_qlen=>1}),
+ {ok,#{config:=C7}} = logger:get_handler_config(?MODULE),
+ ct:log("C7: ~p",[C7]),
+ C7 = FileHConfig#{sync_mode_qlen=>1},
ok.
reconfig(cleanup, _Config) ->
@@ -561,8 +671,8 @@ sync(Config) ->
%% check that if there's no repeated filesync active,
%% a filesync is still performed when handler goes idle
- logger:set_handler_config(?MODULE, config,
- #{filesync_repeat_interval => no_repeat}),
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => no_repeat}),
no_repeat = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)),
%% The following timer is to make sure the time from last log
%% ("second") to next ("third") is long enough, so the a flush is
@@ -592,12 +702,12 @@ sync(Config) ->
start_tracer([{logger_std_h,handle_cast,2}],
[OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]),
- logger:set_handler_config(?MODULE, config,
- #{filesync_repeat_interval => SyncInt}),
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => SyncInt}),
SyncInt = maps:get(filesync_repeat_interval, logger_std_h:info(?MODULE)),
timer:sleep(WaitT),
- logger:set_handler_config(?MODULE, config,
- #{filesync_repeat_interval => no_repeat}),
+ ok = logger:update_handler_config(?MODULE, config,
+ #{filesync_repeat_interval => no_repeat}),
check_tracer(100),
ok.
sync(cleanup, _Config) ->
@@ -652,7 +762,7 @@ sync_failure(Config) ->
rpc:call(Node, ?MODULE, set_result, [file_datasync,ok]),
SyncInt = 500,
- ok = rpc:call(Node, logger, set_handler_config,
+ ok = rpc:call(Node, logger, update_handler_config,
[?STANDARD_HANDLER, config,
#{filesync_repeat_interval => SyncInt}]),
Info = rpc:call(Node, logger_std_h, info, [?STANDARD_HANDLER]),
@@ -718,7 +828,7 @@ op_switch_to_sync_file(Config) ->
drop_mode_qlen => NumOfReqs+1,
flush_qlen => 2*NumOfReqs,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
%% TRecvPid = start_op_trace(),
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Lines = count_lines(Log),
@@ -747,7 +857,7 @@ op_switch_to_sync_tty(Config) ->
drop_mode_qlen => NumOfReqs+1,
flush_qlen => 2*NumOfReqs,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
ok.
op_switch_to_sync_tty(cleanup, _Config) ->
@@ -770,7 +880,7 @@ op_switch_to_drop_file(Config) ->
flush_qlen =>
Procs*NumOfReqs*Bursts,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
%% It sometimes happens that the handler gets the
%% requests in a slow enough pace so that dropping
%% never occurs. Therefore, lets generate a number of
@@ -807,7 +917,7 @@ op_switch_to_drop_tty(Config) ->
flush_qlen =>
Procs*NumOfReqs+1,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
ok.
op_switch_to_drop_tty(cleanup, _Config) ->
@@ -832,7 +942,7 @@ op_switch_to_flush_file(Config) ->
drop_mode_qlen => 300,
flush_qlen => 300,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 1500,
Procs = 10,
Bursts = 10,
@@ -879,7 +989,7 @@ op_switch_to_flush_tty(Config) ->
drop_mode_qlen => 100,
flush_qlen => 100,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 1000,
Procs = 100,
send_burst({n,NumOfReqs}, {spawn,Procs,0}, {chars,79}, notice),
@@ -895,7 +1005,7 @@ limit_burst_disabled(Config) ->
burst_limit_window_time => 2000,
drop_mode_qlen => 200,
flush_qlen => 300}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -915,7 +1025,7 @@ limit_burst_enabled_one(Config) ->
burst_limit_window_time => 2000,
drop_mode_qlen => 200,
flush_qlen => 300}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -936,7 +1046,7 @@ limit_burst_enabled_period(Config) ->
burst_limit_window_time => BurstTWin,
drop_mode_qlen => 20000,
flush_qlen => 20001}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
Windows = 3,
Sent = send_burst({t,BurstTWin*Windows}, seq, {chars,79}, notice),
@@ -956,7 +1066,7 @@ kill_disabled(Config) ->
HConfig#{config=>StdHConfig#{overload_kill_enable=>false,
overload_kill_qlen=>10,
overload_kill_mem_size=>100}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
NumOfReqs = 100,
send_burst({n,NumOfReqs}, seq, {chars,79}, notice),
Logged = count_lines(Log),
@@ -977,7 +1087,7 @@ qlen_kill_new(Config) ->
overload_kill_qlen=>10,
overload_kill_mem_size=>Mem0+50000,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
Procs = 4,
@@ -1011,7 +1121,7 @@ qlen_kill_std(_Config) ->
%% File = lists:concat([?MODULE,"_",?FUNCTION_NAME,".log"]),
%% Log = filename:join(Dir, File),
%% Node = start_std_h_on_new_node(Config, ?FUNCTION_NAME, Log),
- %% ok = rpc:call(Node, logger, set_handler_config,
+ %% ok = rpc:call(Node, logger, update_handler_config,
%% [?STANDARD_HANDLER, config,
%% #{overload_kill_enable=>true,
%% overload_kill_qlen=>10,
@@ -1028,7 +1138,7 @@ mem_kill_new(Config) ->
overload_kill_qlen=>50000,
overload_kill_mem_size=>Mem0+500,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
MRef = erlang:monitor(process, Pid0),
NumOfReqs = 100,
Procs = 4,
@@ -1067,7 +1177,7 @@ restart_after(Config) ->
HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
overload_kill_qlen=>10,
overload_kill_restart_after=>infinity}},
- ok = logger:set_handler_config(?MODULE, NewHConfig1),
+ ok = logger:update_handler_config(?MODULE, NewHConfig1),
MRef1 = erlang:monitor(process, whereis(h_proc_name())),
%% kill handler
send_burst({n,100}, {spawn,4,0}, {chars,79}, notice),
@@ -1082,14 +1192,15 @@ restart_after(Config) ->
ct:pal("Handler state = ~p", [Info1]),
ct:fail("Handler not dead! It should not have survived this!")
end,
-
+
{Log,_,_} = start_handler(?MODULE, ?FUNCTION_NAME, Config),
RestartAfter = ?OVERLOAD_KILL_RESTART_AFTER,
+
NewHConfig2 =
HConfig#{config=>StdHConfig#{overload_kill_enable=>true,
overload_kill_qlen=>10,
overload_kill_restart_after=>RestartAfter}},
- ok = logger:set_handler_config(?MODULE, NewHConfig2),
+ ok = logger:update_handler_config(?MODULE, NewHConfig2),
Pid0 = whereis(h_proc_name()),
MRef2 = erlang:monitor(process, Pid0),
%% kill handler
@@ -1123,7 +1234,7 @@ handler_requests_under_load(Config) ->
drop_mode_qlen => 1000,
flush_qlen => 2000,
burst_limit_enable => false}},
- ok = logger:set_handler_config(?MODULE, NewHConfig),
+ ok = logger:update_handler_config(?MODULE, NewHConfig),
Pid = spawn_link(fun() -> send_requests(?MODULE, 1, [{filesync,[]},
{info,[]},
{reset,[]},
@@ -1155,9 +1266,9 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) ->
Result =
case Req of
change_config ->
- logger:set_handler_config(HName, config,
- #{overload_kill_enable =>
- false});
+ logger:update_handler_config(HName, config,
+ #{overload_kill_enable =>
+ false});
Func ->
logger_std_h:Func(HName)
end,
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index a02b5f87d1..2f465a15bc 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1300,7 +1300,8 @@ e_delete(Config) when is_list(Config) ->
case os:type() of
{win32, _} ->
%% Remove a character device.
- {error, eacces} = ?PRIM_FILE:delete("nul");
+ expect({error, eacces}, {error, einval},
+ ?PRIM_FILE:delete("nul"));
_ ->
?PRIM_FILE:write_file_info(
Base, #file_info {mode=0}),
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index ceb4e9cc49..3bbf62e832 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -19,6 +19,9 @@
%%
-module(seq_trace_SUITE).
+%% label_capability_mismatch needs to run a part of the test on an OTP 20 node.
+-compile(r20).
+
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2]).
@@ -329,7 +332,7 @@ do_incompatible_labels(Rel) ->
Mdir = filename:dirname(Dir),
true = rpc:call(Node,code,add_patha,[Mdir]),
seq_trace:reset_trace(),
- rpc:call(Node,?MODULE,start_tracer,[]),
+ true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])),
Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
%% This node does not support arbitrary labels, so it must fail with a
@@ -356,7 +359,7 @@ do_compatible_labels(Rel) ->
Mdir = filename:dirname(Dir),
true = rpc:call(Node,code,add_patha,[Mdir]),
seq_trace:reset_trace(),
- rpc:call(Node,?MODULE,start_tracer,[]),
+ true = is_pid(rpc:call(Node,?MODULE,start_tracer,[])),
Receiver = spawn(Node,?MODULE,one_time_receiver,[]),
%% This node does not support arbitrary labels, but small integers should
@@ -783,6 +786,24 @@ do_shrink(N) ->
erlang:garbage_collect(),
do_shrink(N-1).
+%% Test that messages from a port does not clear the token
+port_clean_token(Config) when is_list(Config) ->
+ seq_trace:reset_trace(),
+ Label = make_ref(),
+ seq_trace:set_token(label, Label),
+ {label,Label} = seq_trace:get_token(label),
+
+ %% Create a port and get messages from it
+ %% We use os:cmd as a convenience as it does
+ %% open_port, port_command, port_close and receives replies.
+ %% Maybe it is not ideal to rely on the internal implementation
+ %% of os:cmd but it will have to do.
+ os:cmd("ls"),
+
+ %% Make sure that the seq_trace token is still there
+ {label,Label} = seq_trace:get_token(label),
+
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index aa8e4dc119..df95174c9f 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 6.0
+KERNEL_VSN = 6.1
diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in
index eaa875d0a3..bae6144abe 100644
--- a/lib/megaco/configure.in
+++ b/lib/megaco/configure.in
@@ -22,10 +22,6 @@ dnl
dnl define([AC_CACHE_LOAD], )dnl
dnl define([AC_CACHE_SAVE], )dnl
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
AC_INIT(vsn.mk)
@@ -42,11 +38,14 @@ else
host_os=win32
fi
-
dnl ----------------------------------------------------------------------
dnl Checks for programs.
dnl ----------------------------------------------------------------------
+AC_PROG_CC
+
+LM_WINDOWS_ENVIRONMENT
+
AC_DEFUN(ERL_REENTRANT_FLEX,
[flex_compile='$LEX -R -Pconftest -oconftest.c conftest.flex 1>&AC_FD_CC'
changequote(253, 273)dnl
@@ -188,111 +187,7 @@ CFLAGS="$CFLAGS $sanitizers"
LDFLAGS="$LDFLAGS $sanitizers"
])
-dnl
-dnl If ${ERL_TOP}/make/otp_ded.mk.in exists and contains DED_MK_VSN > 0,
-dnl every thing releted to compiling Dynamic Erlang Drivers can be found
-dnl in $(ERL_TOP)/make/$(TARGET)/ded.mk at compile time. If not, try to
-dnl figure these things out.
-dnl
-
-AC_MSG_CHECKING([for usable Dynamic Erlang Driver configuration])
-[
- ded_mk_in="${ERL_TOP}/make/otp_ded.mk.in"
- ded_mk_vsn=
- test -r "$ded_mk_in" &&
- ded_mk_vsn=`sed -n "s/^DED_MK_VSN[ ]*=[ ]*\(.*\)/\1/p" < "$ded_mk_in"`
- test "$ded_mk_vsn" != "" || ded_mk_vsn=0
-]
-
-if test $ded_mk_vsn -gt 0; then
-
-HAVE_USABLE_OTP_DED_MK=yes
-AC_MSG_RESULT([yes])
-
-CC=false
-AC_SUBST(CC)
-DED_LD=false
-AC_SUBST(DED_LD)
-
-else dnl --- begin no usable otp_ded.mk.in ---
-
-HAVE_USABLE_OTP_DED_MK=no
-AC_MSG_RESULT([no])
-
-dnl
-dnl C compiler (related) defs
-dnl
-
-AC_PROG_CC
-
-dnl
-dnl Flags to the C compiler
-dnl
-
-if test "X$host" = "Xwin32"; then
- DED_CFLAGS="$CFLAGS"
-else
- case $host_os in
- darwin*)
- CFLAGS="$CFLAGS -fno-common"
- ;;
- esac
-
- if test "x$GCC" = xyes; then
- DED_CFLAGS="$CFLAGS -fPIC $DED_CFLAGS"
- else
- DED_CFLAGS="$CFLAGS $DED_CFLAGS"
- fi
-fi
-
-dnl emulator includes needed
-DED_INCLUDES="-I${ERL_TOP}/erts/emulator/beam -I${ERL_TOP}/erts/include -I${ERL_TOP}/erts/include/$host -I${ERL_TOP}/erts/include/internal -I${ERL_TOP}/erts/include/internal/$host -I${ERL_TOP}/erts/emulator/sys/$ERLANG_OSTYPE"
-
-DED_THR_DEFS="-D_THREAD_SAFE -D_REENTRANT"
-
-case $host_os in
- win32)
- DED_LDFLAGS="-dll"
- ;;
- solaris2*|sysv4*)
- DED_LDFLAGS="-G"
- ;;
- aix4*)
- DED_LDFLAGS="-G -bnoentry -bexpall"
- ;;
- freebsd2*)
- # Non-ELF GNU linker
- DED_LDFLAGS="-Bshareable"
- ;;
- darwin*)
- # Mach-O linker, a shared lib and a loadable
- # object file is not the same thing.
- DED_LDFLAGS="-bundle -flat_namespace -undefined suppress"
- DED_LD="$CC"
- ;;
- *)
- # assume GNU linker and ELF
- DED_LDFLAGS="-shared"
- ;;
-esac
-
-AC_CHECK_PROGS(DED_LD, [$LD ld.sh])
-AC_CHECK_TOOL(DED_LD, ld, no_ld)
-if test "$DED_LD" = no_ld; then
- AC_MSG_ERROR([ld is required to build the flex scanner!])
-fi
-
-AC_MSG_CHECKING(for linker flags for loadable drivers)
-DED_LDFLAGS="$LDFLAGS $DED_LDFLAGS"
-AC_MSG_RESULT([$DED_LDFLAGS])
-
-fi dnl --- end no usable otp_ded.mk.in ---
-
-AC_SUBST(HAVE_USABLE_OTP_DED_MK)
-AC_SUBST(DED_CFLAGS)
-AC_SUBST(DED_INCLUDES)
-AC_SUBST(DED_THR_DEFS)
-AC_SUBST(DED_LDFLAGS)
+ERL_DED
AC_CHECK_PROG(PERL, perl, perl, no_perl)
if test "$PERL" = no_perl; then
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index 72feb9d2b3..5e085b60b0 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2000-2017. All Rights Reserved.
+# Copyright Ericsson AB 2000-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/megaco/doc/src/book.xml b/lib/megaco/doc/src/book.xml
index 9c304d6cae..06ff315de7 100644
--- a/lib/megaco/doc/src/book.xml
+++ b/lib/megaco/doc/src/book.xml
@@ -4,7 +4,7 @@
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2000</year><year>2016</year>
+ <year>2000</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index 54e048a172..b697c3f631 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -37,7 +37,22 @@
section is the version number of Megaco.</p>
- <section><title>Megaco 3.18.3</title>
+ <section><title>Megaco 3.18.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Megaco 3.18.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index c37ad4d702..26d2ddd44c 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -31,25 +31,6 @@ include ../../vsn.mk
VSN=$(MEGACO_VSN)
# ----------------------------------------------------
-# Dynamic Erlang Driver
-# ----------------------------------------------------
-HAVE_USABLE_OTP_DED_MK = @HAVE_USABLE_OTP_DED_MK@
-
-ifeq ($(HAVE_USABLE_OTP_DED_MK),yes)
-# otp_ded.mk will be used on R13B04 and later
-include $(ERL_TOP)/make/$(TARGET)/otp_ded.mk
-else
-# megacos configure provide the info instead
-DED_CC = @CC@
-DED__NOWARN_NOTHR_CFLAGS = @DED_CFLAGS@
-DED_THR_DEFS = @DED_THR_DEFS@
-DED_LD = @DED_LD@
-DED_LDFLAGS = @DED_LDFLAGS@
-DED_INCLUDES = @DED_INCLUDES@
-DED_EXT = so
-endif
-
-# ----------------------------------------------------
# The following variables differ on different systems, we set
# reasonable defaults, if something different is needed it should
# be set for that system only.
@@ -57,20 +38,19 @@ endif
FLEX_VSN = $(shell flex --version)
-TMP_CFLAGS = $(DED__NOWARN_NOTHR_CFLAGS) @OTP_EXTRA_FLAGS@
+TMP_CFLAGS = @DED_BASIC_CFLAGS@ @OTP_EXTRA_FLAGS@
ifeq ($(TYPE),valgrind)
CFLAGS = $(subst -O2, , $(TMP_CFLAGS)) -DVALGRIND
else
CFLAGS = $(TMP_CFLAGS)
endif
-CC = $(DED_CC)
-CFLAGS_MT = $(CFLAGS) $(DED_THR_DEFS)
-LD = $(DED_LD)
-LDFLAGS = $(DED_LDFLAGS)
+CC = @DED_CC@
+CFLAGS_MT = $(CFLAGS) @DED_THR_DEFS@
+LD = @DED_LD@
+LDFLAGS = @DED_LDFLAGS@
LEX = @LEX@
LEXLIB = @LEXLIB@
PERL = @PERL@
-ERLANG_OSTYPE = @ERLANG_OSTYPE@
# Shall we build the flex scanner or not.
# We assume that it does not exist on windows...
@@ -143,8 +123,8 @@ ifeq ($(findstring win32,$(TARGET)), win32)
FLEX_SCANNER_SO =
SOLIBS = $(FLEX_SCANNER_SO)
else
-FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).$(DED_EXT)
-FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).$(DED_EXT)
+FLEX_SCANNER_SO = $(LIBDIR)/$(STD_DRV).@DED_EXT@
+FLEX_SCANNER_MT_SO = $(LIBDIR)/$(MT_DRV).@DED_EXT@
SOLIBS = $(FLEX_SCANNER_SO) $(FLEX_SCANNER_MT_SO)
endif
@@ -179,7 +159,7 @@ else
CFLAGS += -DMFS_FLEX_DEBUG=0
endif
-CFLAGS += $(DED_INCLUDES) -I$(ERL_TOP)/erts/$(TARGET) $(DRV_FLAGS) -funroll-loops -Wall
+CFLAGS += @DED_INCLUDE@ -I$(ERL_TOP)/erts/$(TARGET) $(DRV_FLAGS) -funroll-loops -Wall
#ifneq ($(FLEX_VSN),)
#CFLAGS += -DFLEX_VERSION="$(FLEX_VSN)"
@@ -398,10 +378,10 @@ $(OBJDIR)/$(MT_DRV).o: $(MT_DRV).c
# No need to link with -lfl as we have also defined %option noyywrap -
# and having -lfl doesn't work under Darwin for some reason. - Sean
-$(LIBDIR)/$(STD_DRV).$(DED_EXT): $(OBJDIR)/$(STD_DRV).o
+$(LIBDIR)/$(STD_DRV).@DED_EXT@: $(OBJDIR)/$(STD_DRV).o
$(V_colon)@echo "linking std driver:"
$(V_LD) $(LDFLAGS) -o $@ $<
-$(LIBDIR)/$(MT_DRV).$(DED_EXT): $(OBJDIR)/$(MT_DRV).o
+$(LIBDIR)/$(MT_DRV).@DED_EXT@: $(OBJDIR)/$(MT_DRV).o
$(V_colon)@echo "linking multi-threaded driver:"
$(V_LD) $(LDFLAGS) -o $@ $<
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index a4f7de7f07..f4c82c537a 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.18.3
+MEGACO_VSN = 3.18.4
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/doc/src/mnesia_frag_hash.xml b/lib/mnesia/doc/src/mnesia_frag_hash.xml
index 51b32129b6..c233acdb05 100644
--- a/lib/mnesia/doc/src/mnesia_frag_hash.xml
+++ b/lib/mnesia/doc/src/mnesia_frag_hash.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2002</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -130,7 +130,7 @@
<name>key_to_frag_number(State, Key) -> FragNum | abort(Reason)</name>
<fsummary>Resolves the key of a record into a fragment number.</fsummary>
<type>
- <v>FragNum = integer()()</v>
+ <v>FragNum = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index 7134e3d1e4..8fc3610bb6 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -39,7 +39,55 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.15.4</title>
+ <section><title>Mnesia 4.15.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed type spec for <c>mnesia:change_config/2</c>.</p>
+ <p>
+ Own Id: OTP-15201 Aux Id: PR-1881 </p>
+ </item>
+ <item>
+ <p>
+ When master node is set do not force a load from
+ ram_copies replica when there are no available
+ disc_copies, since that would load an empty table. Wait
+ until a disk replica is available or until user
+ explicitly force_loads the table.</p>
+ <p>
+ Own Id: OTP-15221 Aux Id: ERIERL-217 </p>
+ </item>
+ <item>
+ <p>
+ Allow to add replicas even if all other replicas are down
+ when the other replicas are not stored on disk.</p>
+ <p>
+ Own Id: OTP-15226 Aux Id: ERIERL-221 </p>
+ </item>
+ <item>
+ <p>
+ Fixed <c>mnesia:delete_object/1</c> bug, where
+ delete_object was deleting the record if it was written
+ in the same transaction even if it was written to a
+ different value.</p>
+ <p>
+ Own Id: OTP-15231 Aux Id: PR-1858 </p>
+ </item>
+ <item>
+ <p>
+ Fixed a bug where the bag table index data was not
+ deleted when objects were deleted.</p>
+ <p>
+ Own Id: OTP-15243</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.15.4</title>
<section><title>Improvements and New Features</title>
<list>
@@ -54,6 +102,32 @@
</section>
+<section><title>Mnesia 4.15.3.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ When master node is set do not force a load from
+ ram_copies replica when there are no available
+ disc_copies, since that would load an empty table. Wait
+ until a disk replica is available or until user
+ explicitly force_loads the table.</p>
+ <p>
+ Own Id: OTP-15221 Aux Id: ERIERL-217 </p>
+ </item>
+ <item>
+ <p>
+ Allow to add replicas even if all other replicas are down
+ when the other replicase are not stored on disk.</p>
+ <p>
+ Own Id: OTP-15226 Aux Id: ERIERL-221 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Mnesia 4.15.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -663,7 +737,7 @@
<p>
Returns the same value for
mnesia_loader:disc_load_table/2 as
- mnesia_loader:net_load_table/4 if a table copy can not be
+ mnesia_loader:net_load_table/4 if a table copy cannot be
found. (Thanks to Uwe Dauernheim)</p>
<p>
Own Id: OTP-10015</p>
diff --git a/lib/mnesia/examples/bench/README b/lib/mnesia/examples/bench/README
index 5d31b5ba25..3648fb59da 100644
--- a/lib/mnesia/examples/bench/README
+++ b/lib/mnesia/examples/bench/README
@@ -141,7 +141,7 @@ statistics_detail
following atoms: normal, debug and debug2. debug enables a
finer grain of statistics to be reported, but since it requires
more counters, to be updated by the generator processes it may
- cause slightly worse benchmark performace figures than the brief
+ cause slightly worse benchmark performance figures than the brief
default case, that is normal. debug2 prints out the debug info
and formats it according to LMC's benchmark program.
@@ -160,7 +160,7 @@ n_fragments
Defines how many fragments each table should be divided in.
Default is 100. The fragments are evenly distributed over
- all table nodes. The group table not devided in fragments.
+ all table nodes. The group table not divided in fragments.
n_replicas
diff --git a/lib/mnesia/src/mnesia.erl b/lib/mnesia/src/mnesia.erl
index e298904e2a..223dba3f90 100644
--- a/lib/mnesia/src/mnesia.erl
+++ b/lib/mnesia/src/mnesia.erl
@@ -168,6 +168,9 @@
-type snmp_struct() :: [{atom(), snmp_type() | tuple_of(snmp_type())}].
-type snmp_type() :: 'fix_string' | 'string' | 'integer'.
-type tuple_of(_T) :: tuple().
+-type config_key() :: extra_db_nodes | dc_dump_limit.
+-type config_value() :: [node()] | number().
+-type config_result() :: {ok, config_value()} | {error, term()}.
-define(DEFAULT_ACCESS, ?MODULE).
@@ -278,7 +281,8 @@ stop() ->
Other -> Other
end.
--spec change_config(Config::atom(), Value::_) -> ok | {error, term()}.
+-spec change_config(Config::config_key(), Value::config_value()) ->
+ config_result().
change_config(extra_db_nodes, Ns) when is_list(Ns) ->
mnesia_controller:connect_nodes(Ns);
change_config(dc_dump_limit, N) when is_number(N), N > 0 ->
@@ -779,12 +783,16 @@ do_delete_object(Tid, Ts, Tab, Val, LockKind) ->
?ets_insert(Store, {Oid, Val, delete_object});
_ ->
case ?ets_match_object(Store, {Oid, '_', write}) of
- [] ->
- ?ets_match_delete(Store, {Oid, Val, '_'}),
- ?ets_insert(Store, {Oid, Val, delete_object});
- _ ->
- ?ets_delete(Store, Oid),
- ?ets_insert(Store, {Oid, Oid, delete})
+ [] ->
+ ?ets_match_delete(Store, {Oid, Val, '_'}),
+ ?ets_insert(Store, {Oid, Val, delete_object});
+ Ops ->
+ case lists:member({Oid, Val, write}, Ops) of
+ true ->
+ ?ets_delete(Store, Oid),
+ ?ets_insert(Store, {Oid, Oid, delete});
+ false -> ok
+ end
end
end,
ok;
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index f81ba783f2..882de0d613 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -772,22 +772,6 @@ handle_call({unannounce_add_table_copy, [Tab, Node], From}, ReplyTo, State) ->
noreply(State#state{early_msgs = [{call, Msg, undefined} | Msgs]})
end;
-handle_call({net_load, Tab, Cs}, From, State) ->
- State2 =
- case State#state.schema_is_merged of
- true ->
- Worker = #net_load{table = Tab,
- opt_reply_to = From,
- reason = {dumper,{add_table_copy, unknown}},
- cstruct = Cs
- },
- add_worker(Worker, State);
- false ->
- reply(From, {not_loaded, schema_not_merged}),
- State
- end,
- noreply(State2);
-
handle_call(Msg, From, State) when State#state.schema_is_merged /= true ->
%% Buffer early messages
Msgs = State#state.early_msgs,
@@ -1457,7 +1441,8 @@ orphan_tables([Tab | Tabs], Node, Ns, Local, Remote) ->
L = [Tab | Local],
orphan_tables(Tabs, Node, Ns, L, Remote);
Masters ->
- R = [{Tab, Masters} | Remote],
+ %% Do not disc_load table from RamCopyHolders
+ R = [{Tab, Masters -- RamCopyHolders} | Remote],
orphan_tables(Tabs, Node, Ns, Local, R)
end;
_ ->
@@ -2162,6 +2147,15 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
{dumper,{add_table_copy,_}} -> true;
_ -> false
end,
+
+ OnlyRamCopies = case Cs of
+ #cstruct{disc_copies = DC,
+ disc_only_copies = DOC,
+ external_copies = Ext} ->
+ [] =:= (DC ++ (DOC ++ Ext)) -- [node()];
+ _ ->
+ false
+ end,
if
ReadNode == node() ->
%% Already loaded locally
@@ -2173,6 +2167,8 @@ load_table_fun(#net_load{cstruct=Cs, table=Tab, reason=Reason, opt_reply_to=Repl
end;
AccessMode == read_only, not AddTableCopy ->
fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
+ Active =:= [], AddTableCopy, OnlyRamCopies ->
+ fun() -> disc_load_table(Tab, Reason, ReplyTo) end;
true ->
fun() ->
%% Either we cannot read the table yet
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 917ada65df..098265d5fc 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -155,7 +155,7 @@ del_object_bag_([IxK|IxKs], Found, Type, Tab, Key, Obj, Ixt) ->
bag ->
db_match_erase(Ixt, {IxK, Key});
ordered ->
- db_erase(Ixt, {{IxK, Key}})
+ db_erase(Ixt, {IxK, Key})
end;
_ ->
ok
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index a884b8e086..6abc05fade 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -929,7 +929,7 @@ error_desc(no_transaction) -> "Operation not allowed outside transactions";
error_desc(combine_error) -> "Table options were ilegally combined";
error_desc(bad_index) -> "Index already exists or was out of bounds";
error_desc(already_exists) -> "Some schema option we try to set is already on";
-error_desc(index_exists)-> "Some ops can not be performed on tabs with index";
+error_desc(index_exists)-> "Some ops cannot be performed on tabs with index";
error_desc(no_exists)-> "Tried to perform op on non-existing (non alive) item";
error_desc(system_limit) -> "Some system_limit was exhausted";
error_desc(mnesia_down) -> "A transaction involving objects at some remote "
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index ebe924a86e..2cdae0c906 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -67,7 +67,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources already allocated
+ {dumper, DR} when is_atom(DR) -> %% Resources already allocated
ignore;
_ ->
mnesia_monitor:mktab(Tab, Args),
@@ -91,8 +91,8 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == ram_copies ->
EtsOpts = proplists:get_value(ets, StorageProps, []),
Args = [{keypos, 2}, public, named_table, Type | EtsOpts],
case Reason of
- {dumper, _} -> %% Resources allready allocated
- ignore;
+ {dumper, DR} when is_atom(DR) ->
+ ignore; %% Resources already allocated
_ ->
mnesia_monitor:mktab(Tab, Args),
Fname = mnesia_lib:tab2dcd(Tab),
@@ -131,7 +131,7 @@ do_get_disc_copy2(Tab, Reason, Storage, Type) when Storage == disc_only_copies -
{repair, mnesia_monitor:get_env(auto_repair)}
| DetsOpts],
case Reason of
- {dumper, _} ->
+ {dumper, DR} when is_atom(DR) ->
mnesia_index:init_index(Tab, Storage),
snmpify(Tab, Storage),
set({Tab, load_node}, node()),
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 4b3fffc735..cbf7db28f0 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1661,7 +1661,7 @@ commit_participant(Coord, Tid, Bin, C0, DiscNs, _RamNs) ->
?eval_debug_fun({?MODULE, commit_participant, pre}, [{tid, Tid}]),
try mnesia_schema:prepare_commit(Tid, C0, {part, Coord}) of
{Modified, C = #commit{}, DumperMode} ->
- %% If we can not find any local unclear decision
+ %% If we cannot find any local unclear decision
%% we should presume abort at startup recovery
case lists:member(node(), DiscNs) of
false ->
diff --git a/lib/mnesia/test/README b/lib/mnesia/test/README
index e0ced7399d..30a0d2fd64 100644
--- a/lib/mnesia/test/README
+++ b/lib/mnesia/test/README
@@ -51,7 +51,7 @@ stated as test suite configuration parameters, but by default
the extra node names are generated. In this example the names
will be: a, a1 and a2. It is enough to start the first node
manually, the extra nodes will automatically be started if
-neccessary.
+necessary.
The attached UNIX shell script mt, does not work on all
platforms, but it may be used as a source for inspiration. It
@@ -63,7 +63,7 @@ test cases (i.e. test cases that encountered an error).
During development we want to be able to run the test cases
in the debugger. This demands a little bit of preparations:
- - Start the neccessary number of nodes (normally 3).
+ - Start the necessary number of nodes (normally 3).
This may either be done by running the mt script or
by starting the main node and then invoke mt:start_nodes()
to start the extra nodes with slave.
@@ -73,7 +73,7 @@ in the debugger. This demands a little bit of preparations:
- Load all files that needs to be interpreted. This is typically
all Mnesia files plus the test case. By invoking mnesia:ni()
- and mnesia:ni([TestModule]) the neccessary modules will be
+ and mnesia:ni([TestModule]) the necessary modules will be
loaded on all CONNECTED nodes.
The test case execution is supervised in order to ensure that no test
diff --git a/lib/mnesia/test/mnesia_durability_test.erl b/lib/mnesia/test/mnesia_durability_test.erl
index 62199d8b9a..ccbfdc9738 100644
--- a/lib/mnesia/test/mnesia_durability_test.erl
+++ b/lib/mnesia/test/mnesia_durability_test.erl
@@ -46,6 +46,7 @@
master_nodes/1, starting_master_nodes/1,
master_on_non_local_tables/1,
remote_force_load_with_local_master_node/1,
+ master_node_with_ram_copy_2/1, master_node_with_ram_copy_3/1,
dump_ram_copies/1, dump_disc_copies/1, dump_disc_only/1]).
-include("mnesia_test_lib.hrl").
@@ -91,7 +92,8 @@ groups() ->
{load_tables_with_master_tables, [],
[master_nodes, starting_master_nodes,
master_on_non_local_tables,
- remote_force_load_with_local_master_node]},
+ remote_force_load_with_local_master_node,
+ master_node_with_ram_copy_2, master_node_with_ram_copy_3]},
{durability_of_dump_tables, [],
[dump_ram_copies, dump_disc_copies, dump_disc_only]}].
@@ -1165,6 +1167,107 @@ remote_force_load_with_local_master_node(Config) when is_list(Config) ->
?verify_mnesia(Nodes, []).
+master_node_with_ram_copy_2(Config) when is_list(Config) ->
+ [A, B] = Nodes = ?acquire_nodes(2, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node require force_load
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+
+ ?match(yes, rpc:call(A, mnesia, force_load_table, [Tab])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
+
+master_node_with_ram_copy_3(Config) when is_list(Config) ->
+ [A, B, C] = Nodes = ?acquire_nodes(3, Config),
+ Tab = ?FUNCTION_NAME,
+ ?match({atomic,ok}, mnesia:create_table(Tab, [{disc_copies, [A,C]}, {ram_copies, [B]}])),
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+
+ %% Test that we don't load from ram_copies
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 1000])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, init}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, init}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node will wait until loaded
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ %% Test that master_nodes set to ram_copy node requires force load
+ ?match({atomic,ok}, mnesia:sync_transaction(?SDwrite({Tab, 1, init}))),
+ ?match(ok, rpc:call(A, mnesia, set_master_nodes, [[B]])),
+ ?match(ok, rpc:call(C, mnesia, set_master_nodes, [[B]])),
+
+ ?match(stopped, rpc:call(A, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, update})])),
+ ?match(stopped, rpc:call(C, mnesia, stop, [])),
+ ?match({atomic,ok}, rpc:call(B, mnesia, sync_transaction, [?SDwrite({Tab, 1, ram_copies})])),
+ ?match(stopped, rpc:call(B, mnesia, stop, [])),
+ ?match(ok, rpc:call(B, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(A, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(ok, rpc:call(C, mnesia, start, [])),
+ ?match({timeout, [Tab]}, rpc:call(A, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match({timeout, [Tab]}, rpc:call(B, mnesia, wait_for_tables, [[Tab], 500])),
+ ?match(yes, rpc:call(C, mnesia, force_load_table, [Tab])),
+
+ ?match(ok, rpc:call(A, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(B, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match(ok, rpc:call(C, mnesia, wait_for_tables, [[Tab], 3000])),
+ ?match([{Tab, 1, update}], rpc:call(A, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(B, mnesia, dirty_read, [{Tab, 1}])),
+ ?match([{Tab, 1, update}], rpc:call(C, mnesia, dirty_read, [{Tab, 1}])),
+
+ ?verify_mnesia(Nodes, []).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1415,7 +1518,7 @@ do_disc_durability(Config,CopyType) ->
[{Tab_bag, 22, a_2222}], [{Tab_bag, 33, a_3333}],
[{Tab_set, counter, 10}]]),
- timer:sleep(1000), %% Debugging strange msgs..
+ timer:sleep(500), %% Debugging strange msgs..
?log("Flushed ~p ~n", [mnesia_test_lib:flush()]),
?verify_mnesia(Nodes, []).
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index eb1f987cf0..a451c8d0c8 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -31,10 +31,11 @@
db_node_lifecycle/1, evil_delete_db_node/1, start_and_stop/1,
checkpoint/1, table_lifecycle/1, storage_options/1,
add_copy_conflict/1, add_copy_when_going_down/1,
+ add_copy_with_down/1,
replica_management/1, clear_table_during_load/1,
schema_availability/1, local_content/1,
replica_location/1, user_properties/1, unsupp_user_props/1,
- sorted_ets/1,
+ sorted_ets/1, index_cleanup/1,
change_table_access_mode/1, change_table_load_order/1,
set_master_nodes/1, offline_set_master_nodes/1,
dump_tables/1, dump_log/1, wait_for_tables/1, force_load_table/1,
@@ -48,7 +49,7 @@
record_name_dirty_access_disc_only/1,
record_name_dirty_access_xets/1]).
--export([info_check/8]).
+-export([info_check/8, index_size/1]).
-define(cleanup(N, Config),
mnesia_test_lib:prepare_test_case([{reload_appls, [mnesia]}],
@@ -65,13 +66,14 @@ all() ->
db_node_lifecycle, evil_delete_db_node, start_and_stop,
checkpoint, table_lifecycle, storage_options,
add_copy_conflict,
- add_copy_when_going_down, replica_management, clear_table_during_load,
+ add_copy_when_going_down, add_copy_with_down, replica_management,
+ clear_table_during_load,
schema_availability, local_content,
{group, table_access_modifications}, replica_location,
{group, table_sync}, user_properties, unsupp_user_props,
{group, record_name}, {group, snmp_access},
{group, subscriptions}, {group, iteration},
- {group, debug_support}, sorted_ets,
+ {group, debug_support}, sorted_ets, index_cleanup,
{mnesia_dirty_access_test, all},
{mnesia_trans_access_test, all},
{mnesia_evil_backup, all}].
@@ -732,6 +734,49 @@ add_copy_when_going_down(Config) ->
?match_receive({test,{aborted,_}}),
?verify_mnesia([Node2], []).
+add_copy_with_down(suite) -> [];
+add_copy_with_down(Config) ->
+ %% Allow add_table_copy() with ram_copies even all other replicas are down
+ Nodes = [Node1, Node2, Node3] = ?acquire_nodes(3, Config),
+ ?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node3]}, {disc_copies, [Node2]}])),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match({aborted, _}, mnesia:del_table_copy(a, Node2)),
+ ok = rpc:call(Node3, mnesia, start, []),
+ ?match({aborted, _}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match([], mnesia_test_lib:start_mnesia([Node2], [a])),
+ ?match({atomic, ok}, mnesia:change_table_copy_type(a, Node2, ram_copies)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, ram_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?match({atomic, ok}, mnesia:del_table_copy(a, Node1)),
+ stopped = rpc:call(Node2, mnesia, stop, []),
+ stopped = rpc:call(Node3, mnesia, stop, []),
+ ?match({atomic, ok}, mnesia:add_table_copy(a, Node1, disc_only_copies)),
+ ?match(ok, mnesia:dirty_write({a,1,1})),
+ ?match([], mnesia_test_lib:start_mnesia([Node2,Node3], [a])),
+ ?match([{a,1,1}], rpc:call(Node1, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node2, mnesia, dirty_read, [{a,1}])),
+ ?match([{a,1,1}], rpc:call(Node3, mnesia, dirty_read, [{a,1}])),
+
+ ?verify_mnesia(Nodes, []).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Add, drop and move replicas, change storage types
@@ -2514,3 +2559,55 @@ sorted_ets(Config) when is_list(Config) ->
?match({atomic, [{rec,1,1}, {rec,2,1}]}, mnesia:transaction(TestIt)).
+index_cleanup(Config) when is_list(Config) ->
+ [N1, N2] = All = ?acquire_nodes(2, Config),
+ ?match({atomic, ok}, mnesia:create_table(i_set, [{type, set}, {ram_copies, [N1]}, {index, [val]},
+ {disc_only_copies, [N2]}])),
+ ?match({atomic, ok}, mnesia:create_table(i_bag, [{type, bag}, {ram_copies, [N1]}, {index, [val]},
+ {disc_only_copies, [N2]}])),
+ ?match({atomic, ok}, mnesia:create_table(i_oset, [{type, ordered_set}, {ram_copies, [N1, N2]},
+ {index, [val]}])),
+
+ Tabs = [i_set, i_bag, i_oset],
+
+ Add = fun(Tab) ->
+ Write = fun(Tab) ->
+ Recs = [{Tab, N, N rem 5} || N <- lists:seq(1,10)],
+ [ok = mnesia:write(Rec) || Rec <- Recs],
+ Recs
+ end,
+ {atomic, Recs} = mnesia:sync_transaction(Write, [Tab]),
+ lists:sort(Recs)
+ end,
+
+ IRead = fun(Tab) ->
+ Read = fun(Tab) ->
+ [mnesia:index_read(Tab, N, val) || N <- lists:seq(0,4)]
+ end,
+ {atomic, Recs} = mnesia:transaction(Read, [Tab]),
+ lists:sort(lists:flatten(Recs))
+ end,
+
+ Delete = fun(Rec) ->
+ Del = fun() -> mnesia:delete_object(Rec) end,
+ {atomic, ok} = mnesia:sync_transaction(Del),
+ ok
+ end,
+
+
+ Recs = [Add(Tab) || Tab <- Tabs],
+ ?match(Recs, [IRead(Tab) || Tab <- Tabs]),
+ [Delete(Rec) || Rec <- lists:flatten(Recs)],
+
+ [?match({Tab,0}, {Tab,mnesia:table_info(Tab, size)}) || Tab <- Tabs],
+
+ [?match({Tab,Node,0, _}, rpc:call(Node, ?MODULE, index_size, [Tab]))
+ || Node <- All, Tab <- Tabs],
+ ?verify_mnesia(All, []).
+
+index_size(Tab) ->
+ %% White box testing
+ case mnesia:table_info(Tab, index_info) of
+ {index, _, [{_, {ram, Ref}}=Dbg]} -> {Tab, node(), ets:info(Ref, size), Dbg};
+ {index, _, [{_, {dets, Ref}}=Dbg]} -> {Tab, node(), dets:info(Ref, size), Dbg}
+ end.
diff --git a/lib/mnesia/test/mnesia_isolation_test.erl b/lib/mnesia/test/mnesia_isolation_test.erl
index b2eea2390b..49bcec14af 100644
--- a/lib/mnesia/test/mnesia_isolation_test.erl
+++ b/lib/mnesia/test/mnesia_isolation_test.erl
@@ -1563,7 +1563,8 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match({atomic, ok}, mnesia:create_table([{name, Tab},
{ram_copies, [Node1]}])),
ValPos = 3,
- RecA = {Tab, a, 1},
+ RecA = {Tab, a, 1},
+ RecA2 = {Tab, a, 2},
PatA = {Tab, '$1', 1},
RecB = {Tab, b, 3},
PatB = {Tab, '$1', 3},
@@ -1598,6 +1599,14 @@ trans_update_visible_inside_trans(Config) when is_list(Config) ->
?match([], mnesia:index_read(Tab, 3, ValPos)),
%% delete_object
+ ?match(ok, mnesia:delete_object(RecA2)),
+ ?match([RecA], mnesia:read({Tab, a})),
+ ?match([RecA], mnesia:wread({Tab, a})),
+ ?match([RecA], mnesia:match_object(PatA)),
+ ?match([a], mnesia:all_keys(Tab)),
+ ?match([RecA], mnesia:index_match_object(PatA, ValPos)),
+ ?match([RecA], mnesia:index_read(Tab, 1, ValPos)),
+
?match(ok, mnesia:delete_object(RecA)),
?match([], mnesia:read({Tab, a})),
?match([], mnesia:wread({Tab, a})),
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index aaa1c3006f..1cfb35c774 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.15.4
+MNESIA_VSN = 4.15.5
diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml
index 67bba37e39..4d1a9a4f55 100644
--- a/lib/observer/doc/src/notes.xml
+++ b/lib/observer/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the Observer
application.</p>
+<section><title>Observer 2.8.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Observer 2.8</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/observer/src/cdv_bin_cb.erl b/lib/observer/src/cdv_bin_cb.erl
index a4a542297c..91d33474c8 100644
--- a/lib/observer/src/cdv_bin_cb.erl
+++ b/lib/observer/src/cdv_bin_cb.erl
@@ -49,7 +49,7 @@ format_bin_fun(Format,Bin) ->
try io_lib:format(Format,[Bin]) of
Str -> plain_html(lists:flatten(Str))
catch error:badarg ->
- Warning = "This binary can not be formatted with " ++ Format,
+ Warning = "This binary cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
end
end.
@@ -59,7 +59,7 @@ binary_to_term_fun(Bin) ->
try binary_to_term(Bin) of
Term -> plain_html(io_lib:format("~tp",[Term]))
catch error:badarg ->
- Warning = "This binary can not be converted to an Erlang term",
+ Warning = "This binary cannot be converted to an Erlang term",
observer_html_lib:warning(Warning)
end
end.
diff --git a/lib/observer/src/cdv_term_cb.erl b/lib/observer/src/cdv_term_cb.erl
index 91de6449c4..85da1d227a 100644
--- a/lib/observer/src/cdv_term_cb.erl
+++ b/lib/observer/src/cdv_term_cb.erl
@@ -51,7 +51,7 @@ format_term_fun(Format,Term,Tab) ->
try io_lib:format(Format,[Term]) of
Str -> {expand, plain_html(Str), Tab}
catch error:badarg ->
- Warning = "This term can not be formatted with " ++ Format,
+ Warning = "This term cannot be formatted with " ++ Format,
observer_html_lib:warning(Warning)
after
observer_lib:report_progress({ok,stop_pulse})
diff --git a/lib/observer/src/cdv_wx.erl b/lib/observer/src/cdv_wx.erl
index 78a897111c..e546997879 100644
--- a/lib/observer/src/cdv_wx.erl
+++ b/lib/observer/src/cdv_wx.erl
@@ -448,10 +448,7 @@ maybe_warn_filename(FileName) ->
true ->
continue;
false ->
- DumpName = case os:getenv("ERL_CRASH_DUMP") of
- false -> filename:absname("erl_crash.dump");
- Name -> filename:absname(Name)
- end,
+ DumpName = filename:absname(os:getenv("ERL_CRASH_DUMP", "erl_crash.dump")),
case filename:absname(FileName) of
DumpName ->
Warning =
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index 14b086ff58..276b209ce5 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1594,31 +1594,92 @@ read_heap(Fd,Pid,DecodeOpts,Dict0) ->
Dict0
end.
-read_heap(DecodeOpts,Dict0) ->
- %% This function is never called if the dump is truncated in {?proc_heap,Pid}
- case get(fd) of
- end_of_heap ->
+read_heap(DecodeOpts, Dict0) ->
+ %% This function is never called if the dump is truncated in
+ %% {?proc_heap,Pid}.
+ %%
+ %% It is not always possible to reconstruct the heap terms
+ %% in a single pass, especially if maps are involved.
+ %% See crashdump_helper:literal_map/0 for an example.
+ %%
+ %% Therefore, we need two passes. In the first pass
+ %% we collect all lines without parsing them, and in the
+ %% second pass we parse them.
+ %%
+ %% The first pass follows.
+
+ Lines0 = read_heap_lines(),
+
+ %% Save a map of all unprocessed lines so that deref_ptr() can
+ %% access any line when there are references to terms not yet
+ %% built.
+
+ LineMap = maps:from_list(Lines0),
+ put(line_map, LineMap),
+
+ %% Refc binaries (tag "Yc") must be processed before any sub
+ %% binaries (tag "Ys") referencing them, so we make sure to
+ %% process all the refc binaries first.
+ %%
+ %% The other lines can be processed in any order, but processing
+ %% them in the reverse order compared to how they are printed in
+ %% the crash dump seems to minimize the number of references to
+ %% terms that have not yet been built. That happens to be the
+ %% order of the line list as returned by read_heap_lines/0.
+
+ RefcBins = [Refc || {_,<<"Yc",_/binary>>}=Refc <- Lines0],
+ Lines = RefcBins ++ Lines0,
+
+ %% Second pass.
+
+ init_progress("Processing terms", map_size(LineMap)),
+ Dict = parse_heap_terms(Lines, DecodeOpts, Dict0),
+ erase(line_map),
+ end_progress(),
+ Dict.
+
+read_heap_lines() ->
+ read_heap_lines_1(get(fd), []).
+
+read_heap_lines_1(Fd, Acc) ->
+ case bytes(Fd) of
+ "=" ++ _next_tag ->
end_progress(),
- Dict0;
- Fd ->
- case bytes(Fd) of
- "=" ++ _next_tag ->
- end_progress(),
- put(fd, end_of_heap),
- Dict0;
- Line ->
- update_progress(length(Line)+1),
- Dict = parse(Line,DecodeOpts,Dict0),
- read_heap(DecodeOpts,Dict)
- end
+ put(fd, end_of_heap),
+ Acc;
+ Line0 ->
+ update_progress(length(Line0)+1),
+ {Addr,":"++Line1} = get_hex(Line0),
+
+ %% Reduce the memory consumption by converting the
+ %% line to a binary. Measurements show that it may also
+ %% be benefical for performance, too, because it makes the
+ %% garbage collections cheaper.
+
+ Line = list_to_binary(Line1),
+ read_heap_lines_1(Fd, [{Addr,Line}|Acc])
end.
-parse(Line0, DecodeOpts, Dict0) ->
- {Addr,":"++Line1} = get_hex(Line0),
- {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0),
- [] = skip_blanks(Line),
+parse_heap_terms([{Addr,Line0}|T], DecodeOpts, Dict0) ->
+ case gb_trees:is_defined(Addr, Dict0) of
+ true ->
+ %% Already parsed (by a recursive call from do_deref_ptr()
+ %% to parse_line()). Nothing to do.
+ parse_heap_terms(T, DecodeOpts, Dict0);
+ false ->
+ %% Parse this previously unparsed term.
+ Dict = parse_line(Addr, Line0, DecodeOpts, Dict0),
+ parse_heap_terms(T, DecodeOpts, Dict)
+ end;
+parse_heap_terms([], _DecodeOpts, Dict) ->
Dict.
+parse_line(Addr, Line0, DecodeOpts, Dict0) ->
+ update_progress(1),
+ Line1 = binary_to_list(Line0),
+ {_Term,Line,Dict} = parse_heap_term(Line1, Addr, DecodeOpts, Dict0),
+ [] = skip_blanks(Line), %Assertion.
+ Dict.
%%-----------------------------------------------------------------
%% Page with one port
@@ -2871,16 +2932,18 @@ parse_atom_translation_table(N, Line0, As) ->
deref_ptr(Ptr, Line, DecodeOpts, D) ->
- Lookup = fun(D0) ->
- gb_trees:lookup(Ptr, D0)
- end,
+ Lookup0 = fun(D0) ->
+ gb_trees:lookup(Ptr, D0)
+ end,
+ Lookup = wrap_line_map(Ptr, Lookup0),
do_deref_ptr(Lookup, Line, DecodeOpts, D).
deref_bin(Binp0, Offset, Sz, Line, DecodeOpts, D) ->
Binp = Binp0 bor DecodeOpts#dec_opts.bin_addr_adj,
- Lookup = fun(D0) ->
- lookup_binary(Binp, Offset, Sz, D0)
- end,
+ Lookup0 = fun(D0) ->
+ lookup_binary(Binp, Offset, Sz, D0)
+ end,
+ Lookup = wrap_line_map(Binp, Lookup0),
do_deref_ptr(Lookup, Line, DecodeOpts, D).
lookup_binary(Binp, Offset, Sz, D) ->
@@ -2899,26 +2962,36 @@ lookup_binary(Binp, Offset, Sz, D) ->
end
end.
+wrap_line_map(Ptr, Lookup) ->
+ wrap_line_map_1(get(line_map), Ptr, Lookup).
+
+wrap_line_map_1(#{}=LineMap, Ptr, Lookup) ->
+ fun(D) ->
+ case Lookup(D) of
+ {value,_}=Res ->
+ Res;
+ none ->
+ case LineMap of
+ #{Ptr:=Line} ->
+ {line,Ptr,Line};
+ #{} ->
+ none
+ end
+ end
+ end;
+wrap_line_map_1(undefined, _Ptr, Lookup) ->
+ Lookup.
+
do_deref_ptr(Lookup, Line, DecodeOpts, D0) ->
case Lookup(D0) of
{value,Term} ->
{Term,Line,D0};
none ->
- case get(fd) of
- end_of_heap ->
- put(incomplete_heap,true),
- {['#CDVIncompleteHeap'],Line,D0};
- Fd ->
- case bytes(Fd) of
- "="++_ ->
- put(fd, end_of_heap),
- do_deref_ptr(Lookup, Line, DecodeOpts, D0);
- L ->
- update_progress(length(L)+1),
- D = parse(L, DecodeOpts, D0),
- do_deref_ptr(Lookup, Line, DecodeOpts, D)
- end
- end
+ put(incomplete_heap, true),
+ {['#CDVIncompleteHeap'],Line,D0};
+ {line,Addr,NewLine} ->
+ D = parse_line(Addr, NewLine, DecodeOpts, D0),
+ do_deref_ptr(Lookup, Line, DecodeOpts, D)
end.
get_hex(L) ->
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index 814f3a1260..dfd19569fd 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -147,7 +147,7 @@ handle_event(#wx{event=#wxList{type=command_list_item_activated,
State=#state{holder=Holder, node=Node, opts=#opts{type=Type}, grid=Grid}) ->
case get_table(Holder, Index) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
@@ -187,7 +187,7 @@ handle_event(#wx{id=?ID_SHOW_TABLE},
R when is_integer(R) ->
case get_table(Holder, R) of
#tab{protection=private} ->
- self() ! {error, "Table has 'private' protection and can not be read"};
+ self() ! {error, "Table has 'private' protection and cannot be read"};
#tab{}=Table ->
observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}]);
_ -> ignore
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index 453e3bdc2d..1f748cb8d2 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -806,7 +806,7 @@ is_rb_compatible(Node) ->
is_rb_server_running(Node, LogState) ->
%% If already started, somebody else may use it.
- %% We can not use it too, as far log file would be overriden. Not fair.
+ %% We cannot use it too, as far log file would be overriden. Not fair.
case rpc:block_call(Node, erlang, whereis, [rb_server]) of
Pid when is_pid(Pid), (LogState == false) ->
throw("Error: rb_server is already started and maybe used by someone.");
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index 145ff56b71..d8f4e046ae 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -142,4 +142,23 @@ create_maps() ->
Map3 = lists:foldl(fun(I, A) ->
A#{I=>I*I}
end, Map2, lists:seq(-10, 0)),
- #{a=>Map0,b=>Map1,c=>Map2,d=>Map3,e=>#{}}.
+ #{a=>Map0,b=>Map1,c=>Map2,d=>Map3,e=>#{},literal=>literal_map()}.
+
+literal_map() ->
+ %% A literal map such as the one below will produce a heap dump
+ %% like this:
+ %%
+ %% Address1:t4:H<Address3>,H<Address4>,H<Address5>,H<Address6>
+ %% Address2:Mf4:H<Adress1>:I1,I2,I3,I4
+ %% Address3: ... % "one"
+ %% Address4: ... % "two"
+ %% Address5: ... % "three"
+ %% Address6: ... % "four"
+ %%
+ %% The map cannot be reconstructed in a single sequential pass.
+ %%
+ %% To reconstruct the map, first the string keys "one"
+ %% through "four" must be reconstructed, then the tuple at
+ %% Adress1, then the map at Address2.
+
+ #{"one"=>1,"two"=>2,"three"=>3,"four"=>4}.
diff --git a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
index 2c8944fa9d..0b30fdf2f1 100644
--- a/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
+++ b/lib/observer/test/crashdump_viewer_SUITE_data/old_format.dump
@@ -10,7 +10,7 @@ Compiled on Wed Dec 4 11:11:21 2002
Process Information
--------------------------------------------------
<0.0.0> Waiting. Registered as: init
-Spawned as: otp_ring0:start/2
+Spawned as: erl_init:start/2
Message buffer data: 4 words
Link list: [<0.5.0>,<0.4.0>,<0.2.0>]
Reductions 3125 stack+heap 610 old_heap_sz=233
@@ -68,7 +68,7 @@ y(3) [gen_event,<0.1.0>,<0.1.0>,{local,error_logger},[],[],[]]
Spawned as: proc_lib:init_p/5
Message buffer data: 4 words
Link list: [<0.7.0>,<0.0.0>]
-Dictionary: [{'$initial_call',{gen,init_it,[gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]}},{'$ancestors',[<0.1.0>]}]
+Dictionary: [{'$initial_call',{gen,init_it,[gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]}},{'$ancestors',[<0.1.0>]}]
Reductions 527 stack+heap 1597 old_heap_sz=0
Heap unused=833 OldHeap unused=0
Stack dump:
@@ -88,13 +88,13 @@ y(5) <0.1.0>
y(0) Catch 0x33480C (proc_lib:init_p/5 + 164)
y(1) gen
y(2) init_it
-y(3) [gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]
+y(3) [gen_server,<0.1.0>,<0.1.0>,{local,application_controller},application_controller,{application,kernel,[{description,"ERTS CXC 138 10"},{vsn,"2.6.3.15"},{id,[]},{modules,[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init]},{registered,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2]},{applications,[]},{included_applications,[]},{env,[{error_logger,tty}]},{start_phases,undefined},{maxT,infinity},{maxP,infinity},{mod,{kernel,[]}}]},[]]
--------------------------------------------------
<0.7.0> Waiting.
Spawned as: proc_lib:init_p/5
Message buffer data: 0 words
Link list: [<0.8.0>,<0.5.0>]
-Dictionary: [{'$initial_call',{application_master,init,[<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},normal]}},{'$ancestors',[<0.6.0>]}]
+Dictionary: [{'$initial_call',{application_master,init,[<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},normal]}},{'$ancestors',[<0.6.0>]}]
Reductions 45 stack+heap 377 old_heap_sz=377
Heap unused=306 OldHeap unused=377
Stack dump:
@@ -103,14 +103,14 @@ cp = 0x33480c (proc_lib:init_p/5 + 164)
arity = 0
347174 Return addr 0x33480C (proc_lib:init_p/5 + 164)
-y(0) {state,<0.8.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},[],0,<0.0.0>}
+y(0) {state,<0.8.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},[],0,<0.0.0>}
y(1) <0.5.0>
347180 Return addr 0xFCEC8 (<terminate process normally>)
y(0) Catch 0x33480C (proc_lib:init_p/5 + 164)
y(1) application_master
y(2) init
-y(3) [<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,otp_ring0],[],infinity,infinity},normal]
+y(3) [<0.5.0>,<0.6.0>,{appl_data,kernel,[application_controller,erl_reply,auth,boot_server,code_server,disk_log_server,disk_log_sup,erl_prim_loader,error_logger,file_server,fixtable_server,global_group,global_name_server,heart,init,kernel_config,kernel_sup,net_kernel,net_sup,rex,user,os_server,ddll_server,erl_epmd,inet_db,pg2],undefined,{kernel,[]},[application,application_controller,application_master,application_starter,auth,code,code_aux,code_server,code_server_int,dist_util,erl_boot_server,erl_distribution,erl_open_port,erl_prim_loader,erl_reply,erlang,error_handler,error_logger,file,global,global_group,global_search,group,heart,inet6_tcp,inet6_tcp_dist,inet6_udp,inet_config,inet_hosts,inet_gethost_native,inet_tcp_dist,otp_pre_init,init,kernel,kernel_config,net,net_adm,net_kernel,os,ram_file,rpc,user,user_drv,user_sup,disk_log,disk_log_1,disk_log_server,disk_log_sup,dist_ac,erl_atom_cache,erl_ddll,erl_epmd,erl_external,erts_debug,fixtable_server,gen_tcp,gen_udp,prim_inet,inet,inet_db,inet_dns,inet_parse,inet_res,inet_tcp,inet_udp,pg2,seq_trace,socks5,socks5_auth,socks5_tcp,socks5_udp,wrap_log_reader,erl_init],[],infinity,infinity},normal]
--------------------------------------------------
<0.8.0> Waiting.
Spawned as: application_master:start_it/4
@@ -652,7 +652,7 @@ Not alive
Loaded Modules Information
--------------------------------------------------
-otp_ring0 448
+erl_init 448
init 28000
prim_inet 34800
erl_prim_loader 14187
@@ -1202,7 +1202,7 @@ udp_error
inet_async
inet_reply
empty_out_q
-otp_ring0
+erl_init
boot
init
run
@@ -1285,7 +1285,7 @@ sleep
start_prim_loader
erl_prim_loader
set_path
-'can not start loader'
+'cannot start loader'
add_to_kernel
prim_load_flags
'-loader'
@@ -1304,7 +1304,7 @@ path_flags
'-pz'
get_boot
not_found
-'can not get bootfile'
+'cannot get bootfile'
'bootfile format error'
get_file
script
@@ -1349,7 +1349,7 @@ extension
'-boot/1-fun-0-'
'-bs2ss/1-fun-0-'
'-bs2as/1-fun-0-'
-'can not load'
+'cannot load'
'unexpected command in bootfile'
prim_inet
open
@@ -3071,7 +3071,7 @@ change_group
change_time
master
start_slave
-'can not get remote filer '
+'cannot get remote filer '
start_relay
relay
'Port controlling ~w terminated in file_server'
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index 40f5d44847..75336cedcc 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -301,7 +301,7 @@ table_win(Config) when is_list(Config) ->
Notebook = setup_whitebox_testing(),
Parent = get_top_level_parent(Notebook),
TObj = observer_tv_table:start_link(Parent, [{node,node()}, {type,ets}, {table,#tab{name=foo, id=Table}}]),
- %% Modal can not test edit..
+ %% Modal cannot test edit..
%% TPid = wx_object:get_pid(TObj),
%% TPid ! #wx{event=#wxList{type=command_list_item_activated, itemIndex=12}},
timer:sleep(3000),
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index bf6fd2a421..21c8f4e6c9 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 2.8
+OBSERVER_VSN = 2.8.1
diff --git a/lib/odbc/configure.in b/lib/odbc/configure.in
index 2dec6e5abf..c5cf2786ca 100644
--- a/lib/odbc/configure.in
+++ b/lib/odbc/configure.in
@@ -21,12 +21,6 @@ dnl
dnl define([AC_CACHE_LOAD], )dnl
dnl define([AC_CACHE_SAVE], )dnl
-if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then
- # We do not want to use a common cache!
- cache_file=/dev/null
-fi
-
-
dnl Process this file with autoconf to produce a configure script.
AC_INIT(c_src/odbcserver.c)
diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile
index 553db8a9a4..a6311ceede 100644
--- a/lib/odbc/doc/src/Makefile
+++ b/lib/odbc/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/odbc/doc/src/databases.xml b/lib/odbc/doc/src/databases.xml
index a060f87e46..614c327a46 100644
--- a/lib/odbc/doc/src/databases.xml
+++ b/lib/odbc/doc/src/databases.xml
@@ -65,7 +65,7 @@
<p>Another obstacle is that some drivers do not support scrollable
cursors which has the effect that the only way to traverse the
result set is sequentially, with next, from the first row to the
- last, and once you pass a row you can not go back. This means
+ last, and once you pass a row you cannot go back. This means
that some functions in the interface will not work together with
certain drivers. A similar problem is that not all drivers
support "row count" for select queries, hence resulting in that
diff --git a/lib/odbc/doc/src/error_handling.xml b/lib/odbc/doc/src/error_handling.xml
index 4c80cff12f..8d794d2c99 100644
--- a/lib/odbc/doc/src/error_handling.xml
+++ b/lib/odbc/doc/src/error_handling.xml
@@ -138,7 +138,7 @@
should be run through the erlang port was not compiled for
your platform.</item>
<item>Errors discovered by the ODBC driver - If calls to the
- ODBC-driver fails due to circumstances that can not be
+ ODBC-driver fails due to circumstances that cannot be
controlled by the Erlang ODBC application programmer, an
error string will be dug up from the driver. This string
will be the <c>Reason</c> in the <c>{error, Reason} </c>
diff --git a/lib/odbc/doc/src/getting_started.xml b/lib/odbc/doc/src/getting_started.xml
index f2ff8b8993..b27754ff22 100644
--- a/lib/odbc/doc/src/getting_started.xml
+++ b/lib/odbc/doc/src/getting_started.xml
@@ -50,7 +50,7 @@
and paths to appropriate values. This may differ a lot
between different os's, databases and ODBC drivers. This
is a configuration problem related to the third party product
- and hence we can not give you a standard solution in this guide.</item>
+ and hence we cannot give you a standard solution in this guide.</item>
<item>The Erlang ODBC application consists of both <c>Erlang</c>
and <c>C</c> code. The <c>C</c> code is delivered as a
precompiled executable for windows, solaris and linux (SLES10) in the commercial
diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml
index 2aa55ca99c..dba7663bb9 100644
--- a/lib/odbc/doc/src/notes.xml
+++ b/lib/odbc/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -32,7 +32,22 @@
<p>This document describes the changes made to the odbc application.
</p>
- <section><title>ODBC 2.12.1</title>
+ <section><title>ODBC 2.12.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>ODBC 2.12.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/odbc/doc/src/notes_history.xml b/lib/odbc/doc/src/notes_history.xml
index 22a92f67cd..d0c0a472e7 100644
--- a/lib/odbc/doc/src/notes_history.xml
+++ b/lib/odbc/doc/src/notes_history.xml
@@ -63,7 +63,7 @@
<list type="bulleted">
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
@@ -193,7 +193,7 @@
</item>
<item>
<p>The erlang odbc process will now die normally if a
- connection can not be established. No connection no
+ connection cannot be established. No connection no
process it is expected. And as the client has already
received the error message that would be the reason with
which the erlang process would be stopped, the supervisor
diff --git a/lib/odbc/doc/src/odbc.xml b/lib/odbc/doc/src/odbc.xml
index 4bb1f035f9..9760908855 100644
--- a/lib/odbc/doc/src/odbc.xml
+++ b/lib/odbc/doc/src/odbc.xml
@@ -246,7 +246,7 @@
<p>Closes a connection to a database. This will also
terminate all processes that may have been spawned
when the connection was opened. This call will always succeed.
- If the connection can not be disconnected gracefully it will
+ If the connection cannot be disconnected gracefully it will
be brutally killed. However you may receive an error message
as result if you try to disconnect a connection started by another
process.
diff --git a/lib/odbc/test/odbc_connect_SUITE.erl b/lib/odbc/test/odbc_connect_SUITE.erl
index 261dfc6f20..94ca62b3fb 100644
--- a/lib/odbc/test/odbc_connect_SUITE.erl
+++ b/lib/odbc/test/odbc_connect_SUITE.erl
@@ -259,7 +259,7 @@ not_exist_db(_Config) ->
%%-------------------------------------------------------------------------
no_c_executable() ->
- [{doc,"Test what happens if the port-program can not be found"}].
+ [{doc,"Test what happens if the port-program cannot be found"}].
no_c_executable(_Config) ->
process_flag(trap_exit, true),
Dir = filename:nativename(filename:join(code:priv_dir(odbc),
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index 3f7677a71d..bb21016fad 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.12.1
+ODBC_VSN = 2.12.2
diff --git a/lib/os_mon/Makefile b/lib/os_mon/Makefile
index 1eff8a785a..40ce94e0c7 100644
--- a/lib/os_mon/Makefile
+++ b/lib/os_mon/Makefile
@@ -23,11 +23,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
#
# Macros
#
-ifeq ($(findstring win32,$(TARGET)),win32)
-SUB_DIRECTORIES = src c_src mibs doc/src
-else
-SUB_DIRECTORIES = src c_src mibs doc/src
-endif
+SUB_DIRECTORIES = src c_src doc/src
include vsn.mk
VSN = $(OS_MON_VSN)
diff --git a/lib/os_mon/c_src/cpu_sup.c b/lib/os_mon/c_src/cpu_sup.c
index 17ef48c26e..c96a5c9f7c 100644
--- a/lib/os_mon/c_src/cpu_sup.c
+++ b/lib/os_mon/c_src/cpu_sup.c
@@ -152,6 +152,8 @@ static void util_measure(unsigned int **result_vec, int *result_sz);
#if defined(__sun__)
static unsigned int misc_measure(char* name);
+#elif defined(__linux__)
+static unsigned int misc_measure(char cmd);
#endif
static void sendi(unsigned int data);
static void sendv(unsigned int data[], int ints);
@@ -231,6 +233,11 @@ int main(int argc, char** argv) {
case AVG1: sendi(misc_measure("avenrun_1min")); break;
case AVG5: sendi(misc_measure("avenrun_5min")); break;
case AVG15: sendi(misc_measure("avenrun_15min")); break;
+#elif defined(__linux__)
+ case NPROCS:
+ case AVG1:
+ case AVG5:
+ case AVG15: sendi(misc_measure(cmd)); break;
#elif defined(__OpenBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__DragonFly__)
case NPROCS: bsd_count_procs(); break;
case AVG1: bsd_loadavg(0); break;
@@ -238,7 +245,7 @@ int main(int argc, char** argv) {
case AVG15: bsd_loadavg(2); break;
#endif
#if defined(__sun__) || defined(__linux__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
- case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break;
+ case UTIL: util_measure(&rv,&sz); sendv(rv, sz); break;
#endif
case QUIT: free((void*)rv); return 0;
default: error("Bad command"); break;
@@ -329,6 +336,22 @@ static void bsd_count_procs(void) {
#if defined(__linux__)
+static unsigned int misc_measure(char cmd) {
+ struct sysinfo info;
+
+ if (sysinfo(&info))
+ error(strerror(errno));
+
+ switch (cmd) {
+ case AVG1: return (unsigned int)(info.loads[0] / 256);
+ case AVG5: return (unsigned int)(info.loads[1] / 256);
+ case AVG15: return (unsigned int)(info.loads[2] / 256);
+ case NPROCS: return info.procs;
+ }
+
+ return -1;
+}
+
static cpu_t *read_procstat(FILE *fp, cpu_t *cpu) {
char buffer[BUFFERSIZE];
@@ -357,8 +380,24 @@ static void util_measure(unsigned int **result_vec, int *result_sz) {
FILE *fp;
unsigned int *rv = NULL;
cpu_t cpu;
-
+
+ rv = *result_vec;
+ rv[0] = no_of_cpus;
+
if ( (fp = fopen(PROCSTAT,"r")) == NULL) {
+ if (errno == EACCES) { /* SELinux */
+ rv[1] = 1; /* just the cpu id */
+ ++rv; /* first value is number of cpus */
+ ++rv; /* second value is number of entries */
+ for (i = 0; i < no_of_cpus; ++i) {
+ rv[0] = CU_CPU_ID;
+ rv[1] = i;
+ rv += 1*2;
+ }
+ *result_sz = 2 + 2*1 * no_of_cpus;
+ return;
+ }
+
/* Check if procfs is mounted,
* otherwise:
* try and try again, bad procsfs.
@@ -367,20 +406,19 @@ static void util_measure(unsigned int **result_vec, int *result_sz) {
return;
}
- /*ignore read*/
+ /*ignore read*/
if (fgets(buffer, BUFFERSIZE, fp) == NULL) {
*result_sz = 0;
return;
}
- rv = *result_vec;
- rv[0] = no_of_cpus;
+
rv[1] = CU_VALUES;
++rv; /* first value is number of cpus */
++rv; /* second value is number of entries */
for (i = 0; i < no_of_cpus; ++i) {
read_procstat(fp, &cpu);
-
+
rv[ 0] = CU_CPU_ID; rv[ 1] = cpu.id;
rv[ 2] = CU_USER; rv[ 3] = cpu.user;
rv[ 4] = CU_NICE_USER; rv[ 5] = cpu.nice_user;
diff --git a/lib/os_mon/doc/src/Makefile b/lib/os_mon/doc/src/Makefile
index 354f8ed26b..8e9a4c333c 100644
--- a/lib/os_mon/doc/src/Makefile
+++ b/lib/os_mon/doc/src/Makefile
@@ -39,7 +39,6 @@ XML_APPLICATION_FILES = ref_man.xml
XML_REF3_FILES = cpu_sup.xml \
disksup.xml \
memsup.xml \
- os_mon_mib.xml \
os_sup.xml \
nteventlog.xml
diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml
index 4a878dd704..0910b3c0f3 100644
--- a/lib/os_mon/doc/src/notes.xml
+++ b/lib/os_mon/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the OS_Mon application.</p>
+<section><title>Os_Mon 2.4.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Os_Mon 2.4.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/os_mon/doc/src/os_mon_app.xml b/lib/os_mon/doc/src/os_mon_app.xml
index 99492a2021..c77a9d0411 100644
--- a/lib/os_mon/doc/src/os_mon_app.xml
+++ b/lib/os_mon/doc/src/os_mon_app.xml
@@ -88,33 +88,6 @@
</section>
<section>
- <title>SNMP MIBs</title>
- <p>The following MIBs are defined in OS_Mon:</p>
- <taglist>
- <tag>OTP-OS-MON-MIB</tag>
- <item>
- <p>This MIB contains objects for instrumentation of disk,
- memory and CPU usage of the nodes in the system.</p>
- </item>
- </taglist>
- <p>The MIB is stored in the <c>mibs</c> directory. It is defined
- in SNMPv2 SMI syntax. An SNMPv1 version of the MIB is delivered
- in the <c>mibs/v1</c> directory.</p>
- <p>The compiled MIB is located under <c>priv/mibs</c>, and
- the generated <c>.hrl</c> file under the <c>include</c> directory.
- To compile a MIB that IMPORTS the <c>OTP-OS-MON-MIB</c>, give
- the option <c>{il, ["os_mon/priv/mibs"]}</c> to the MIB compiler.</p>
- <p>If the MIB should be used in a system, it should be loaded into
- an agent with a call to <c>os_mon_mib:load(Agent)</c>, where
- <c>Agent</c> is the pid or registered name of an SNMP agent. Use
- <c>os_mon_mib:unload(Agent)</c> to unload the MIB.
- The implementation of this MIB uses Mnesia to store a cache with
- data needed, which implicates that Mnesia must be up and running.
- The MIB also use functions defined for the <c>OTP-MIB</c>, thus
- that MIB must be loaded as well.</p>
- </section>
-
- <section>
<title>See Also</title>
<p><seealso marker="cpu_sup">cpu_sup(3)</seealso>,
<seealso marker="disksup">disksup(3)</seealso>,
diff --git a/lib/os_mon/doc/src/os_mon_mib.xml b/lib/os_mon/doc/src/os_mon_mib.xml
deleted file mode 100644
index e995bf3de1..0000000000
--- a/lib/os_mon/doc/src/os_mon_mib.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2004</year><year>2018</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>os_mon_mib</title>
- <prepared>Ingela Andin</prepared>
- <responsible></responsible>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>os_mon_mib</module>
- <modulesummary>Loading and Unloading of OTP-OS-MON-MIB</modulesummary>
- <description>
- <p>Functions for loading and unloading the OTP-OS-MON-MIB into/from
- an SNMP agent. The instrumentation of the OTP-OS-MON-MIB uses
- Mnesia, hence Mnesia must be started prior to loading
- the OTP-OS-MON-MIB.</p>
- <warning>
- <p>This module has been deprecated and will be removed in a furture release.</p>
- </warning>
- </description>
- <funcs>
- <func>
- <name>load(Agent) -> ok | {error, Reason}</name>
- <fsummary>Load the OTP-OS-MON-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Loads the OTP-OS-MON-MIB.</p>
- </desc>
- </func>
- <func>
- <name>unload(Agent) -> ok | {error, Reason}</name>
- <fsummary>Unload the OTP-OS-MON-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom() </v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Unloads the OTP-OS-MON-MIB.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>See Also</title>
- <p><seealso marker="os_mon_app">os_mon(6)</seealso>,
- <seealso marker="snmp:snmp">snmp(3)</seealso></p>
- </section>
-</erlref>
-
diff --git a/lib/os_mon/doc/src/ref_man.xml b/lib/os_mon/doc/src/ref_man.xml
index a8f847a8ba..57dd5c5f0b 100644
--- a/lib/os_mon/doc/src/ref_man.xml
+++ b/lib/os_mon/doc/src/ref_man.xml
@@ -36,7 +36,6 @@
<xi:include href="cpu_sup.xml"/>
<xi:include href="disksup.xml"/>
<xi:include href="memsup.xml"/>
- <xi:include href="os_mon_mib.xml"/>
<xi:include href="os_sup.xml"/>
<xi:include href="nteventlog.xml"/>
</application>
diff --git a/lib/os_mon/mibs/Makefile b/lib/os_mon/mibs/Makefile
deleted file mode 100644
index dbc105ee3d..0000000000
--- a/lib/os_mon/mibs/Makefile
+++ /dev/null
@@ -1,101 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(OS_MON_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/os_mon-$(VSN)
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MIB_FILES= OTP-OS-MON-MIB.mib
-FUNCS_FILES = OTP-OS-MON-MIB.funcs
-
-BIN_TARGETS= $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin)
-HRL_TARGETS= $(MIB_FILES:%.mib=$(SNMP_HRL_TARGET_DIR)/%.hrl)
-V1_MIB_FILES= $(MIB_FILES:%.mib=v1/%.mib.v1)
-
-TARGET_FILES= $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-TC.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin \
- $(BIN_TARGETS) $(HRL_TARGETS) $(V1_MIB_FILES)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-SNMP_FLAGS = -I $(SNMP_BIN_TARGET_DIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
- else echo sasl; fi)
-
-$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-TC.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-MIB.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
-v1/%.mib.v1: %.mib
- $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
-
-$(SNMP_BIN_TARGET_DIR)/OTP-OS-MON-MIB.bin: \
- $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
- $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin \
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
- $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
- $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
-
-release_docs_spec:
diff --git a/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs b/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs
deleted file mode 100644
index 7ed76517b9..0000000000
--- a/lib/os_mon/mibs/OTP-OS-MON-MIB.funcs
+++ /dev/null
@@ -1,5 +0,0 @@
-{loadMemorySystemWatermark, {os_mon_mib, mem_sys_mark, []}}.
-{loadMemoryErlProcWatermark, {os_mon_mib, mem_proc_mark, []}}.
-{loadTable, {os_mon_mib, load_table, []}}.
-{diskAlmostFullThreshold, {os_mon_mib, disk_threshold, []}}.
-{diskTable, {os_mon_mib, disk_table, []}}.
diff --git a/lib/os_mon/mibs/OTP-OS-MON-MIB.mib b/lib/os_mon/mibs/OTP-OS-MON-MIB.mib
deleted file mode 100644
index e027e96154..0000000000
--- a/lib/os_mon/mibs/OTP-OS-MON-MIB.mib
+++ /dev/null
@@ -1,423 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 1997-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-OS-MON-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, NOTIFICATION-TYPE, OBJECT-TYPE,
- Counter32, Gauge32, Integer32, Unsigned32, Counter64
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, NOTIFICATION-GROUP, OBJECT-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- erlNodeId
- FROM OTP-MIB
- ;
-
-
-otpOsMonModule MODULE-IDENTITY
- LAST-UPDATED "0305090900Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
-
- DESCRIPTION
- "This MIB is part of the OTP MIB. It defines MIB objects
- for the os_mon application in OTP."
-
- REVISION "0508260900Z"
- DESCRIPTION
- "Removed dependeny on EVA."
- REVISION "0305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "9807080900Z"
- DESCRIPTION
- "Changed MAX-ACCESS for diskDescr from not-accessible to
- read-only."
-
- REVISION "9801270900Z"
- DESCRIPTION
- "Changed erroneous name of this module to otpOsMonModule."
-
- REVISION "9712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
-
- REVISION "9608191700Z"
- DESCRIPTION
- "The initial revision of MIB module OTP-OS-MON-MIB."
- ::= { otpModules 4 }
-
-OTPCounterBasedGauge64 ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The CounterBasedGauge64 type represents a non-negative
- integer, which may increase or decrease, but shall never
- exceed a maximum value, nor fall below a minimum value. The
- maximum value can not be greater than 2^64-1
- (18446744073709551615 decimal), and the minimum value can
-
- not be smaller than 0. The value of a CounterBasedGauge64
- has its maximum value whenever the information being modeled
- is greater than or equal to its maximum value, and has its
- minimum value whenever the information being modeled is
- smaller than or equal to its minimum value. If the
- information being modeled subsequently decreases below
- (increases above) the maximum (minimum) value, the
- CounterBasedGauge64 also decreases (increases).
-
- Note that this TC is not strictly supported in SMIv2,
- because the 'always increasing' and 'counter wrap' semantics
- associated with the Counter64 base type are not preserved.
- It is possible that management applications which rely
- solely upon the (Counter64) ASN.1 tag to determine object
- semantics will mistakenly operate upon objects of this type
- as they would for Counter64 objects.
-
- This textual convention represents a limited and short-term
- solution, and may be deprecated as a long term solution is
- defined and deployed to replace it."
- SYNTAX Counter64
-
-otpOsMonMIB OBJECT IDENTIFIER ::= { otpApplications 2 }
-otpOsMonMIBConformance
- OBJECT IDENTIFIER ::= { otpOsMonMIB 1 }
-otpOsMonMIBObjects
- OBJECT IDENTIFIER ::= { otpOsMonMIB 2 }
-otpOsMonMIBAlarms
- OBJECT IDENTIFIER ::= { otpOsMonMIB 4 }
-otpOsMonMIBAlarmsV2
- OBJECT IDENTIFIER ::= { otpOsMonMIBAlarms 0 }
-
-
--- Datatypes
-
--- Managed Objects
-
-load OBJECT IDENTIFIER ::= { otpOsMonMIBObjects 1 }
-disk OBJECT IDENTIFIER ::= { otpOsMonMIBObjects 2 }
-
-loadMemorySystemWatermark OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the total available system
- memory, which specifies how much memory can be allocated
- by the system before an alarm is sent."
- ::= { load 1 }
-
-loadMemoryErlProcWatermark OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the total available system
- memory, which specifies how much memory can be allocated
- by one Erlang process before an alarm is sent."
- ::= { load 2 }
-
-loadTable OBJECT-TYPE
- SYNTAX SEQUENCE OF LoadEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with load and memory information
- for each node."
- ::= { load 3 }
-
-loadEntry OBJECT-TYPE
- SYNTAX LoadEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the loadTable."
- INDEX { loadErlNodeName }
- ::= { loadTable 1 }
-
-LoadEntry ::= SEQUENCE {
- loadErlNodeName DisplayString,
- loadSystemTotalMemory Gauge32,
- loadSystemUsedMemory Gauge32,
- loadLargestErlProcess DisplayString,
- loadLargestErlProcessUsedMemory Gauge32,
- loadCpuLoad Integer32,
- loadCpuLoad5 Integer32,
- loadCpuLoad15 Integer32,
- loadOsWordsize Unsigned32,
- loadSystemTotalMemory64 OTPCounterBasedGauge64,
- loadSystemUsedMemory64 OTPCounterBasedGauge64,
- loadLargestErlProcessUsedMemory64 OTPCounterBasedGauge64
- }
-
-loadErlNodeName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "The name of the erlang node, e.g. erlnode@host1."
- ::= { loadEntry 1 }
-
-loadSystemTotalMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total memory in the system."
- ::= { loadEntry 2 }
-
-loadSystemUsedMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of used memory."
- ::= { loadEntry 3 }
-
-loadLargestErlProcess OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The process identifier (Pid) of the largest Erlang
- process."
- ::= { loadEntry 4 }
-
-loadLargestErlProcessUsedMemory OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of memory used by the largest Erlang
- process."
- ::= { loadEntry 5 }
-
-loadCpuLoad OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last minute in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 6 }
-
-loadCpuLoad5 OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last 5 minutes in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 7}
-
-loadCpuLoad15 OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The average load the last 15 minutes in percent of the CPU
- where the Erlang node runs."
- ::= { loadEntry 8}
-
-loadOsWordsize OBJECT-TYPE
- SYNTAX Unsigned32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The wordsize of the operating operating system."
- ::= { loadEntry 9 }
-
-loadSystemTotalMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total memory in the system for 64-bit operating system."
- ::= { loadEntry 10 }
-
-loadSystemUsedMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of used memory for 64-bit operating system."
- ::= { loadEntry 11 }
-
-loadLargestErlProcessUsedMemory64 OBJECT-TYPE
- SYNTAX OTPCounterBasedGauge64
- UNITS "bytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of memory used by the largest Erlang
- process for 64-bit operating system.."
- ::= { loadEntry 12 }
-
-diskAlmostFullThreshold OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Threshold in percent of the available disk space,
- which specifies how much disk space can be used by
- a disk or partition before an alarm is sent."
- ::= { disk 1 }
-
-diskTable OBJECT-TYPE
- SYNTAX SEQUENCE OF DiskEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with all local disks or partitions on each
- node."
- ::= { disk 2 }
-
-diskEntry OBJECT-TYPE
- SYNTAX DiskEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the diskTable."
- INDEX { erlNodeId, diskId }
- ::= { diskTable 1 }
-
-DiskEntry ::= SEQUENCE {
- diskId Integer32,
- diskDescr DisplayString,
- diskKBytes Gauge32,
- diskCapacity Integer32
- }
-
-diskId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the disk
- or partition."
- ::= { diskEntry 1 }
-
-diskDescr OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A string that identifies the disk or partition."
- ::= { diskEntry 2 }
-
-diskKBytes OBJECT-TYPE
- SYNTAX Gauge32
- UNITS "kbytes"
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The amount of total disk/partition space. "
- ::= { diskEntry 3 }
-
-diskCapacity OBJECT-TYPE
- SYNTAX Integer32 (0..100)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "How much of the disk's/partition's total capacity has
- been used, in percent."
- ::= { diskEntry 4 }
-
-
--- conformance information
-
-otpOsMonMIBCompliances
- OBJECT IDENTIFIER ::= { otpOsMonMIBConformance 1 }
-otpOsMonMIBGroups
- OBJECT IDENTIFIER ::= { otpOsMonMIBConformance 2 }
-
-
--- compliance statements
-
-otpOsMonBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-OS-MON-MIB."
- MODULE -- this module
- GROUP loadGroup
- DESCRIPTION
- "This group is mandatory for systems implementing the
- load supervison functionality."
- GROUP loadAlarmsGroup
- DESCRIPTION
- "This group is optional for systems implementing the
- load supervison functionality."
- GROUP diskGroup
- DESCRIPTION
- "This group is mandatory for system implementing the
- disk supervison functionality."
- GROUP diskAlarmsGroup
- DESCRIPTION
- "This group is optional for systems implementing the
- disk supervison functionality."
- ::= { otpOsMonMIBCompliances 1 }
-
-
--- units of conformance
-
-loadGroup OBJECT-GROUP
- OBJECTS { loadMemorySystemWatermark,
- loadMemoryErlProcWatermark,
- loadSystemTotalMemory,
- loadSystemUsedMemory,
- loadLargestErlProcess,
- loadLargestErlProcessUsedMemory,
- loadCpuLoad,
- loadCpuLoad5,
- loadCpuLoad15,
- loadOsWordsize,
- loadSystemTotalMemory64,
- loadSystemUsedMemory64,
- loadLargestErlProcessUsedMemory64}
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the load of the OTP system."
- ::= { otpOsMonMIBGroups 1 }
-
-diskGroup OBJECT-GROUP
- OBJECTS { diskAlmostFullThreshold,
- diskDescr,
- diskKBytes,
- diskCapacity }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the disks in the OTP system."
- ::= { otpOsMonMIBGroups 3 }
-
-END
diff --git a/lib/os_mon/mibs/v1/.gitignore b/lib/os_mon/mibs/v1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/os_mon/mibs/v1/.gitignore
+++ /dev/null
diff --git a/lib/os_mon/src/Makefile b/lib/os_mon/src/Makefile
index fc2eb22393..923a31f290 100644
--- a/lib/os_mon/src/Makefile
+++ b/lib/os_mon/src/Makefile
@@ -34,8 +34,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/os_mon-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-MODULES= disksup memsup cpu_sup os_mon os_mon_mib os_sup os_mon_sysinfo \
- nteventlog
+MODULES= disksup memsup cpu_sup os_mon os_sup os_mon_sysinfo nteventlog
INCLUDE=../include
CSRC=../c_src
diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl
index 81e049ef22..ba2d89313e 100644
--- a/lib/os_mon/src/cpu_sup.erl
+++ b/lib/os_mon/src/cpu_sup.erl
@@ -220,17 +220,21 @@ code_change(_OldVsn, State, _Extra) ->
%% internal functions
%%----------------------------------------------------------------------
-get_uint32_measurement(Request, #internal{os_type = {unix, linux}}) ->
- {ok,F} = file:open("/proc/loadavg",[read,raw]),
- {ok,D} = file:read_line(F),
- ok = file:close(F),
- {ok,[Load1,Load5,Load15,_PRun,PTotal],_} = io_lib:fread("~f ~f ~f ~d/~d", D),
- case Request of
- ?avg1 -> sunify(Load1);
- ?avg5 -> sunify(Load5);
- ?avg15 -> sunify(Load15);
- ?ping -> 4711;
- ?nprocs -> PTotal
+get_uint32_measurement(Request, #internal{port = P, os_type = {unix, linux}}) ->
+ case file:open("/proc/loadavg",[read,raw]) of
+ {ok,F} ->
+ {ok,D} = file:read_line(F),
+ ok = file:close(F),
+ {ok,[Load1,Load5,Load15,_PRun,PTotal],_} = io_lib:fread("~f ~f ~f ~d/~d", D),
+ case Request of
+ ?avg1 -> sunify(Load1);
+ ?avg5 -> sunify(Load5);
+ ?avg15 -> sunify(Load15);
+ ?ping -> 4711;
+ ?nprocs -> PTotal
+ end;
+ {error,_} ->
+ port_server_call(P, Request)
end;
get_uint32_measurement(Request, #internal{port = P, os_type = {unix, Sys}}) when
Sys == sunos;
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index 9d6447430d..b69d657aa7 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -701,6 +701,7 @@ get_os_wordsize_with_uname() ->
"sparc64" -> 64;
"amd64" -> 64;
"ppc64" -> 64;
+ "ppc64le" -> 64;
"s390x" -> 64;
_ -> 32
end.
diff --git a/lib/os_mon/src/os_mon.app.src b/lib/os_mon/src/os_mon.app.src
index 8be94f65d4..6c9b0d7576 100644
--- a/lib/os_mon/src/os_mon.app.src
+++ b/lib/os_mon/src/os_mon.app.src
@@ -21,7 +21,7 @@
{application, os_mon,
[{description, "CPO CXC 138 46"},
{vsn, "%VSN%"},
- {modules, [os_mon, os_mon_mib, os_sup,
+ {modules, [os_mon, os_sup,
disksup, memsup, cpu_sup, os_mon_sysinfo, nteventlog]},
{registered, [os_mon_sup, os_mon_sysinfo, disksup, memsup, cpu_sup,
os_sup_server]},
@@ -31,6 +31,4 @@
{start_memsup, true},
{start_os_sup, false}]},
{mod, {os_mon, []}},
- {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","sasl-2.4",
- "otp_mibs-1.0.9","mnesia-4.12","kernel-3.0",
- "erts-6.0"]}]}.
+ {runtime_dependencies, ["stdlib-2.0","sasl-2.4","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/os_mon/src/os_mon_mib.erl b/lib/os_mon/src/os_mon_mib.erl
deleted file mode 100644
index 9b5d2fbba6..0000000000
--- a/lib/os_mon/src/os_mon_mib.erl
+++ /dev/null
@@ -1,251 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(os_mon_mib).
-%%%-----------------------------------------------------------------
-%%% Description: This module implements the OS-MON-MIB.
-%%% The tables are implemented as shadow tables with the module
-%%% snmp_shadow_table. Here the update functions are implemented.
-%%%-----------------------------------------------------------------
-
--include("../../otp_mibs/include/OTP-MIB.hrl").
-
-%% API
--export([load/1, unload/1]).
-
-%% Deprecated API
--export([init/1, stop/1]).
-
--deprecated([{init,1,eventually},
- {stop,1,eventually}]).
-
-%% SNMP instrumentation
--export([load_table/1, load_table/3, disk_table/1, disk_table/3,
- mem_sys_mark/1, mem_proc_mark/1, disk_threshold/1]).
-
-%% SNMP shadow functions
--export([update_load_table/0, update_disk_table/0]).
-
-%% Exported for internal use via rpc
--export([get_load/1, get_disks/1]).
-
-%% Shadow tables
--record(loadTable, {
- loadErlNodeName,
- loadSystemTotalMemory,
- loadSystemUsedMemory,
- loadLargestErlProcess,
- loadLargestErlProcessUsedMemory,
- loadCpuLoad,
- loadCpuLoad5,
- loadCpuLoad15,
- loadOsWordsize,
- loadSystemTotalMemory64,
- loadSystemUsedMemory64,
- loadLargestErlProcessUsedMemory64}).
-
--record(diskTable,
- {key, diskDescr, diskKBytes, diskCapacity}).
-
-%% Shadow argument macros
--define(loadShadowArgs,
- {loadTable, string, record_info(fields, loadTable), 5000,
- fun os_mon_mib:update_load_table/0}).
-
--define(diskShadowArgs,
- {diskTable, {integer, integer}, record_info(fields, diskTable), 5000,
- fun os_mon_mib:update_disk_table/0}).
-
-%% Misc
--record(diskAlloc, {diskDescr, diskId}).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-%%-------------------------------------------------------------------------
-%% load(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-OS-MON-MIB
-%%-------------------------------------------------------------------------
-load(Agent) ->
- MibDir = filename:join(code:priv_dir(os_mon), "mibs"),
- snmpa:load_mibs(Agent, [filename:join(MibDir, "OTP-OS-MON-MIB")]).
-
-%%-------------------------------------------------------------------------
-%% unload(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Unloads the OTP-OS-MON-MIB
-%%-------------------------------------------------------------------------
-unload(Agent) ->
- snmpa:unload_mibs(Agent, ["OTP-OS-MON-MIB"]).
-
-%% To be backwards compatible
-init(Agent) ->
- load(Agent).
-stop(Agent) ->
- unload(Agent).
-
-%%%=========================================================================
-%%% SNMP instrumentation
-%%%=========================================================================
-load_table(Op) ->
- snmp_shadow_table:table_func(Op, ?loadShadowArgs).
-load_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?loadShadowArgs).
-
-disk_table(new) ->
- Tab = diskAlloc,
- Storage = ram_copies,
- case lists:member(Tab, mnesia:system_info(tables)) of
- true ->
- case mnesia:table_info(Tab, storage_type) of
- unknown ->
- {atomic, ok}=mnesia:add_table_copy(Tab, node(), Storage);
- Storage ->
- catch delete_all(Tab)
- end;
- false ->
- Nodes = [node()],
- Props = [{type, set},
- {attributes, record_info(fields, diskAlloc)},
- {local_content, true},
- {Storage, Nodes}],
- {atomic, ok} = mnesia:create_table(Tab, Props)
-
- end,
- Rec = #diskAlloc{diskDescr = next_index, diskId = 1},
- ok = mnesia:dirty_write(Rec),
- snmp_shadow_table:table_func(new, ?diskShadowArgs).
-
-disk_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?diskShadowArgs).
-
-mem_sys_mark(get) ->
- {value, memsup:get_sysmem_high_watermark()};
-mem_sys_mark(_) ->
- ok.
-
-mem_proc_mark(get) ->
- {value, memsup:get_procmem_high_watermark()};
-mem_proc_mark(_) ->
- ok.
-
-disk_threshold(get) ->
- {value, disksup:get_almost_full_threshold()};
-disk_threshold(_) ->
- ok.
-
-%%%=========================================================================
-%%% SNMP shadow functions
-%%%=========================================================================
-update_load_table() ->
- delete_all(loadTable),
- lists:foreach(
- fun(Node) ->
- case rpc:call(Node, os_mon_mib, get_load, [Node]) of
- Load when is_record(Load,loadTable) ->
- ok = mnesia:dirty_write(Load);
- _Else ->
- ok
- end
- end, [node() | nodes()]).
-
-
-update_disk_table() ->
- delete_all(diskTable),
- node_update_disk_table(
- otp_mib:erl_node_table(get_next, [], [?erlNodeName,?erlNodeOutBytes])).
-
-%%%========================================================================
-%%% Exported for internal use via rpc
-%%%========================================================================
-get_load(Node) ->
- {Total, Allocated, PidString, PidAllocated} = case memsup:get_memory_data() of
- {MemTot, MemAlloc, undefined} -> {MemTot, MemAlloc, "undefined", 0};
- {MemTot, MemAlloc, {Pid, PidMem}} -> {MemTot, MemAlloc, pid_to_str(Pid), PidMem}
- end,
- OsWordsize = case memsup:get_os_wordsize() of
- WS when is_integer(WS) -> WS;
- _ -> 0
- end,
- #loadTable{
- loadErlNodeName = atom_to_list(Node),
- loadSystemTotalMemory = mask_int32(Total),
- loadSystemUsedMemory = mask_int32(Allocated),
- loadLargestErlProcess = PidString,
- loadLargestErlProcessUsedMemory = mask_int32(PidAllocated),
- loadCpuLoad = get_cpu_load(avg1),
- loadCpuLoad5 = get_cpu_load(avg5),
- loadCpuLoad15 = get_cpu_load(avg15),
- loadOsWordsize = OsWordsize,
- loadSystemTotalMemory64 = Total,
- loadSystemUsedMemory64 = Allocated,
- loadLargestErlProcessUsedMemory64 = PidAllocated
- }.
-
-mask_int32(Value) -> Value band ((1 bsl 32) - 1).
-
-get_disks(NodeId) ->
- element(1,
- lists:mapfoldl(
- fun({Descr, KByte, Capacity}, DiskId) ->
- {#diskTable{key = {NodeId, DiskId},
- diskDescr = Descr,
- diskKBytes = KByte,
- diskCapacity = Capacity},
- DiskId + 1}
- end, 1, disksup:get_disk_data())).
-
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-node_update_disk_table([_, endOfTable]) ->
- ok;
-
-node_update_disk_table([{[?erlNodeName | IndexList], NodeStr}, _]) ->
- Disks = rpc:call(list_to_atom(NodeStr), os_mon_mib, get_disks,
- IndexList),
- lists:foreach(fun(Disk) ->
- mnesia:dirty_write(Disk)
- end, Disks),
- node_update_disk_table(otp_mib:erl_node_table(get_next,
- IndexList,
- [?erlNodeName,
- ?erlNodeOutBytes])).
-
-get_cpu_load(X) when X == avg1; X == avg5; X == avg15 ->
- case erlang:round(apply(cpu_sup, X, [])/2.56) of
- Large when Large > 100 ->
- 100;
- Load ->
- Load
- end.
-
-delete_all(Name) -> delete_all(mnesia:dirty_first(Name), Name).
-delete_all('$end_of_table', _Name) -> done;
-delete_all(Key, Name) ->
- Next = mnesia:dirty_next(Name, Key),
- ok = mnesia:dirty_delete({Name, Key}),
- delete_all(Next, Name).
-
-pid_to_str(Pid) -> lists:flatten(io_lib:format("~w", [Pid])).
diff --git a/lib/os_mon/test/Makefile b/lib/os_mon/test/Makefile
index 6ac67e6bae..03c73b95ec 100644
--- a/lib/os_mon/test/Makefile
+++ b/lib/os_mon/test/Makefile
@@ -30,7 +30,6 @@ MODULES= \
disksup_SUITE \
memsup_SUITE \
cpu_sup_SUITE \
- os_mon_mib_SUITE \
os_sup_SUITE \
os_mon_conf
@@ -87,7 +86,6 @@ release_tests_spec: make_emakefile
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DATA) os_mon.spec os_mon.cover os_mon_smoke.spec \
$(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
- $(INSTALL_DATA) os_mon_mib_SUITE.cfg "$(RELSYSDIR)"
## tar chf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
diff --git a/lib/os_mon/test/os_mon.spec b/lib/os_mon/test/os_mon.spec
index 4b4286b313..d292b258f3 100644
--- a/lib/os_mon/test/os_mon.spec
+++ b/lib/os_mon/test/os_mon.spec
@@ -1,2 +1 @@
{suites,"../os_mon_test",all}.
-{config,"os_mon_mib_SUITE.cfg"}. \ No newline at end of file
diff --git a/lib/os_mon/test/os_mon_mib_SUITE.cfg b/lib/os_mon/test/os_mon_mib_SUITE.cfg
deleted file mode 100644
index a33c23530b..0000000000
--- a/lib/os_mon/test/os_mon_mib_SUITE.cfg
+++ /dev/null
@@ -1,8 +0,0 @@
-%% -*- erlang -*-
-{snmp, [{start_agent,true},
- {users,[{os_mon_mib_test,[snmpm_user_default,[]]}]},
- {managed_agents,[{os_mon_mib_test,
- [os_mon_mib_test, {127,0,0,1}, 4000, []]}]},
- {agent_sysname,"Test os_mon_mibs"},
- {mgr_port,5001}
- ]}.
diff --git a/lib/os_mon/test/os_mon_mib_SUITE.erl b/lib/os_mon/test/os_mon_mib_SUITE.erl
deleted file mode 100644
index f40d5f442c..0000000000
--- a/lib/os_mon/test/os_mon_mib_SUITE.erl
+++ /dev/null
@@ -1,578 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(os_mon_mib_SUITE).
-
-%%-----------------------------------------------------------------
-%% This suite can no longer be executed standalone, i.e. it must be
-%% executed with common test. The reason is that ct_snmp is used
-%% instead of the snmp application directly. The suite requires a
-%% config file, os_mon_mib_SUITE.cfg, found in the same directory as
-%% the suite.
-%%
-%% Execute with:
-%% > ct_run -suite os_mon_mib_SUITE -config os_mon_mib_SUITE.cfg
-%%-----------------------------------------------------------------
-
--include_lib("common_test/include/ct.hrl").
--include_lib("os_mon/include/OTP-OS-MON-MIB.hrl").
--include_lib("snmp/include/snmp_types.hrl").
-
-% Test server specific exports
--export([all/0, suite/0, groups/0,
- init_per_suite/1, end_per_suite/1]).
-
-
-% Test cases must be exported.
--export([update_load_table/1]).
-
--export([get_mem_sys_mark/1, get_mem_proc_mark/1, get_disk_threshold/1,
- get_load_table/1, get_disk_table/1,
- real_snmp_request/1, load_unload/1]).
-
--export([sys_tot_mem/1, sys_used_mem/1, large_erl_process/1,
- large_erl_process_mem/1, cpu_load/1, cpu_load5/1, cpu_load15/1,
- os_wordsize/1, sys_tot_mem64/1, sys_used_mem64/1,
- large_erl_process_mem64/1, disk_descr/1, disk_kbytes/1,
- disk_capacity/1]).
-
--export([otp_6351/1, otp_7441/1]).
-
--define(TRAP_UDP, 5000).
--define(AGENT_UDP, 4000).
--define(CONF_FILE_VER, [v2]).
--define(SYS_NAME, "Test os_mon_mibs").
--define(MAX_MSG_SIZE, 484).
--define(ENGINE_ID, "mgrEngine").
--define(MGR_PORT, 5001).
-
-%%---------------------------------------------------------------------
-
-suite() ->
- [{ct_hooks,[ts_install_cth]},
- {timetrap,{minutes,6}},
- {require, snmp_mgr_agent, snmp}].
-
-all() ->
- [load_unload, get_mem_sys_mark, get_mem_proc_mark,
- get_disk_threshold, get_load_table,
- {group, get_next_load_table}, get_disk_table,
- {group, get_next_disk_table}, real_snmp_request,
- update_load_table, {group, tickets}].
-
-groups() ->
- [{tickets, [], [otp_6351, otp_7441]},
- {get_next_load_table, [],
- [sys_tot_mem, sys_used_mem, large_erl_process,
- large_erl_process_mem, cpu_load, cpu_load5, cpu_load15,
- os_wordsize, sys_tot_mem64, sys_used_mem64,
- large_erl_process_mem64]},
- {get_next_disk_table, [],
- [disk_descr, disk_kbytes, disk_capacity]}].
-
-
-%%---------------------------------------------------------------------
-%%--------------------------------------------------------------------
-%% Function: init_per_suite(Config) -> Config
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Initiation before the whole suite
-%%
-%% Note: This function is free to add any key/value pairs to the Config
-%% variable, but should NOT alter/remove any existing entries.
-%%--------------------------------------------------------------------
-init_per_suite(Config) ->
- application:start(sasl),
- application:start(mnesia),
- application:start(os_mon),
-
- ok = ct_snmp:start(Config,snmp_mgr_agent),
-
- %% Load the mibs that should be tested
- otp_mib:load(snmp_master_agent),
- os_mon_mib:load(snmp_master_agent),
-
- Config.
-%%--------------------------------------------------------------------
-%% Function: end_per_suite(Config) -> _
-%% Config - [tuple()]
-%% A list of key/value pairs, holding the test case configuration.
-%% Description: Cleanup after the whole suite
-%%--------------------------------------------------------------------
-end_per_suite(Config) ->
- PrivDir = proplists:get_value(priv_dir, Config),
- ConfDir = filename:join(PrivDir,"conf"),
- DbDir = filename:join(PrivDir,"db"),
- MgrDir = filename:join(PrivDir, "mgr"),
-
- %% Uload mibs
- snmpa:unload_mibs(snmp_master_agent,["OTP-OS-MON-MIB"]),
- otp_mib:unload(snmp_master_agent),
-
- %% Clean up
- application:stop(snmp),
- application:stop(mnesia),
- application:stop(os_mon),
-
- del_dir(ConfDir),
- del_dir(DbDir),
- (catch del_dir(MgrDir)),
- ok.
-
-%%---------------------------------------------------------------------
-%% Test cases
-%%---------------------------------------------------------------------
-
-%% Test to unload and the reload the OTP.mib
-load_unload(Config) when is_list(Config) ->
- os_mon_mib:unload(snmp_master_agent),
- os_mon_mib:load(snmp_master_agent),
- ok.
-%%---------------------------------------------------------------------
-
-%% check os_mon_mib:update_load_table error handling
-update_load_table(Config) when is_list(Config) ->
- Node = start_node(),
- ok = rpc:call(Node,application,start,[sasl]),
- ok = rpc:call(Node,application,start,[os_mon]),
- ok = os_mon_mib:update_load_table(),
- rpc:call(Node,application,stop,[os_mon]),
- ok = os_mon_mib:update_load_table(),
- stop_node(Node),
- ok.
-
-%% like update_load_table, when memsup_system_only==true
-otp_6351(Config) when is_list(Config) ->
- Node = start_node(),
- ok = rpc:call(Node,application,start,[sasl]),
- ok = rpc:call(Node,application,load,[os_mon]),
- ok = rpc:call(Node,application,set_env,
- [os_mon,memsup_system_only,true]),
- ok = rpc:call(Node,application,start,[os_mon]),
- Res = rpc:call(Node,os_mon_mib,get_load,[Node]),
- if
- is_tuple(Res), element(1, Res)==loadTable ->
- ok;
- true ->
- ct:fail(Res)
- end,
- rpc:call(Node,application,stop,[os_mon]),
- stop_node(Node),
- ok.
-
-
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the loadMemorySystemWatermark variable.
-get_mem_sys_mark(Config) when is_list(Config) ->
- case os_mon_mib:mem_sys_mark(get) of
- {value, SysMark} when is_integer(SysMark) ->
- ok;
- _ ->
- ct:fail(sys_mark_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the loadMemoryErlProcWatermark variable.
-get_mem_proc_mark(Config) when is_list(Config) ->
- case os_mon_mib:mem_proc_mark(get) of
- {value, ProcMark} when is_integer(ProcMark) ->
- ok;
- _ ->
- ct:fail(proc_mark_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates a get call to test the instrumentation function
-%% for the diskAlmostFullThreshold variable.
-get_disk_threshold(Config) when is_list(Config) ->
- case os_mon_mib:disk_threshold(get) of
- {value, ProcMark} when is_integer(ProcMark) ->
- ok;
- _ ->
- ct:fail(disk_threshold_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-
-%%% Note that when we have a string key, as in loadTable, the
-%%% instrumentation will deal with the [length(String), String]. We
-%%% have to know about this, when short cutting SNMP and calling
-%%% instrumentation functions directly as done in most test cases in
-%%% this test suite
-
-%% Simulates get calls to test the instrumentation function
-%% for the loadTable
-get_load_table(Config) when is_list(Config) ->
-
- NodeStr = atom_to_list(node()),
- NodeLen = length(NodeStr),
-
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- [{value, NodeStr},{value, PidStr}] =
- os_mon_mib:load_table(get, [NodeLen | NodeStr],
- [?loadErlNodeName, ?loadLargestErlProcess]),
-
- Values = os_mon_mib:load_table(get, [NodeLen | NodeStr] ,
- [?loadSystemTotalMemory,
- ?loadSystemUsedMemory,
- ?loadLargestErlProcessUsedMemory,
- ?loadCpuLoad,
- ?loadCpuLoad5,
- ?loadCpuLoad15,
- ?loadOsWordsize,
- ?loadSystemTotalMemory64,
- ?loadSystemUsedMemory64,
- ?loadLargestErlProcessUsedMemory64]),
-
- IsInt = fun({value, Val}) when is_integer(Val) ->
- true;
- (_) ->
- false
- end,
-
- NewValues = lists:filter(IsInt, Values),
-
- case length(NewValues) of
- 10 ->
- ok;
- _ ->
- ct:fail(value_not_integer)
- end,
-
- [{noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance}] =
- os_mon_mib:load_table(get, [3, 102, 111, 111],
- [?loadErlNodeName,
- ?loadSystemTotalMemory,
- ?loadSystemUsedMemory,
- ?loadLargestErlProcess,
- ?loadLargestErlProcessUsedMemory,
- ?loadCpuLoad,
- ?loadCpuLoad5,
- ?loadCpuLoad15,
- ?loadOsWordsize,
- ?loadSystemTotalMemory64,
- ?loadSystemUsedMemory64,
- ?loadLargestErlProcessUsedMemory64]),
-
- ok.
-%%---------------------------------------------------------------------
-
-sys_tot_mem(Config) when is_list(Config) ->
- [{[?loadSystemTotalMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_tot_mem_value_not_integer)
- end.
-
-sys_used_mem(Config) when is_list(Config) ->
- [{[?loadSystemUsedMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_used_mem_value_not_integer)
- end.
-
-large_erl_process(Config) when is_list(Config) ->
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- [{[?loadLargestErlProcess, Len | NodeStr], PidStr}] =
- os_mon_mib:load_table(get_next,[], [?loadLargestErlProcess]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
- ok.
-
-large_erl_process_mem(Config) when is_list(Config) ->
-
- [{[?loadLargestErlProcessUsedMemory, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[],
- [?loadLargestErlProcessUsedMemory]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(erl_pid_mem_value_not_integer)
- end.
-
-cpu_load(Config) when is_list(Config) ->
- [{[?loadCpuLoad, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load_value_not_integer)
- end.
-
-cpu_load5(Config) when is_list(Config) ->
- [{[?loadCpuLoad5, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad5]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load5_value_not_integer)
- end.
-
-cpu_load15(Config) when is_list(Config) ->
- [{[?loadCpuLoad15, Len | NodeStr], Load}] =
- os_mon_mib:load_table(get_next,[], [?loadCpuLoad15]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Load of
- Load when is_integer(Load) ->
- ok;
- _ ->
- ct:fail(cpu_load15_value_not_integer)
- end.
-
-os_wordsize(Config) when is_list(Config) ->
- [{[?loadOsWordsize, Len | NodeStr], Wordsize}] =
- os_mon_mib:load_table(get_next,[], [?loadOsWordsize]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Wordsize of
- Wordsize when is_integer(Wordsize) ->
- ok;
- _ ->
- ct:fail(os_wordsize_value_not_integer)
- end.
-
-sys_tot_mem64(Config) when is_list(Config) ->
- [{[?loadSystemTotalMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next, [], [?loadSystemTotalMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_tot_mem_value_not_integer)
- end.
-
-sys_used_mem64(Config) when is_list(Config) ->
- [{[?loadSystemUsedMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[], [?loadSystemUsedMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(sys_used_mem_value_not_integer)
- end.
-
-large_erl_process_mem64(Config) when is_list(Config) ->
-
- [{[?loadLargestErlProcessUsedMemory64, Len | NodeStr], Mem}] =
- os_mon_mib:load_table(get_next,[],
- [?loadLargestErlProcessUsedMemory64]),
- Len = length(NodeStr),
- true = lists:member(list_to_atom(NodeStr), [node() | nodes()]),
-
- case Mem of
- Mem when is_integer(Mem) ->
- ok;
- _ ->
- ct:fail(erl_pid_mem_value_not_integer)
- end.
-%%---------------------------------------------------------------------
-%% Simulates get calls to test the instrumentation function
-%% for the diskTable.
-get_disk_table(Config) when is_list(Config) ->
-
- DiskData = disksup:get_disk_data(),
- DiskDataLen = length(DiskData),
-
- if
- DiskDataLen > 0 ->
- [{value, Value}] =
- os_mon_mib:disk_table(get, [1,1], [?diskDescr]),
-
- case is_list(Value) of
- true ->
- ok;
- false ->
- ct:fail(value_not_a_string)
- end,
-
- Values = os_mon_mib:disk_table(get, [1,1],
- [?diskId,
- ?diskKBytes,
- ?diskCapacity]),
-
- IsInt = fun({value, Val}) when is_integer(Val) ->
- true;
- (_) ->
- false
- end,
-
- NewValues = lists:filter(IsInt, Values),
-
- case length(NewValues) of
- 3 ->
- ok;
- _ ->
- ct:fail(value_not_integer)
- end
- end,
-
- [{noValue,noSuchInstance}, {noValue,noSuchInstance},
- {noValue,noSuchInstance}, {noValue,noSuchInstance}] =
- os_mon_mib:disk_table(get, [1, DiskDataLen + 1], [?diskId,
- ?diskDescr,
- ?diskKBytes,
- ?diskCapacity]),
-
- ok.
-
-%%---------------------------------------------------------------------
-
-disk_descr(Config) when is_list(Config) ->
- [{[?diskDescr, 1,1], Descr}] =
- os_mon_mib:disk_table(get_next, [], [?diskDescr]),
-
- case Descr of
- Descr when is_list(Descr) ->
- ok;
- _ ->
- ct:fail(disk_descr_value_not_a_string)
- end.
-
-disk_kbytes(Config) when is_list(Config) ->
- [{[?diskKBytes, 1,1], Kbytes}] =
- os_mon_mib:disk_table(get_next,[], [?diskKBytes]),
-
- case Kbytes of
- Kbytes when is_integer(Kbytes) ->
- ok;
- _ ->
- ct:fail(disk_kbytes_value_not_integer)
- end.
-
-
-disk_capacity(Config) when is_list(Config) ->
- [{[?diskCapacity, 1,1], Capacity}] =
- os_mon_mib:disk_table(get_next,[], [?diskCapacity]),
-
- case Capacity of
- Capacity when is_integer(Capacity) ->
- ok;
- _ ->
- ct:fail(disk_capacity_value_not_integer)
- end.
-
-%%---------------------------------------------------------------------
-%% Starts an snmp manager and sends a real snmp-request. i.e.
-%% sends a udp message on the correct format.
-real_snmp_request(Config) when is_list(Config) ->
- NodStr = atom_to_list(node()),
- Len = length(NodStr),
- {_, _, {Pid, _}} = memsup:get_memory_data(),
- PidStr = lists:flatten(io_lib:format("~w", [Pid])),
- io:format("FOO: ~p~n", [PidStr]),
- ok = snmp_get([?loadEntry ++
- [?loadLargestErlProcess, Len | NodStr]],
- PidStr),
- ok = snmp_get_next([?loadEntry ++
- [?loadSystemUsedMemory, Len | NodStr]],
- ?loadEntry ++ [?loadSystemUsedMemory + 1, Len
- | NodStr], PidStr),
- ok = snmp_set([?loadEntry ++ [?loadLargestErlProcess, Len | NodStr]],
- s, "<0.101.0>", Config),
- ok.
-
-%% Starts an snmp manager and requests total memory. Was previously
-%% integer32 which was errornous on 64 bit machines.
-otp_7441(Config) when is_list(Config) ->
- NodStr = atom_to_list(node()),
- Len = length(NodStr),
- Oids = [Oid|_] = [?loadEntry ++ [?loadSystemTotalMemory, Len | NodStr]],
- {noError,0,[#varbind{oid = Oid, variabletype = 'Unsigned32'}]} =
- ct_snmp:get_values(os_mon_mib_test, Oids, snmp_mgr_agent),
-
- ok.
-
-%%---------------------------------------------------------------------
-%% Internal functions
-%%---------------------------------------------------------------------
-start_node() ->
- Pa = filename:dirname(code:which(?MODULE)),
- {ok,Node} = test_server:start_node(testnisse, slave, [{args, " -pa " ++ Pa}]),
- Node.
-
-stop_node(Node) ->
- test_server:stop_node(Node).
-
-del_dir(Dir) ->
- io:format("Deleting: ~s~n",[Dir]),
- {ok, Files} = file:list_dir(Dir),
- FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end,
- Files),
- lists:foreach(fun file:delete/1, FullPathFiles),
- file:del_dir(Dir).
-
-%%---------------------------------------------------------------------
-snmp_get(Oids = [Oid |_], Result) ->
- {noError,0,[#varbind{oid = Oid,
- variabletype = 'OCTET STRING',
- value = Result}]} =
- ct_snmp:get_values(os_mon_mib_test, Oids, snmp_mgr_agent),
- ok.
-
-snmp_get_next(Oids, NextOid, Result) ->
- {noError,0,[#varbind{oid = NextOid,
- variabletype = 'OCTET STRING',
- value = Result}]} =
- ct_snmp:get_next_values(os_mon_mib_test, Oids, snmp_mgr_agent),
- ok.
-
-snmp_set(Oid, ValuType, Value, Config) ->
- {notWritable, _, _} =
- ct_snmp:set_values(os_mon_mib_test, [{Oid, ValuType, Value}],
- snmp_mgr_agent, Config),
- ok.
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index 4a327e5506..0c62c3db35 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.4.5
+OS_MON_VSN = 2.4.6
diff --git a/lib/otp_mibs/AUTHORS b/lib/otp_mibs/AUTHORS
deleted file mode 100644
index 3f570082f4..0000000000
--- a/lib/otp_mibs/AUTHORS
+++ /dev/null
@@ -1,8 +0,0 @@
-Original Authors and Contributors:
-
-Martin Bj�rklund
-Lars Thorsen
-Claes Wikstr�m
-Kent Boortz
-Bj�rn Gustavsson
-Ingela Anderton - Created otp_mibs app. to eliminate SASL's SNMP dependence.
diff --git a/lib/otp_mibs/Makefile b/lib/otp_mibs/Makefile
deleted file mode 100644
index 64bd683c7a..0000000000
--- a/lib/otp_mibs/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Macros
-# ----------------------------------------------------
-
-SUB_DIRECTORIES = src mibs doc/src
-
-include vsn.mk
-VSN = $(OTP_MIBS_VSN)
-
-SPECIAL_TARGETS =
-
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/otp_mibs/doc/html/.gitignore b/lib/otp_mibs/doc/html/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/html/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/man3/.gitignore b/lib/otp_mibs/doc/man3/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/man3/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/pdf/.gitignore b/lib/otp_mibs/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/doc/src/Makefile b/lib/otp_mibs/doc/src/Makefile
deleted file mode 100644
index 143d9befb8..0000000000
--- a/lib/otp_mibs/doc/src/Makefile
+++ /dev/null
@@ -1,116 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2017. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(OTP_MIBS_VSN)
-APPLICATION=otp_mibs
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = otp_mib.xml
-
-XML_PART_FILES = part.xml
-XML_CHAPTER_FILES = \
- introduction.xml \
- mibs.xml \
- notes.xml
-
-BOOK_FILES = book.xml
-
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_APPLICATION_FILES)
-
-GIF_FILES =
-
-# ----------------------------------------------------
-
-HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
- $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
-
-INFO_FILE = ../../info
-
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
-
-TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-XML_FLAGS +=
-DVIPS_FLAGS +=
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-$(HTMLDIR)/%.gif: %.gif
- $(INSTALL_DATA) $< $@
-
-docs: pdf html man
-
-$(TOP_PDF_FILE): $(XML_FILES)
-
-pdf: $(TOP_PDF_FILE)
-
-html: gifs $(HTML_REF_MAN_FILE)
-
-man: $(MAN3_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-debug opt:
-
-clean clean_docs:
- rm -rf $(HTMLDIR)/*
- rm -rf $(XMLDIR)
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_docs_spec: docs
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DATA) $(TOP_PDF_FILE) "$(RELSYSDIR)/doc/pdf"
- $(INSTALL_DIR) "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(HTMLDIR)/* \
- "$(RELSYSDIR)/doc/html"
- $(INSTALL_DATA) $(INFO_FILE) "$(RELSYSDIR)"
- $(INSTALL_DIR) "$(RELEASE_PATH)/man/man3"
- $(INSTALL_DATA) $(MAN3DIR)/* "$(RELEASE_PATH)/man/man3"
-
-release_spec:
diff --git a/lib/otp_mibs/doc/src/book.xml b/lib/otp_mibs/doc/src/book.xml
deleted file mode 100644
index 482da46876..0000000000
--- a/lib/otp_mibs/doc/src/book.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-04-15</date>
- <rev>A</rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>OTP_Mibs application</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <index></index>
-</book>
-
-
diff --git a/lib/otp_mibs/doc/src/introduction.xml b/lib/otp_mibs/doc/src/introduction.xml
deleted file mode 100644
index 7046cbb8ae..0000000000
--- a/lib/otp_mibs/doc/src/introduction.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Introduction</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-05-19</date>
- <rev>A</rev>
- <file>introduction.xml</file>
- </header>
-
- <section>
- <title>Purpose</title>
- <p>The purpose of the OTP_Mibs application is to provide an SNMP
- management information base for Erlang nodes.</p>
- </section>
-
- <section>
- <title>Pre-requisites</title>
- <p>It is assumed that the reader is familiar with the Erlang
- programming language, concepts of OTP and has a basic knowledge
- of SNMP.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/mibs.xml b/lib/otp_mibs/doc/src/mibs.xml
deleted file mode 100644
index a32d5ea5f5..0000000000
--- a/lib/otp_mibs/doc/src/mibs.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>Mibs</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2003-05-19</date>
- <rev>A</rev>
- <file>mibs.xml</file>
- </header>
-
- <section>
- <title>Structure</title>
- <p>The OTP mibs are stored in the
- <c>$OTP_ROOT/lib/otp_mibs/mibs/</c> directory. They
- are defined in SNMPv2 SMI syntax. An SNMPv1 version of the mib is
- delivered in the <c>mibs/v1</c> directory. The compiled MIB is
- located under <c>priv/mibs</c>, and the generated <c>.hrl</c>
- file under the <c>include</c> directory. To compile a MIB that
- IMPORTS a MIB in the OTP_Mibs application, give the option
- <c>{il, ["otp_mibs/priv/mibs"]}</c> to the MIB compiler.</p>
- </section>
-
- <section>
- <title>OTP-MIB</title>
- <p>The OTP-MIB mib represents information about Erlang nodes such as
- node name, number of running processes, virtual machine version
- etc. If the MIB should be used in a system, it should be
- loaded into an SNMP agent by using the API function
- <c>otp_mib:load/1</c>.</p>
- </section>
-
- <section>
- <title>OTP-REG</title>
- <p>The OTP-REG mib defines the unique OTP subtree of object
- identifiers under the Ericsson subtree. Under the OTP subtree
- several object identifiers are defined. This module is typically
- included by OTP applications defining their own mibs, or ASN.1
- modules in general, that require unique object identifiers under
- the OTP subtree.</p>
- </section>
-
- <section>
- <title>OTP-TC</title>
- <p>The OTP-TC mib provides the textual convention datatype
- <c>OwnerString</c>.</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml
deleted file mode 100644
index ac0777d225..0000000000
--- a/lib/otp_mibs/doc/src/notes.xml
+++ /dev/null
@@ -1,312 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2004</year><year>2018</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs Release Notes</title>
- <prepared>otp_appnotes</prepared>
- <docno>nil</docno>
- <date>nil</date>
- <rev>nil</rev>
- <file>notes.xml</file>
- </header>
- <p>This document describes the changes made to the OTP_Mibs
- application.</p>
-
-<section><title>Otp_Mibs 1.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The otp_mibs application has been deprecated and will be
- removed in a future release.</p>
- <p>
- Own Id: OTP-15141</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.1.2</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Removed all old unused files in the documentation.
- </p>
- <p>
- Own Id: OTP-14475 Aux Id: ERL-409, PR-1493 </p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.1.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Internal changes</p>
- <p>
- Own Id: OTP-13551</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.1</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Change license text from Erlang Public License to Apache
- Public License v2</p>
- <p>
- Own Id: OTP-12845</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Make sure the clean rule for ssh, ssl, eunit and otp_mibs
- actually removes generated files.</p>
- <p>
- Own Id: OTP-12200</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Add type based integer value truncation/reset.</p>
- <p>
- This fixes errors when querying e.g. the
- erlNodeReductions, erlNodeInBytes and erlNodeOutBytes
- objects in long-running Erlang/OTP systems.</p>
- <p>
- Update types of applicable MIB objects to 64bit based
- types.</p>
- <p>
- Potential incompatibility: Type change of Counter32 to
- Counter64 in OTP-MIB.mib</p>
- <p>
- (Thanks to Tobias Schlager)</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-11203</p>
- </item>
- <item>
- <p>
- Application upgrade (appup) files are corrected for the
- following applications: </p>
- <p>
- <c>asn1, common_test, compiler, crypto, debugger,
- dialyzer, edoc, eldap, erl_docgen, et, eunit, gs, hipe,
- inets, observer, odbc, os_mon, otp_mibs, parsetools,
- percept, public_key, reltool, runtime_tools, ssh,
- syntax_tools, test_server, tools, typer, webtool, wx,
- xmerl</c></p>
- <p>
- A new test utility for testing appup files is added to
- test_server. This is now used by most applications in
- OTP.</p>
- <p>
- (Thanks to Tobias Schlager)</p>
- <p>
- Own Id: OTP-11744</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Misc build updates</p>
- <p>
- Own Id: OTP-10784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Tuple funs (a two-element tuple with a module name and a
- function) are now officially deprecated and will be
- removed in R16. Use '<c>fun M:F/A</c>' instead. To make
- you aware that your system uses tuple funs, the very
- first time a tuple fun is applied, a warning will be sent
- to the error logger.</p>
- <p>
- Own Id: OTP-9649</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.6</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The documentation is now built with open source tools
- (xsltproc and fop) that exists on most platforms. One
- visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Otp_Mibs 1.0.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The copyright notices have been updated.</p>
- <p>
- Own Id: OTP-7851</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section>
- <title>Otp_Mibs 1.0.4.1</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Minor Makefile changes.</p>
- <p>Own Id: OTP-6689</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.4</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>Replaced calls to deprecated functions in <c>snmp</c>
- with calls to the equivalent functions in <c>snmpa</c>.</p>
- <p>Own Id: OTP-6112</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.3</title>
-
- <section>
- <title>Improvements and New Features</title>
- <list type="bulleted">
- <item>
- <p>The <c>otp_mib</c> module has been cleaned up to improve the
- maintainability. It should have no effect on the
- functionality of the OTP_Mibs application.</p>
- <p>Own Id: OTP-4982</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.2</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Incorrect <c>.app</c> file (missing mandatory
- <c>registered</c>).</p>
- <p>Own Id: OTP-4823 Aux Id: Seq8145, OTP-4801 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0.1</title>
-
- <section>
- <title>Fixed Bugs and Malfunctions</title>
- <list type="bulleted">
- <item>
- <p>Missing <c>.app</c> and <c>appup</c> files in <c>ebin</c>.</p>
- <p>Own Id: OTP-4801 Aux Id: Seq8145 </p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>OTP_Mibs 1.0</title>
- <p>The OTP mibs that where included in the SASL application
- have been moved to this new application OTP_Mibs. The OTP
- mibs had no real connection to SASL and it is desirable that
- the core of Erlang/OTP is not dependent on SNMP.</p>
- <p>Own Id: OTP-4686</p>
- </section>
-</chapter>
-
-
diff --git a/lib/otp_mibs/doc/src/otp_mib.xml b/lib/otp_mibs/doc/src/otp_mib.xml
deleted file mode 100644
index 530c529c69..0000000000
--- a/lib/otp_mibs/doc/src/otp_mib.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2003</year><year>2018</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>otp_mib</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>otp_mib</module>
- <modulesummary>Handles the OTP-MIB</modulesummary>
- <description>
- <p>The SNMP application should be used to start an SNMP agent. Then
- the API functions below can be used to load/unload the OTP-MIB
- into/from the agent. The instrumentation of the OTP-MIB uses
- Mnesia, hence Mnesia must be started prior to loading the OTP-MIB.</p>
- <warning>
- <p>This application has been deprecated and will be removed in a furture release.</p>
- </warning>
- </description>
- <funcs>
- <func>
- <name>load(Agent) -> ok | {error, Reason}</name>
- <fsummary>Load the OTP-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Loads the OTP-MIB.</p>
- </desc>
- </func>
- <func>
- <name>unload(Agent) -> ok | {error, Reason}</name>
- <fsummary>Unload the OTP-MIB</fsummary>
- <type>
- <v>Agent = pid() | atom()</v>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Unloads the OTP-MIB.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>See Also</title>
- <p>snmp(3)</p>
- </section>
-</erlref>
-
-
diff --git a/lib/otp_mibs/doc/src/part.xml b/lib/otp_mibs/doc/src/part.xml
deleted file mode 100644
index 0a8ddce268..0000000000
--- a/lib/otp_mibs/doc/src/part.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs User's Guide</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2002-09-17</date>
- <rev>A</rev>
- </header>
- <description>
- <p>The <em>OTP_Mibs</em> application provides an SNMP management
- information base for Erlang nodes.</p>
- </description>
- <xi:include href="introduction.xml"/>
- <xi:include href="mibs.xml"/>
-</part>
-
-
diff --git a/lib/otp_mibs/doc/src/ref_man.xml b/lib/otp_mibs/doc/src/ref_man.xml
deleted file mode 100644
index 06c5aadcd9..0000000000
--- a/lib/otp_mibs/doc/src/ref_man.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!DOCTYPE application SYSTEM "application.dtd">
-
-<application xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2003</year><year>2016</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- </legalnotice>
-
- <title>OTP_Mibs Reference Manual</title>
- <prepared>Ingela Anderton</prepared>
- <docno></docno>
- <date>2002-09-13</date>
- <rev>A</rev>
- </header>
- <description>
- <p>The <em>OTP_Mibs</em> application provides an SNMP management
- information base for Erlang nodes.</p>
- </description>
- <xi:include href="otp_mib.xml"/>
-</application>
-
-
diff --git a/lib/otp_mibs/ebin/.gitignore b/lib/otp_mibs/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/ebin/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/include/.gitignore b/lib/otp_mibs/include/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/include/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/info b/lib/otp_mibs/info
deleted file mode 100644
index aedd1c883b..0000000000
--- a/lib/otp_mibs/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: oam Operation & Maintenance Applications
-short: SNMP management information base for Erlang/OTP nodes.
diff --git a/lib/otp_mibs/mibs/Makefile b/lib/otp_mibs/mibs/Makefile
deleted file mode 100644
index 11d790d014..0000000000
--- a/lib/otp_mibs/mibs/Makefile
+++ /dev/null
@@ -1,89 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# Release directory specification
-# ----------------------------------------------------
-include ../vsn.mk
-ifdef SASL_VSN
-VSN=$(SASL_VSN)
-RELSYSDIR = $(RELEASE_PATH)/lib/sasl-$(VSN)
-else
-VSN=$(OTP_MIBS_VSN)
-RELSYSDIR = $(RELEASE_PATH)/lib/otp_mibs-$(VSN)
-endif
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MIB_FILES= OTP-REG.mib OTP-TC.mib OTP-MIB.mib
-FUNCS_FILES = OTP-MIB.funcs
-
-BIN_TARGETS= $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin)
-HRL_TARGETS= $(MIB_FILES:%.mib=$(SNMP_HRL_TARGET_DIR)/%.hrl)
-V1_MIB_FILES= $(MIB_FILES:%.mib=v1/%.mib.v1)
-
-TARGET_FILES= $(BIN_TARGETS) $(HRL_TARGETS) $(V1_MIB_FILES)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-SNMP_FLAGS = -I ../priv/mibs
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-v1/%.mib.v1: %.mib
- $(gen_verbose)$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs"
- $(INSTALL_DIR) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DATA) $(MIB_FILES) $(FUNCS_FILES) "$(RELSYSDIR)/mibs"
- $(INSTALL_DATA) $(V1_MIB_FILES) "$(RELSYSDIR)/mibs/v1"
- $(INSTALL_DIR) "$(RELSYSDIR)/include"
- $(INSTALL_DATA) $(HRL_TARGETS) "$(RELSYSDIR)/include"
- $(INSTALL_DIR) "$(RELSYSDIR)/priv/mibs"
- $(INSTALL_DATA) $(BIN_TARGETS) "$(RELSYSDIR)/priv/mibs"
-
-release_docs_spec:
diff --git a/lib/otp_mibs/mibs/OTP-EVA-MIB.mib b/lib/otp_mibs/mibs/OTP-EVA-MIB.mib
deleted file mode 100644
index 4d0c53ed95..0000000000
--- a/lib/otp_mibs/mibs/OTP-EVA-MIB.mib
+++ /dev/null
@@ -1,569 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 2004-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-EVA-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
- Counter32, Gauge32, Integer32
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString, DateAndTime
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- OwnerString
- FROM OTP-TC
- ;
-
-otpEvaModule MODULE-IDENTITY
- LAST-UPDATED "200305090900Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
- DESCRIPTION
- "This MIB is part of the OTP MIB. It defines MIB objects
- for the eva application in OTP."
-
- REVISION "200305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "199801270900Z"
- DESCRIPTION
- "Changed erroneous defintion of alarmCleared notification.
- Changed erroneous name of this module to otpEvaModule."
- REVISION "199712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
- REVISION "199705020900Z"
- DESCRIPTION
- "The initial version of this MIB module. It is very much
- inspired by the ANS-ALM-MIB and Axd301Eva-OMS mibs."
- ::= { otpModules 6 }
-
-otpEvaMIB OBJECT IDENTIFIER ::= { otpApplications 4 }
-otpEvaMIBConformance
- OBJECT IDENTIFIER ::= { otpEvaMIB 1 }
-otpEvaMIBObjects
- OBJECT IDENTIFIER ::= { otpEvaMIB 2 }
-otpEvaMIBEvents OBJECT IDENTIFIER ::= { otpEvaMIB 3 }
-otpEvaMIBEventsV2
- OBJECT IDENTIFIER ::= { otpEvaMIBEvents 0 }
-
-
--- Datatypes
-
-AlarmSeverity ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The AlarmSeverity defines six severity levels,
- which provide an indication of how it is perceived that the
- capability of the managed object has been affected. Those
- severity levels which represent service affecting conditions
- ordered from most severe to least severe are critical,
- major, minor and warning. The levels used are as defined
- in X.733, ITU Alarm Reporting Function:
-
- o The Indeterminate severity level indicates that the
- severity level cannot be determined.
-
- o The Critical severity level indicates that a service
- affecting condition has occurred and an immediate
- corrective action is required. Such a severity can be
- reported, for example, when a managed object becomes
- totally out of service and its capability must be restored.
-
- o The Major severity level indicates that a service
- affecting condition has developed and an urgent corrective
- action is required. Such a severity can be reported, for
- example, when there is a severe degradation in the
- capability of the managed object and its full capability
- must be restored.
-
- o The Minor severity level indicates the existence of a
- non-service affecting fault condition and that corrective
- action should be taken in order to prevent a more serious
- (for example, service affecting) fault. Such a severity
- can be reported, for example, when the detected alarm
- condition is not currently degrading the capacity of the
- managed object.
-
- o The Warning severity level indicates the detection of a
- potential or impending service affecting fault, before any
- significant effects have been felt. Action should be taken
- to further diagnose (if necessary) and correct the problem
- in order to prevent it from becoming a more serious service
- affecting fault.
-
- When an alarm is cleared, an alarmCleared event is generated.
- This event clears the alarm with the currentAlarmFaultId
- contained in the event. It is not required that the clearing
- of previously reported alarms are reported. Therefore, a managing
- system cannot assume that the absence of an alarmedCleared event
- for a fault means that the condition that caused the generation
- of previous alarms is still present. Managed object definers
- shall state if, and under which conditions, the alarmedCleared
- event is used.
-
- The clear value of AlarmSeverity is an action which is used when
- a management station wants to clear an active alarm. This is not
- possible on all systems, and thus an agent does not have support
- write access for this value."
- REFERENCE
- "X.733, ITU Alarm Reporting Function"
- SYNTAX INTEGER {
- indeterminate (0),
- critical (1),
- major (2),
- minor (3),
- warning (4),
- clear (5) -- Written, not read
- }
-
-AlarmClass ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The AlarmClass type categorizes the alarm, and is
- defined when the alarm is registered. It is as defined in
- X.733, ITU Alarm Reporting Function:
-
- o communications. An alarm of this class is principally
- associated with the procedures or processes required
- to convey information from one point to another.
-
- o qos. An alarm of this class is principally associated
- with a degradation in the quality of service.
-
- o processing. An alarm of this class is principally
- associated with a software or processing fault.
-
- o equipment. An alarm of this class is principally
- associated with an equipment fault.
-
- o environmental. An alarm of this class is principally
- associated with a condition relating to an enclosure in
- with equipment resides."
- REFERENCE
- "X.733, ITU Alarm Reporting Function"
- SYNTAX INTEGER {
- unknown (0),
- communications (1),
- qos (2),
- processing (3),
- equipment (4),
- environmental (5)
- }
-
-
--- Managed Objects
-
-event OBJECT IDENTIFIER ::= { otpEvaMIBObjects 1 }
-alarm OBJECT IDENTIFIER ::= { otpEvaMIBObjects 2 }
-currentAlarm OBJECT IDENTIFIER ::= { otpEvaMIBObjects 3 }
-
--- The Event group
---
--- The Event group controls the generation of notifications of
--- events from the system.
-
-eventTable OBJECT-TYPE
- SYNTAX SEQUENCE OF EventEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A list of events defined by the system. This table is used
- to control the sending of traps and to whom the traps are
- sent."
- ::= { event 1 }
-
-eventEntry OBJECT-TYPE
- SYNTAX EventEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters that describe an event to be
- generated when certain conditions are met."
- INDEX { eventIndex }
- ::= { eventTable 1 }
-
-EventEntry ::= SEQUENCE {
- eventIndex Integer32 (1..2147483647),
- eventTrapName DisplayString,
- eventTreatment INTEGER,
- eventCommunity OCTET STRING (SIZE (0..127)),
- eventSentTraps Counter32,
- eventOwner OwnerString
- }
-
-eventIndex OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An index that uniquely identifies an entry in the
- event table. Each such entry defines one event that
- is to be generated when the appropriate conditions
- occur. The value for each eventIndex must remain
- constant, at least from one re-initialization of the
- entity's network management system to the next
- re-initialization."
- ::= { eventEntry 1 }
-
-eventTrapName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The identifier of the corresponding trap.
- NOTE: this should be an OID in SNMPv2, but must be
- a string in v1."
- ::= { eventEntry 2 }
-
-eventTreatment OBJECT-TYPE
- SYNTAX INTEGER {
- none(1),
- log(2),
- snmpTrap(3),
- logAndTrap(4)
- }
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "Defines how the system shall treat this event. In the
- case of snmpTrap, an SNMP trap is sent to one or more
- management stations. In the case of log, the event is
- guaranteed to be logged in a log according to some log
- strategy. Each such log strategy may define a MIB module
- for control and examination of logs."
- ::= { eventEntry 3 }
-
-eventCommunity OBJECT-TYPE
- SYNTAX OCTET STRING (SIZE (0..127))
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "If an SNMP trap is to be sent, it will be sent to
- the SNMP community specified by this octet string."
- ::= { eventEntry 4 }
-
-eventSentTraps OBJECT-TYPE
- SYNTAX Counter32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The number of times this event has been sent as a trap."
- ::= { eventEntry 5 }
-
-eventOwner OBJECT-TYPE
- SYNTAX OwnerString
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The manager entity that 'owns' this event entry, and is
- therefore responsible for its contents."
- ::= { eventEntry 6 }
-
-eventTime OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS accessible-for-notify
- STATUS current
- DESCRIPTION
- "This object may be included in a trap definition for an event.
- It specifies the time the event was generated."
- ::= { event 2 }
-
-
--- The Alarm group
---
--- The Alarm group extends the Event group with objects for alarms.
-
-alarmTable OBJECT-TYPE
- SYNTAX SEQUENCE OF AlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "Contains additional information for alarm events."
- ::= { alarm 1 }
-
-alarmEntry OBJECT-TYPE
- SYNTAX AlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters for alarms."
- INDEX { eventIndex }
- ::= { alarmTable 1 }
-
-AlarmEntry ::= SEQUENCE {
- alarmClass AlarmClass,
- alarmSeverity AlarmSeverity
- }
-
-alarmClass OBJECT-TYPE
- SYNTAX AlarmClass
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The class of this alarm."
- ::= { alarmEntry 1 }
-
-alarmSeverity OBJECT-TYPE
- SYNTAX AlarmSeverity
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The perceived severity that shall apply to the
- associated alarms."
- ::= { alarmEntry 2 }
-
-
--- The CurrentAlarm group
---
--- The CurrentAlarm group is a collection of objects for monitoring of
--- active alarms in the system.
-
-numberOfCurrentAlarms OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of currently active alarms in the system."
- ::= { currentAlarm 1 }
-
-currentAlarmLastTimeChanged OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The time an entry in the currentAlarmTable was changed.
- It may be used by a management station as a value to
- poll. If the value is changed, the management station
- knows that the currentAlarmTable has been updated."
- ::= { currentAlarm 2 }
-
-currentAlarmTable OBJECT-TYPE
- SYNTAX SEQUENCE OF CurrentAlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A list of currently active alarms in the system."
- ::= { currentAlarm 3 }
-
-currentAlarmEntry OBJECT-TYPE
- SYNTAX CurrentAlarmEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A set of parameters that describe a currently active
- alarm."
- INDEX { currentAlarmFaultId }
- ::= { currentAlarmTable 1 }
-
-CurrentAlarmEntry ::= SEQUENCE {
- currentAlarmFaultId Integer32 (1..2147483647),
- currentAlarmEventIndex Integer32 (1..2147483647),
- currentAlarmObject OBJECT IDENTIFIER,
- currentAlarmCause OBJECT IDENTIFIER,
- currentAlarmSeverity AlarmSeverity,
- currentAlarmTime DateAndTime,
- currentAlarmInformation DisplayString,
- currentAlarmExtra1 OBJECT IDENTIFIER,
- currentAlarmExtra2 OBJECT IDENTIFIER
- }
-
-currentAlarmFaultId OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An id that uniquely identifies a fault. Each fault is
- represented as one an entry in the currentAlarmTable."
- ::= { currentAlarmEntry 1 }
-
-currentAlarmEventIndex OBJECT-TYPE
- SYNTAX Integer32 (1..2147483647)
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A pointer into the eventTable. Points to the event
- corresponding to this alarm."
- ::= { currentAlarmEntry 2 }
-
-currentAlarmObject OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The alarming object."
- ::= { currentAlarmEntry 3 }
-
-currentAlarmCause OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The probable cause of the alarm."
- ::= { currentAlarmEntry 4 }
-
-currentAlarmSeverity OBJECT-TYPE
- SYNTAX AlarmSeverity
- MAX-ACCESS read-write
- STATUS current
- DESCRIPTION
- "The perceived severity of the fault. A manager can set
- this value to clear only. When set to clear, the alarm
- is removed from this table, and a 'clearAlarm' event is
- generated."
- ::= { currentAlarmEntry 5 }
-
-currentAlarmTime OBJECT-TYPE
- SYNTAX DateAndTime
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The time the fault was detected."
- ::= { currentAlarmEntry 6 }
-
-currentAlarmInformation OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Additional information pin-pointing the problem."
- ::= { currentAlarmEntry 7 }
-
-currentAlarmExtra1 OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "An extra parameter used for some alarms at their own
- discretion. Can be used for example to identify
- additional objects in the alarm, or instead of
- currentAlarmInformation to pin-point the problem, if the
- additional information is defined in some MIB."
- ::= { currentAlarmEntry 8 }
-
-currentAlarmExtra2 OBJECT-TYPE
- SYNTAX OBJECT IDENTIFIER
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "An extra parameter used for some alarms at their own
- discretion. Can be used for example to identify
- additional objects in the alarm, or instead of
- currentAlarmInformation to pin-point the problem, if the
- additional information is defined in some MIB."
- ::= { currentAlarmEntry 9 }
-
-
--- Events
-
-alarmCleared NOTIFICATION-TYPE
- OBJECTS {
- currentAlarmEventIndex,
- eventTime
- }
- STATUS current
- DESCRIPTION
- "This event is sent when an alarm has been cleared,
- either by the application or by an operator. Note that the
- currentAlarmFaultId is implicitly sent as the instance identifier
- for currentAlarmEventIndex."
- ::= { otpEvaMIBEventsV2 1 }
-
-
--- conformance information
-
-otpEvaMIBCompliances
- OBJECT IDENTIFIER ::= { otpEvaMIBConformance 1 }
-otpEvaMIBGroups
- OBJECT IDENTIFIER ::= { otpEvaMIBConformance 2 }
-
-
--- compliance statements
-
-otpEvaBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-EVA-MIB."
- MODULE -- this module
- MANDATORY-GROUPS { eventGroup,
- alarmGroup,
- currentAlarmGroup,
- evaEventsGroup }
-
- ::= { otpEvaMIBCompliances 1 }
-
-
--- units of conformance
-
-eventGroup OBJECT-GROUP
- OBJECTS { eventTrapName,
- eventTreatment,
- eventCommunity,
- eventSentTraps,
- eventOwner,
- eventTime }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- and control of the events defined in the OTP system."
- ::= { otpEvaMIBGroups 1 }
-
-alarmGroup OBJECT-GROUP
- OBJECTS { alarmClass,
- alarmSeverity }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- and control of the alarms defined the OTP system."
- ::= { otpEvaMIBGroups 2 }
-
-currentAlarmGroup OBJECT-GROUP
- OBJECTS { numberOfCurrentAlarms,
- currentAlarmLastTimeChanged,
- currentAlarmEventIndex,
- currentAlarmObject,
- currentAlarmCause,
- currentAlarmSeverity,
- currentAlarmTime,
- currentAlarmInformation,
- currentAlarmExtra1,
- currentAlarmExtra2 }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the activa alarm list in the OTP system."
- ::= { otpEvaMIBGroups 3 }
-
-evaEventsGroup NOTIFICATION-GROUP
- NOTIFICATIONS { alarmCleared }
- STATUS current
- DESCRIPTION
- "The notification which is generated from EVA."
- ::= { otpEvaMIBGroups 4 }
-
-
-END
diff --git a/lib/otp_mibs/mibs/OTP-MIB.funcs b/lib/otp_mibs/mibs/OTP-MIB.funcs
deleted file mode 100644
index 9f9d69c3d1..0000000000
--- a/lib/otp_mibs/mibs/OTP-MIB.funcs
+++ /dev/null
@@ -1,2 +0,0 @@
-{erlNodeTable, {otp_mib, erl_node_table, []}}.
-{applTable, {otp_mib, appl_table, []}}.
diff --git a/lib/otp_mibs/mibs/OTP-MIB.mib b/lib/otp_mibs/mibs/OTP-MIB.mib
deleted file mode 100644
index 693319eae4..0000000000
--- a/lib/otp_mibs/mibs/OTP-MIB.mib
+++ /dev/null
@@ -1,318 +0,0 @@
---
--- %CopyrightBegin%
---
--- Copyright Ericsson AB 1996-2016. All Rights Reserved.
---
--- Licensed under the Apache License, Version 2.0 (the "License");
--- you may not use this file except in compliance with the License.
--- You may obtain a copy of the License at
---
--- http://www.apache.org/licenses/LICENSE-2.0
---
--- Unless required by applicable law or agreed to in writing, software
--- distributed under the License is distributed on an "AS IS" BASIS,
--- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--- See the License for the specific language governing permissions and
--- limitations under the License.
---
--- %CopyrightEnd%
---
-
-OTP-MIB DEFINITIONS ::= BEGIN
-
-IMPORTS
- MODULE-IDENTITY, OBJECT-TYPE,
- Counter64, Gauge32, Integer32
- FROM SNMPv2-SMI
- TEXTUAL-CONVENTION, DisplayString
- FROM SNMPv2-TC
- MODULE-COMPLIANCE, OBJECT-GROUP
- FROM SNMPv2-CONF
- otpModules, otpApplications
- FROM OTP-REG
- ;
-
-otpModule MODULE-IDENTITY
- LAST-UPDATED "201307160700Z"
- ORGANIZATION "Ericsson"
- CONTACT-INFO
- "Contact: Erlang Support see license agreement for Erlang/OTP."
- DESCRIPTION
- "This is a MIB for a distributed OTP system, with one SNMP
- agent executing at one node only. Each Erlang node in the
- OTP system is represented by one row in the erlNodeTable."
-
- REVISION "201307160700Z"
- DESCRIPTION
- "Updated various types to be able to reflect larger values.
- The objects erlNodeReductions, erlNodeInBytes, erlNodeOutBytes as well
- as the type MilliSeconds have been updated to Counter64."
-
- REVISION "200305090900Z"
- DESCRIPTION
- "Changed CONTACT-INFO as it was outdated, made it more generic
- to avoid such changes in the future."
-
- REVISION "199712010900Z"
- DESCRIPTION
- "Converted to v2 SMI and placed in the OTP tree."
-
- REVISION "199608191700Z"
- DESCRIPTION
- "The initial revision of MIB module OTP-MIB."
-
- ::= { otpModules 3 }
-
-otpMIB OBJECT IDENTIFIER ::= { otpApplications 1 }
-otpMIBConformance
- OBJECT IDENTIFIER ::= { otpMIB 1 }
-otpMIBObjects OBJECT IDENTIFIER ::= { otpMIB 2 }
-
--- Datatypes
-
-MilliSeconds ::= TEXTUAL-CONVENTION
- STATUS current
- DESCRIPTION
- "The MilliSeconds type represents a Counter which represents
- the time, in milliseconds between two epochs. When objects
- are defined which use this type, the description of the object
- identifies both of the reference epochs."
- SYNTAX Counter64
-
-
--- Managed Objects
-
-erlang OBJECT IDENTIFIER ::= { otpMIBObjects 1 }
-appls OBJECT IDENTIFIER ::= { otpMIBObjects 2 }
-
-erlNodeTable OBJECT-TYPE
- SYNTAX SEQUENCE OF ErlNodeEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with info on each erlang node in the system."
- ::= { erlang 1 }
-
-erlNodeEntry OBJECT-TYPE
- SYNTAX ErlNodeEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the erlNodeTable."
- INDEX { erlNodeId }
- ::= { erlNodeTable 1 }
-
-ErlNodeEntry ::= SEQUENCE {
- erlNodeId Integer32,
- erlNodeName DisplayString,
- erlNodeMachine DisplayString,
- erlNodeVersion DisplayString,
- erlNodeRunQueue Gauge32,
- erlNodeRunTime MilliSeconds,
- erlNodeWallClock MilliSeconds,
- erlNodeReductions Counter64,
- erlNodeProcesses Gauge32,
- erlNodeInBytes Counter64,
- erlNodeOutBytes Counter64
-}
-
-erlNodeId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the erlang node."
- ::= { erlNodeEntry 1 }
-
-erlNodeName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The symbolic name of the erlang node."
- ::= { erlNodeEntry 2 }
-
-erlNodeMachine OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The virtual machine executing the erlang node"
- ::= { erlNodeEntry 3 }
-
-erlNodeVersion OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The version number of the virtual machine"
- ::= { erlNodeEntry 4 }
-
-erlNodeRunQueue OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of processes scheduled to run"
- ::= { erlNodeEntry 5 }
-
-erlNodeRunTime OBJECT-TYPE
- SYNTAX MilliSeconds
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total cpu time in milliseconds since the
- system started"
- ::= { erlNodeEntry 6 }
-
-erlNodeWallClock OBJECT-TYPE
- SYNTAX MilliSeconds
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Total real time in milliseconds since the
- system started"
- ::= { erlNodeEntry 7 }
-
-erlNodeReductions OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of function calls since the system started"
- ::= { erlNodeEntry 8 }
-
-erlNodeProcesses OBJECT-TYPE
- SYNTAX Gauge32
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "Number of running processes in the system."
- ::= { erlNodeEntry 9 }
-
-erlNodeInBytes OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The total number of bytes delivered to the system"
- ::= { erlNodeEntry 10 }
-
-erlNodeOutBytes OBJECT-TYPE
- SYNTAX Counter64
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The total number of bytes delivered from the system"
- ::= { erlNodeEntry 11 }
-
-
-applTable OBJECT-TYPE
- SYNTAX SEQUENCE OF ApplEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A table with all currently running applications
- for each node."
- ::= { appls 1 }
-
-applEntry OBJECT-TYPE
- SYNTAX ApplEntry
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "A conceptual row in the applTable."
- INDEX { erlNodeId, applId }
- ::= { applTable 1 }
-
-ApplEntry ::= SEQUENCE {
- applId Integer32,
- applName DisplayString,
- applDescr DisplayString,
- applVsn DisplayString
-}
-
-applId OBJECT-TYPE
- SYNTAX Integer32
- MAX-ACCESS not-accessible
- STATUS current
- DESCRIPTION
- "An integer that uniquely identifies the application."
- ::= { applEntry 1 }
-
-applName OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The name of the application."
- ::= { applEntry 2 }
-
-applDescr OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "A short description of the application."
- ::= { applEntry 3 }
-
-applVsn OBJECT-TYPE
- SYNTAX DisplayString
- MAX-ACCESS read-only
- STATUS current
- DESCRIPTION
- "The version of the application."
- ::= { applEntry 4 }
-
-
--- conformance information
-
-otpMIBCompliances
- OBJECT IDENTIFIER ::= { otpMIBConformance 1 }
-otpMIBGroups OBJECT IDENTIFIER ::= { otpMIBConformance 2 }
-
-
--- compliance statements
-
-otpBasicCompliance MODULE-COMPLIANCE
- STATUS current
- DESCRIPTION
- "The compliance statement for SNMPv2 entities which
- implement the OTP-MIB."
- MODULE -- this module
- MANDATORY-GROUPS { erlGroup, applGroup }
-
- ::= { otpMIBCompliances 1 }
-
-
--- units of conformance
-
-erlGroup OBJECT-GROUP
- OBJECTS { erlNodeName,
- erlNodeMachine,
- erlNodeVersion,
- erlNodeRunQueue,
- erlNodeRunTime,
- erlNodeWallClock,
- erlNodeReductions,
- erlNodeProcesses,
- erlNodeInBytes,
- erlNodeOutBytes }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the Erlang runtime system."
- ::= { otpMIBGroups 1 }
-
-applGroup OBJECT-GROUP
- OBJECTS { applName,
- applDescr,
- applVsn }
- STATUS current
- DESCRIPTION
- "A collection of objects providing basic instrumentation
- of the applications in the OTP system."
- ::= { otpMIBGroups 2 }
-
-
-END
diff --git a/lib/otp_mibs/mibs/v1/.gitignore b/lib/otp_mibs/mibs/v1/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/mibs/v1/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/bin/.gitignore b/lib/otp_mibs/priv/bin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/bin/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/mibs/.gitignore b/lib/otp_mibs/priv/mibs/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/mibs/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/priv/obj/.gitignore b/lib/otp_mibs/priv/obj/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/otp_mibs/priv/obj/.gitignore
+++ /dev/null
diff --git a/lib/otp_mibs/src/Makefile b/lib/otp_mibs/src/Makefile
deleted file mode 100644
index 5c7af39c3f..0000000000
--- a/lib/otp_mibs/src/Makefile
+++ /dev/null
@@ -1,106 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2003-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug -W
-endif
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(OTP_MIBS_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/otp_mibs-$(VSN)
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-MODULES = \
- otp_mib
-
-INCLUDE=../include
-
-HRL_FILES =
-
-INTERNAL_HRL_FILES =
-
-ERL_FILES = $(MODULES:%=%.erl)
-
-APP_FILE = otp_mibs.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-APPUP_FILE = otp_mibs.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-TARGETS = $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_COMPILE_FLAGS += -I$(INCLUDE)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGETS)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f $(APP_TARGET)
- rm -f $(APPUP_TARGET)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- $(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) "$(RELSYSDIR)/src"
- $(INSTALL_DATA) $(ERL_FILES) "$(RELSYSDIR)/src"
- $(INSTALL_DIR) "$(RELSYSDIR)/ebin"
- $(INSTALL_DATA) $(TARGETS) "$(RELSYSDIR)/ebin"
-
-release_docs_spec:
-
-
diff --git a/lib/otp_mibs/src/otp_mib.erl b/lib/otp_mibs/src/otp_mib.erl
deleted file mode 100644
index ca868f2817..0000000000
--- a/lib/otp_mibs/src/otp_mib.erl
+++ /dev/null
@@ -1,219 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(otp_mib).
-%%%-----------------------------------------------------------------
-%%% Description: This module implements the OTP-MIB.
-%%% The tables are implemented as shadow tables with the module
-%%% snmp_shadow_table.
-%%%-----------------------------------------------------------------
-
-%% API
--export([load/1, unload/1]).
-
-%% SNMP instrumentation
--export([erl_node_table/1, erl_node_table/3, appl_table/1, appl_table/3]).
-
-%% SNMP shadow functions
--export([update_erl_node_table/0, update_appl_table/0]).
-
-%% Exported for internal use via rpc
--export([get_erl_node/1, get_appls/1]).
-
--deprecated([{load,1,eventually},
- {unload,1,eventually}]).
-
-%% Shadow tables
--record(erlNodeTable,
- {erlNodeId, erlNodeName, erlNodeMachine, erlNodeVersion,
- erlNodeRunQueue,
- erlNodeRunTime, erlNodeWallClock, erlNodeReductions,
- erlNodeProcesses, erlNodeInBytes, erlNodeOutBytes}).
-
--record(applTable, {key = '_', applName = '_', applDescr = '_',
- applVsn = '_'}).
-
-%% Shadow argument macros
--define(erlNodeShadowArgs,
- {erlNodeTable, integer, record_info(fields, erlNodeTable), 5000,
- fun otp_mib:update_erl_node_table/0}).
-
--define(applShadowArgs,
- {applTable, {integer, integer}, record_info(fields, applTable),
- 5000, fun otp_mib:update_appl_table/0}).
-
-%% Misc
--record(erlNodeAlloc, {nodeName, nodeId}).
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-%%-------------------------------------------------------------------------
-%% load(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-MIB
-%%-------------------------------------------------------------------------
-load(Agent) ->
- MibDir = code:priv_dir(otp_mibs) ++ "/mibs",
- snmpa:load_mibs(Agent, [MibDir ++ "/OTP-MIB"]).
-
-%%-------------------------------------------------------------------------
-%% unload(Agent) -> ok | {error, Reason}
-%% Agent - pid() | atom()
-%% Reason - term()
-%% Description: Loads the OTP-MIB
-%%-------------------------------------------------------------------------
-unload(Agent) ->
- snmpa:unload_mibs(Agent, ["OTP-MIB"]).
-
-
-%%%=========================================================================
-%%% SNMP instrumentation
-%%%=========================================================================
-erl_node_table(new) ->
- Tab = erlNodeAlloc,
- Storage = ram_copies,
- case lists:member(Tab, mnesia:system_info(tables)) of
- true ->
- case mnesia:table_info(Tab, storage_type) of
- unknown ->
- {atomic, ok} = mnesia:add_table_copy(Tab, node(), Storage);
- Storage ->
- catch delete_all(Tab)
- end;
- false ->
- Nodes = [node()],
- Props = [{type, set},
- {attributes, record_info(fields, erlNodeAlloc)},
- {local_content, true},
- {Storage, Nodes}],
- {atomic, ok} = mnesia:create_table(Tab, Props)
- end,
- ok = mnesia:dirty_write({erlNodeAlloc, next_index, 1}),
- update_node_alloc([node() | nodes()]),
- snmp_shadow_table:table_func(new, ?erlNodeShadowArgs).
-
-erl_node_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?erlNodeShadowArgs).
-
-
-appl_table(Op) ->
- snmp_shadow_table:table_func(Op, ?applShadowArgs).
-appl_table(Op, RowIndex, Cols) ->
- snmp_shadow_table:table_func(Op, RowIndex, Cols, ?applShadowArgs).
-
-
-%%%=========================================================================
-%%% SNMP shadow functions
-%%%=========================================================================
-update_erl_node_table() ->
- delete_all(erlNodeTable),
- Nodes = [node() | nodes()],
- update_node_alloc(Nodes),
- lists:foreach(
- fun(Node) ->
- [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
- ErlNode = rpc:call(Node, otp_mib, get_erl_node, [Idx]),
- ok = mnesia:dirty_write(ErlNode)
- end, Nodes).
-
-update_appl_table() ->
- delete_all(applTable),
- Nodes = [node() | nodes()],
- update_node_alloc(Nodes),
- lists:foreach(
- fun(Node) ->
- [{_,_,Idx}] = mnesia:dirty_read({erlNodeAlloc, Node}),
- Appls = rpc:call(Node, otp_mib, get_appls, [Idx]),
- lists:foreach(fun(Appl) ->
- ok = mnesia:dirty_write(Appl)
- end, Appls)
- end, Nodes).
-
-%%%========================================================================
-%%% Exported for internal use via rpc
-%%%========================================================================
-get_erl_node(Id) ->
- RunQueue = erlang:statistics(run_queue),
- RunTime = element(1, erlang:statistics(runtime)),
- WallClock = element(1, erlang:statistics(wall_clock)),
- Reductions = element(1, erlang:statistics(reductions)),
- Processes = length(processes()),
- IO = erlang:statistics(io),
- InBytes = element(2, element(1, IO)),
- OutBytes = element(2, element(2, IO)),
- #erlNodeTable{erlNodeId = truncate_int('Integer32', Id),
- erlNodeName = atom_to_list(node()),
- erlNodeVersion = erlang:system_info(version),
- erlNodeMachine = erlang:system_info(machine),
- erlNodeRunQueue = truncate_int('Unsigned32', RunQueue),
- erlNodeRunTime = truncate_int('Counter64', RunTime),
- erlNodeWallClock = truncate_int('Counter64', WallClock),
- erlNodeReductions = truncate_int('Counter64', Reductions),
- erlNodeProcesses = truncate_int('Unsigned32', Processes),
- erlNodeInBytes = truncate_int('Counter64', InBytes),
- erlNodeOutBytes = truncate_int('Counter64', OutBytes)}.
-
-get_appls(NodeId) ->
- element(1,
- lists:mapfoldl(
- fun({ApplName, ApplDescr, ApplVsn}, ApplId) ->
- {#applTable{key = {NodeId, ApplId},
- applName = atom_to_list(ApplName),
- applDescr = ApplDescr,
- applVsn = ApplVsn},
- ApplId + 1}
- end, 1, application:which_applications())).
-
-%%%========================================================================
-%%% Internal functions
-%%%========================================================================
-update_node_alloc([Node | T]) ->
- case mnesia:dirty_read({erlNodeAlloc, Node}) of
- [] ->
- [{_, _, Idx}] = mnesia:dirty_read({erlNodeAlloc, next_index}),
- ok = mnesia:dirty_write(#erlNodeAlloc{nodeName = Node,
- nodeId = Idx}),
- ok = mnesia:dirty_write({erlNodeAlloc, next_index, Idx + 1});
- _ ->
- ok
- end,
- update_node_alloc(T);
-update_node_alloc([]) -> ok.
-
-delete_all(Name) -> delete_all(mnesia:dirty_first(Name), Name).
-delete_all('$end_of_table', _Name) -> done;
-delete_all(Key, Name) ->
- Next = mnesia:dirty_next(Name, Key),
- ok = mnesia:dirty_delete({Name, Key}),
- delete_all(Next, Name).
-
-%% This will return a value limited to fit into the specified type.
-%% While counter types will be resetted, other integer types will
-%% only be restricted to the valid range.
-truncate_int('Counter64', Value) when Value < 0 -> 0;
-truncate_int('Counter64', Value) -> Value rem 18446744073709551615;
-truncate_int('Unsigned32', Value) when Value < 0 -> 0;
-truncate_int('Unsigned32', Value) when Value > 4294967295 -> 4294967295;
-truncate_int('Unsigned32', Value) -> Value;
-truncate_int('Integer32', Value) when Value < -2147483648 -> -2147483648;
-truncate_int('Integer32', Value) when Value > 2147483647 -> 2147483647;
-truncate_int('Integer32', Value) -> Value.
diff --git a/lib/otp_mibs/src/otp_mibs.app.src b/lib/otp_mibs/src/otp_mibs.app.src
deleted file mode 100644
index 75ef25c366..0000000000
--- a/lib/otp_mibs/src/otp_mibs.app.src
+++ /dev/null
@@ -1,30 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-{application, otp_mibs,
- [{description, "SNMP managment information base for Erlang/OTP nodes."},
- {vsn, "%VSN%"},
- {modules, [otp_mib]},
- {registered, []},
- {applications, [kernel, stdlib, snmp]},
- {env,[]},
- {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","mnesia-4.12",
- "kernel-3.0","erts-6.0"]}]}.
-
diff --git a/lib/otp_mibs/test/Makefile b/lib/otp_mibs/test/Makefile
deleted file mode 100644
index 9736cf8bce..0000000000
--- a/lib/otp_mibs/test/Makefile
+++ /dev/null
@@ -1,85 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# %CopyrightEnd%
-#
-include $(ERL_TOP)/make/target.mk
-
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-MODULES= otp_mibs_SUITE
-
-EBIN = .
-
-HRL_FILES=
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-SOURCE = $(ERL_FILES) $(HRL_FILES)
-
-EMAKEFILE=Emakefile
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/otp_mibs_test
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += \
- -I$(ERL_TOP)/lib/snmp/include
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\
- > $(EMAKEFILE)
-
-tests debug opt: make_emakefile
- erl $(ERL_MAKE_FLAGS) -make
-
-clean:
- rm -f $(EMAKEFILE)
- rm -f $(TARGET_FILES)
- rm -f core *~
-
-docs:
-
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
-
-release_tests_spec: make_emakefile
- $(INSTALL_DIR) "$(RELSYSDIR)"
- $(INSTALL_DATA) $(EMAKEFILE) $(SOURCE) "$(RELSYSDIR)"
- $(INSTALL_DATA) otp_mibs_SUITE.cfg "$(RELSYSDIR)"
-
-release_docs_spec:
diff --git a/lib/otp_mibs/test/otp_mibs_SUITE.cfg b/lib/otp_mibs/test/otp_mibs_SUITE.cfg
deleted file mode 100644
index d01cf92104..0000000000
--- a/lib/otp_mibs/test/otp_mibs_SUITE.cfg
+++ /dev/null
@@ -1,15 +0,0 @@
-%% -*- erlang -*-
-{snmp,
- [
- {start_agent,true},
- {users,
- [
- {otp_mibs_test,[snmpm_user_default,[]]}
- ]},
- {managed_agents,
- [
- {otp_mibs_test, [otp_mibs_test, {127,0,0,1}, 4000, []]}
- ]},
- {agent_sysname,"Test otp_mibs"},
- {mgr_port,5001}
- ]}.
diff --git a/lib/otp_mibs/test/otp_mibs_SUITE.erl b/lib/otp_mibs/test/otp_mibs_SUITE.erl
deleted file mode 100644
index cb3cd28200..0000000000
--- a/lib/otp_mibs/test/otp_mibs_SUITE.erl
+++ /dev/null
@@ -1,255 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(otp_mibs_SUITE).
-
-%%-----------------------------------------------------------------
-%% This suite can no longer be executed standalone, i.e. it must be
-%% executed with common test. The reason is that ct_snmp is used
-%% instead of the snmp application directly. The suite requires a
-%% config file, otp_mibs_SUITE.cfg, found in the same directory as
-%% the suite.
-%%
-%% Execute with:
-%% > ct_run -suite otp_mibs_SUITE -config otp_mibs_SUITE.cfg
-%%-----------------------------------------------------------------
-
--include_lib("common_test/include/ct.hrl").
--include_lib("otp_mibs/include/OTP-MIB.hrl").
--include_lib("snmp/include/snmp_types.hrl").
-
-% Test server specific exports
--export([all/0,
- suite/0,
- groups/0,
- init_per_group/2,
- end_per_group/2,
- init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2]).
-
-% Test cases must be exported.
--export([app/1, appup/1, nt_basic_types/1, nt_high_reduction_count/1]).
-
--define(TRAP_UDP, 5000).
--define(AGENT_UDP, 4000).
--define(CONF_FILE_VER, [v2]).
--define(SYS_NAME, "Test otp_mibs").
--define(MAX_MSG_SIZE, 484).
--define(ENGINE_ID, "mgrEngine").
--define(MGR_PORT, 5001).
-
-%% Since some cases are only interested in single entries of the OTP-MIB's
-%% node table, one row must be chosen. The first row should be sufficient
-%% for this.
--define(NODE_ENTRY, 1).
-
-%%---------------------------------------------------------------------
-%% CT setup
-%%---------------------------------------------------------------------
-
-init_per_testcase(_Case, Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:minutes(6)),
- [{watchdog, Dog}|Config].
-
-end_per_testcase(_Case, Config) when is_list(Config) ->
- Dog = ?config(watchdog, Config),
- test_server:timetrap_cancel(Dog),
- Config.
-
-suite() -> [{ct_hooks,[ts_install_cth]}, {require, snmp_mgr_agent, snmp}].
-
-all() -> [{group, app}, {group, node_table}].
-
-groups() -> [{app, [], [app, appup]},
- {node_table, [], [nt_basic_types, nt_high_reduction_count]}].
-
-init_per_group(_GroupName, Config) -> Config.
-
-end_per_group(_GroupName, Config) -> Config.
-
-init_per_suite(Config) ->
- ?line application:start(sasl),
- ?line application:start(mnesia),
- ?line application:start(otp_mibs),
-
- ok = ct_snmp:start(Config,snmp_mgr_agent),
-
- %% Load the mibs that should be tested
- otp_mib:load(snmp_master_agent),
-
- Config.
-
-end_per_suite(Config) ->
- PrivDir = ?config(priv_dir, Config),
- ConfDir = filename:join(PrivDir,"conf"),
- DbDir = filename:join(PrivDir,"db"),
- MgrDir = filename:join(PrivDir, "mgr"),
-
- %% Uload mibs
- otp_mib:unload(snmp_master_agent),
-
- %% Clean up
- application:stop(snmp),
- application:stop(mnesia),
- application:stop(otp_mibs),
-
- del_dir(ConfDir),
- del_dir(DbDir),
- (catch del_dir(MgrDir)),
- ok.
-
-%%---------------------------------------------------------------------
-%% Test cases
-%%---------------------------------------------------------------------
-
-%% Test that the otp_mibs app file is ok
-app(Config) when is_list(Config) ->
- ok = ?t:app_test(otp_mibs).
-
-%% Test that the otp_mibs appup file is ok
-appup(Config) when is_list(Config) ->
- ok = ?t:appup_test(otp_mibs).
-
-nt_basic_types(suite) ->
- [];
-nt_basic_types(doc) ->
- ["Query every item of the node table and check its variable "
- "type and content for sensible values."];
-nt_basic_types(Config) when is_list(Config) ->
- ok = otp_mib:update_erl_node_table(),
-
- NodeNameId = ?erlNodeEntry ++ [?erlNodeName, ?NODE_ENTRY],
- {noError, 0, [NodeNameVal]} = snmp_get([NodeNameId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeNameVal,
- true = is_list(NodeNameVal#varbind.value),
-
- NodeMachineId = ?erlNodeEntry ++ [?erlNodeMachine, ?NODE_ENTRY],
- {noError, 0, [NodeMachineVal]} = snmp_get([NodeMachineId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeMachineVal,
- true = is_list(NodeMachineVal#varbind.value),
-
- NodeVersionId = ?erlNodeEntry ++ [?erlNodeVersion, ?NODE_ENTRY],
- {noError, 0, [NodeVersionVal]} = snmp_get([NodeVersionId]),
- #varbind{variabletype = 'OCTET STRING'} = NodeVersionVal,
- true = is_list(NodeVersionVal#varbind.value),
-
- NodeRunQueueId = ?erlNodeEntry ++ [?erlNodeRunQueue, ?NODE_ENTRY],
- {noError, 0, [NodeRunQueueVal]} = snmp_get([NodeRunQueueId]),
- #varbind{variabletype = 'Unsigned32'} = NodeRunQueueVal,
- true = is_integer(NodeRunQueueVal#varbind.value),
- NodeRunQueueVal#varbind.value >= 0,
- NodeRunQueueVal#varbind.value =< 4294967295,
-
- NodeRunTimeId = ?erlNodeEntry ++ [?erlNodeRunTime, ?NODE_ENTRY],
- {noError, 0, [NodeRunTimeVal]} = snmp_get([NodeRunTimeId]),
- #varbind{variabletype = 'Counter64'} = NodeRunTimeVal,
- true = is_integer(NodeRunTimeVal#varbind.value),
- NodeRunTimeVal#varbind.value >= 0,
- NodeRunTimeVal#varbind.value =< 18446744073709551615,
-
- NodeWallClockId = ?erlNodeEntry ++ [?erlNodeWallClock, ?NODE_ENTRY],
- {noError, 0, [NodeWallClockVal]} = snmp_get([NodeWallClockId]),
- #varbind{variabletype = 'Counter64'} = NodeWallClockVal,
- true = is_integer(NodeWallClockVal#varbind.value),
- NodeWallClockVal#varbind.value >= 0,
- NodeWallClockVal#varbind.value =< 18446744073709551615,
-
- NodeReductionsId = ?erlNodeEntry ++ [?erlNodeReductions, ?NODE_ENTRY],
- {noError, 0, [NodeReductionsVal]} = snmp_get([NodeReductionsId]),
- #varbind{variabletype = 'Counter64'} = NodeReductionsVal,
- true = is_integer(NodeReductionsVal#varbind.value),
- NodeReductionsVal#varbind.value >= 0,
- NodeReductionsVal#varbind.value =< 18446744073709551615,
-
- NodeProcessesId = ?erlNodeEntry ++ [?erlNodeProcesses, ?NODE_ENTRY],
- {noError, 0, [NodeProcessesVal]} = snmp_get([NodeProcessesId]),
- #varbind{variabletype = 'Unsigned32'} = NodeProcessesVal,
- true = is_integer(NodeProcessesVal#varbind.value),
- NodeProcessesVal#varbind.value >= 0,
- NodeProcessesVal#varbind.value =< 4294967295,
-
- NodeInBytesId = ?erlNodeEntry ++ [?erlNodeInBytes, ?NODE_ENTRY],
- {noError, 0, [NodeInBytesVal]} = snmp_get([NodeInBytesId]),
- #varbind{variabletype = 'Counter64'} = NodeInBytesVal,
- true = is_integer(NodeInBytesVal#varbind.value),
- NodeInBytesVal#varbind.value >= 0,
- NodeInBytesVal#varbind.value =< 18446744073709551615,
-
- NodeOutBytesId = ?erlNodeEntry ++ [?erlNodeOutBytes, ?NODE_ENTRY],
- {noError, 0, [NodeOutBytesVal]} = snmp_get([NodeOutBytesId]),
- #varbind{variabletype = 'Counter64'} = NodeOutBytesVal,
- true = is_integer(NodeOutBytesVal#varbind.value),
- NodeOutBytesVal#varbind.value >= 0,
- NodeOutBytesVal#varbind.value =< 18446744073709551615,
-
- ok.
-
-nt_high_reduction_count(suite) ->
- [];
-nt_high_reduction_count(doc) ->
- ["Check that no error occurs when the erlNodeReductions field"
- "exceeds the 32bit boundary, this may take about 10min."];
-nt_high_reduction_count(Config) when is_list(Config) ->
- NodeReductions = ?erlNodeEntry ++ [?erlNodeReductions, ?NODE_ENTRY],
-
- BumpFun = fun(F, Limit) ->
- case erlang:statistics(reductions) of
- {Total, _} when Total < Limit ->
- F(F, Limit);
- _ ->
- ok
- end
- end,
-
- ok = otp_mib:update_erl_node_table(),
-
- {noError, 0, [StartVal]} = snmp_get([NodeReductions]),
- #varbind{variabletype = 'Counter64'} = StartVal,
- true = is_integer(StartVal#varbind.value),
- StartVal#varbind.value >= 0,
- case StartVal#varbind.value =< 4294967295 of
- true ->
- ok = otp_mib:update_erl_node_table(),
- BumpFun(BumpFun, 4294967295),
- {noError, 0, [EndVal]} = snmp_get([NodeReductions]),
- #varbind{variabletype = 'Counter64'} = EndVal,
- true = is_integer(EndVal#varbind.value),
- EndVal#varbind.value >= 4294967295,
- EndVal#varbind.value =< 18446744073709551615;
- false ->
- %% no need to bump more reductions, since the initial get
- %% command already returned successfully with a large value
- ok
- end.
-
-%%---------------------------------------------------------------------
-%% Internal functions
-%%---------------------------------------------------------------------
-
-snmp_get(OIdList) ->
- ct_snmp:get_values(otp_mibs_test, OIdList, snmp_mgr_agent).
-
-del_dir(Dir) ->
- io:format("Deleting: ~s~n",[Dir]),
- {ok, Files} = file:list_dir(Dir),
- FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end, Files),
- lists:foreach(fun file:delete/1, FullPathFiles),
- file:del_dir(Dir).
diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk
deleted file mode 100644
index 2e9e367d98..0000000000
--- a/lib/otp_mibs/vsn.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-OTP_MIBS_VSN = 1.2
-
-# Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and
-# should NOT be used again.
-
diff --git a/lib/parsetools/doc/src/Makefile b/lib/parsetools/doc/src/Makefile
index a40ccd0fe7..2e8b232902 100644
--- a/lib/parsetools/doc/src/Makefile
+++ b/lib/parsetools/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml
index 3e999c8cd0..f8cd9b972d 100644
--- a/lib/parsetools/doc/src/notes.xml
+++ b/lib/parsetools/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Parsetools application.</p>
+<section><title>Parsetools 2.1.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Parsetools 2.1.7</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index 210723e449..1a5201ce5d 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.1.7
+PARSETOOLS_VSN = 2.1.8
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index 37196bb9bf..10a83555af 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -368,6 +368,13 @@ SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
ID id-dsaWithSHA1
TYPE DSAParams }
+ id-dsa-with-sha224 OBJECT IDENTIFIER ::= {
+ joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+ csor(3) algorithms(4) id-dsa-with-sha2(3) 1 }
+
+ id-dsa-with-sha256 OBJECT IDENTIFIER ::= {
+ joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+ csor(3) algorithms(4) id-dsa-with-sha2(3) 2 }
--
-- RSA Keys and Signatures
--
diff --git a/lib/public_key/doc/specs/.gitignore b/lib/public_key/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/public_key/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index 03467e9783..c8647750af 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2017. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -77,12 +77,18 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
DVIPS_FLAGS +=
+SPECS_FLAGS = -I../../include -I../../src -I../../..
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
@@ -103,6 +109,7 @@ clean clean_docs:
rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+ rm -f $(SPECS_FILES)
rm -f errs core *~
man: $(MAN3_FILES) $(MAN6_FILES)
diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml
index 204520473a..62b4b4ca1b 100644
--- a/lib/public_key/doc/src/notes.xml
+++ b/lib/public_key/doc/src/notes.xml
@@ -35,6 +35,41 @@
<file>notes.xml</file>
</header>
+<section><title>Public_Key 1.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Removed <c>#DSAPrivateKey{}</c> as acceptable input to
+ <c>public_key:verify/5</c>.</p>
+ <p>
+ Own Id: OTP-15284</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The typing in the CRYPTO and PUBLIC_KEY applications are
+ reworked and a few mistakes are corrected.</p>
+ <p>
+ The documentation is now generated from the typing and
+ some clarifications are made.</p>
+ <p>
+ A new chapter on Algorithm Details such as key sizes and
+ availability is added to the CRYPTO User's Guide.</p>
+ <p>
+ Own Id: OTP-15134</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Public_Key 1.6.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index c0a67c25b8..1b588018e4 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -41,7 +41,7 @@
</description>
<section>
- <title>DATA TYPES</title>
+ <title>Common Records and ASN.1 Types</title>
<note><p>All records used in this Reference Manual
<!-- except #policy_tree_node{} -->
@@ -54,193 +54,132 @@
records and constant macros described here and in the User's Guide:</p>
<code> -include_lib("public_key/include/public_key.hrl").</code>
+ </section>
+
+ <datatypes>
+ <datatype>
+ <name name="oid"/>
+ <desc>
+ <p>Object identifier, a tuple of integers as generated by the <c>ASN.1</c> compiler.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="der_encoded"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pki_asn1_type"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="asn1_type"/>
+ <desc>
+ <p>ASN.1 type present in the Public Key applications ASN.1 specifications.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pem_entry"/>
+ <name name="der_or_encrypted_der"/>
+ <name name="cipher_info"/>
+ <name name="cipher"/>
+ <name name="salt"/>
+ <name name="cipher_info_params"/>
+ <desc>
+ <code>Cipher = "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC"</code>
+ <p><c>Salt</c> could be generated with
+ <seealso marker="crypto:crypto#strong_rand_bytes-1"><c>crypto:strong_rand_bytes(8)</c></seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="public_key"/>
+ <name name="rsa_public_key"/>
+ <name name="dsa_public_key"/>
+ <name name="ec_public_key"/>
+ <name name="ecpk_parameters"/>
+ <name name="ecpk_parameters_api"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="private_key"/>
+ <name name="rsa_private_key"/>
+ <name name="dsa_private_key"/>
+ <name name="ec_private_key"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="key_params"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="digest_type"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="crl_reason"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="issuer_id"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="issuer_name"/>
+ <desc>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="ssh_file"/>
+ <desc>
+ </desc>
+ </datatype>
+
+
+
+ </datatypes>
- <p>The following data types are used in the functions for <c>public_key</c>:</p>
-
- <taglist>
- <tag><c>oid()</c></tag>
- <item><p>Object identifier, a tuple of integers as generated by the <c>ASN.1</c> compiler.</p></item>
-
- <tag><c>boolean() =</c></tag>
- <item><p><c>true | false</c></p></item>
-
- <tag><c>string() =</c></tag>
- <item><p><c>[bytes()]</c></p></item>
-
- <tag><c>der_encoded() =</c></tag>
- <item><p><c>binary()</c></p></item>
-
- <tag><c>pki_asn1_type() =</c></tag>
- <item>
- <p><c>'Certificate'</c></p>
- <p><c>| 'RSAPrivateKey'</c></p>
- <p><c>| 'RSAPublicKey'</c></p>
- <p><c>| 'DSAPrivateKey'</c></p>
- <p><c>| 'DSAPublicKey'</c></p>
- <p><c>| 'DHParameter'</c></p>
- <p><c>| 'SubjectPublicKeyInfo'</c></p>
- <p><c>| 'PrivateKeyInfo'</c></p>
- <p><c>| 'CertificationRequest'</c></p>
- <p><c>| 'CertificateList'</c></p>
- <p><c>| 'ECPrivateKey'</c></p>
- <p><c>| 'EcpkParameters'</c></p>
- </item>
-
- <tag><c>pem_entry () =</c></tag>
- <item><p><c>{pki_asn1_type(), binary(), %% DER or encrypted DER</c></p>
- <p><c> not_encrypted | cipher_info()}</c></p></item>
-
- <tag><c>cipher_info() = </c></tag>
- <item><p><c>{"RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC", crypto:strong_rand_bytes(8)</c></p>
- <p><c>| {#'PBEParameter{}, digest_type()} | #'PBES2-params'{}}</c></p>
- </item>
-
- <tag><marker id="type-public_key"/>
- <c>public_key() =</c></tag>
- <item><p><c>rsa_public_key() | dsa_public_key() | ec_public_key()</c></p></item>
-
- <tag><marker id="type-private_key"/>
- <c>private_key() =</c></tag>
- <item><p><c>rsa_private_key() | dsa_private_key() | ec_private_key()</c></p></item>
-
- <tag><c>rsa_public_key() =</c></tag>
- <item><p><c>#'RSAPublicKey'{}</c></p></item>
-
- <tag><c>rsa_private_key() =</c></tag>
- <item><p><c>#'RSAPrivateKey'{}</c></p></item>
-
- <tag><c>dsa_public_key() =</c></tag>
- <item><p><c>{integer(), #'Dss-Parms'{}}</c></p></item>
-
- <tag><c>dsa_private_key() =</c></tag>
- <item><p><c>#'DSAPrivateKey'{}</c></p></item>
-
- <tag><c>ec_public_key()</c></tag>
- <item><p>= <c>{#'ECPoint'{}, #'ECParameters'{} | {namedCurve, oid()}}</c></p></item>
-
- <tag><c>ec_private_key() =</c></tag>
- <item><p><c>#'ECPrivateKey'{}</c></p></item>
-
- <tag><c>key_params() =</c></tag>
- <item><p> #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{}
- | {rsa, Size::integer(), PubExp::integer()} </p></item>
-
- <tag><c>public_crypt_options() =</c></tag>
- <item><p><c>[{rsa_pad, rsa_padding()}]</c></p></item>
-
- <tag><c>rsa_padding() =</c></tag>
- <item>
- <p><c>'rsa_pkcs1_padding'</c></p>
- <p><c>| 'rsa_pkcs1_oaep_padding'</c></p>
- <p><c>| 'rsa_no_padding'</c></p>
- </item>
-
- <tag><c>public_sign_options() =</c></tag>
- <item><p><c>[{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}]</c></p></item>
-
- <tag><c>rsa_sign_padding() =</c></tag>
- <item>
- <p><c>'rsa_pkcs1_padding'</c></p>
- <p><c>| 'rsa_pkcs1_pss_padding'</c></p>
- </item>
-
- <tag><c>digest_type() = </c></tag>
- <item><p>Union of <c>rsa_digest_type()</c>, <c>dss_digest_type()</c>,
- and <c>ecdsa_digest_type()</c>.</p></item>
-
- <tag><c>rsa_digest_type() = </c></tag>
- <item><p><c>'md5' | 'ripemd160' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p></item>
-
- <tag><c>dss_digest_type() = </c></tag>
- <item><p><c>'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p>
- <p>Note that the actual supported dss_digest_type depends on the underlying crypto library.
- In OpenSSL version >= 1.0.1 the listed digest are supported, while in 1.0.0 only
- sha, sha224 and sha256 are supported. In version 0.9.8 only sha is supported.</p>
- </item>
-
- <tag><c>ecdsa_digest_type() = </c></tag>
- <item><p><c>'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'</c></p></item>
-
- <tag><c>crl_reason() = </c></tag>
- <item>
- <p><c>unspecified</c></p>
- <p><c>| keyCompromise</c></p>
- <p><c>| cACompromise</c></p>
- <p><c>| affiliationChanged</c></p>
- <p><c>| superseded</c></p>
- <p><c>| cessationOfOperation</c></p>
- <p><c>| certificateHold</c></p>
- <p><c>| privilegeWithdrawn</c></p>
- <p><c>| aACompromise</c></p>
- </item>
-
- <tag><c>issuer_name() =</c></tag>
- <item><p><c>{rdnSequence,[#'AttributeTypeAndValue'{}]}</c></p>
- </item>
-
- <tag><c>ssh_file() =</c></tag>
- <item>
- <p><c>openssh_public_key</c></p>
- <p><c>| rfc4716_public_key</c></p>
- <p><c>| known_hosts</c></p>
- <p><c>| auth_keys</c></p>
- </item>
- </taglist>
-
-
-<!-- <p><code>policy_tree() = [Root, Children]</code></p> -->
-
-<!-- <p><code>Root = #policy_tree_node{}</code></p> -->
-
-<!-- <p><code>Children = [] | policy_tree()</code></p> -->
-
-<!-- <p>The <c>policy_tree_node</c> record has the following fields:</p> -->
-
-<!-- <taglist> -->
-
-<!-- <tag>valid_policy</tag> -->
-<!-- <item>A single policy OID representing a -->
-<!-- valid policy for the path of length x.</item> -->
-
-<!-- <tag>qualifier_set</tag> -->
-<!-- <item>A set of policy qualifiers associated -->
-<!-- with the valid policy in certificate x.</item> -->
-
-<!-- <tag>critically_indicator</tag> -->
-<!-- <item>Indicates whether the -->
-<!-- certificate policy extension in certificate x was marked as -->
-<!-- critical.</item> -->
-
-<!-- <tag>expected_policy_set</tag> -->
-<!-- <item>Contains one or more policy OIDs -->
-<!-- that would satisfy this policy in the certificate x+1.</item> -->
-<!-- </taglist> -->
- </section>
<funcs>
<func>
- <name>compute_key(OthersKey, MyKey)-></name>
- <name>compute_key(OthersKey, MyKey, Params)-></name>
+ <name name="compute_key" arity="2"/>
+ <fsummary>Computes shared secret.</fsummary>
+ <desc>
+ <p>Computes shared secret.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name name="compute_key" arity="3"/>
<fsummary>Computes shared secret.</fsummary>
- <type>
- <v>OthersKey = #'ECPoint'{} | binary(), MyKey = #'ECPrivateKey'{} | binary()</v>
- <v>Params = #'DHParameter'{}</v>
- </type>
<desc>
<p>Computes shared secret.</p>
</desc>
</func>
<func>
- <name>decrypt_private(CipherText, Key) -> binary()</name>
- <name>decrypt_private(CipherText, Key, Options) -> binary()</name>
+ <name name="decrypt_private" arity="2"/>
+ <name name="decrypt_private" arity="3"/>
<fsummary>Public-key decryption.</fsummary>
- <type>
- <v>CipherText = binary()</v>
- <v>Key = rsa_private_key()</v>
- <v>Options = public_crypt_options()</v>
- </type>
<desc>
<p>Public-key decryption using the private key. See also <seealso
marker="crypto:crypto#private_decrypt/4">crypto:private_decrypt/4</seealso></p>
@@ -248,14 +187,9 @@
</func>
<func>
- <name>decrypt_public(CipherText, Key) - > binary()</name>
- <name>decrypt_public(CipherText, Key, Options) - > binary()</name>
+ <name name="decrypt_public" arity="2"/>
+ <name name="decrypt_public" arity="3"/>
<fsummary>Public-key decryption.</fsummary>
- <type>
- <v>CipherText = binary()</v>
- <v>Key = rsa_public_key()</v>
- <v>Options = public_crypt_options()</v>
- </type>
<desc>
<p>Public-key decryption using the public key. See also <seealso
marker="crypto:crypto#public_decrypt/4">crypto:public_decrypt/4</seealso></p>
@@ -263,47 +197,24 @@
</func>
<func>
- <name>der_decode(Asn1type, Der) -> term()</name>
+ <name name="der_decode" arity="2"/>
<fsummary>Decodes a public-key ASN.1 DER encoded entity.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>ASN.1 type present in the Public Key applications
- ASN.1 specifications.</d>
- <v>Der = der_encoded()</v>
- </type>
- <desc>
+ <desc>
<p>Decodes a public-key ASN.1 DER encoded entity.</p>
</desc>
</func>
-
+
<func>
- <name>der_encode(Asn1Type, Entity) -> der_encoded()</name>
+ <name name="der_encode" arity="2"/>
<fsummary>Encodes a public-key entity with ASN.1 DER encoding.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>ASN.1 type present in the Public Key applications
- ASN.1 specifications.</d>
- <v>Entity = term()</v>
- <d>Erlang representation of <c>Asn1Type</c></d>
- </type>
<desc>
<p>Encodes a public-key entity with ASN.1 DER encoding.</p>
</desc>
</func>
<func>
- <name>dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) -> {ok, {Size,Group}} | {error,Error}</name>
+ <name name="dh_gex_group" arity="4"/>
<fsummary>Selects a group for Diffie-Hellman key exchange</fsummary>
- <type>
- <v>MinSize = positive_integer()</v>
- <v>SuggestedSize = positive_integer()</v>
- <v>MaxSize = positive_integer()</v>
- <v>Groups = undefined | [{Size,[{G,P}]}]</v>
- <v>Size = positive_integer()</v>
- <v>Group = {G,P}</v>
- <v>G = positive_integer()</v>
- <v>P = positive_integer()</v>
- </type>
<desc>
<p>Selects a group for Diffie-Hellman key exchange with the key size in the range <c>MinSize...MaxSize</c>
and as close to <c>SuggestedSize</c> as possible. If <c>Groups == undefined</c> a default set will be
@@ -322,13 +233,10 @@
</desc>
</func>
- <func>
- <name>encrypt_private(PlainText, Key) -> binary()</name>
+ <func>
+ <name name="encrypt_private" arity="2"/>
+ <name name="encrypt_private" arity="3"/>
<fsummary>Public-key encryption using the private key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>Key = rsa_private_key()</v>
- </type>
<desc>
<p>Public-key encryption using the private key.
See also <seealso
@@ -337,12 +245,9 @@
</func>
<func>
- <name>encrypt_public(PlainText, Key) -> binary()</name>
+ <name name="encrypt_public" arity="2"/>
+ <name name="encrypt_public" arity="3"/>
<fsummary>Public-key encryption using the public key.</fsummary>
- <type>
- <v>PlainText = binary()</v>
- <v>Key = rsa_public_key()</v>
- </type>
<desc>
<p>Public-key encryption using the public key. See also <seealso
marker="crypto:crypto#public_encrypt/4">crypto:public_encrypt/4</seealso>.</p>
@@ -350,11 +255,8 @@
</func>
<func>
- <name>generate_key(Params) -> {Public::binary(), Private::binary()} | #'ECPrivateKey'{} | #'RSAPrivateKey'{}</name>
+ <name name="generate_key" arity="1"/>
<fsummary>Generates a new keypair.</fsummary>
- <type>
- <v>Params = key_params()</v>
- </type>
<desc>
<p>Generates a new keypair. Note that except for Diffie-Hellman
the public key is included in the private key structure. See also
@@ -364,38 +266,27 @@
</func>
<func>
- <name>pem_decode(PemBin) -> [pem_entry()]</name>
+ <name name="pem_decode" arity="1"/>
<fsummary>Decodes PEM binary data and returns
entries as ASN.1 DER encoded entities.</fsummary>
- <type>
- <v>PemBin = binary()</v>
- <d>Example {ok, PemBin} = file:read_file("cert.pem").</d>
- </type>
<desc>
- <p>Decodes PEM binary data and returns
- entries as ASN.1 DER encoded entities.</p>
+ <p>Decodes PEM binary data and returns entries as ASN.1 DER encoded entities.</p>
+ <p>Example <c>{ok, PemBin} = file:read_file("cert.pem").</c></p>
</desc>
</func>
- <func>
- <name>pem_encode(PemEntries) -> binary()</name>
+ <func>
+ <name name="pem_encode" arity="1"/>
<fsummary>Creates a PEM binary.</fsummary>
- <type>
- <v> PemEntries = [pem_entry()] </v>
- </type>
- <desc>
- <p>Creates a PEM binary.</p>
- </desc>
+ <desc>
+ <p>Creates a PEM binary.</p>
+ </desc>
</func>
- <func>
- <name>pem_entry_decode(PemEntry) -> term()</name>
- <name>pem_entry_decode(PemEntry, Password) -> term()</name>
+ <func>
+ <name name="pem_entry_decode" arity="1"/>
+ <name name="pem_entry_decode" arity="2"/>
<fsummary>Decodes a PEM entry.</fsummary>
- <type>
- <v>PemEntry = pem_entry()</v>
- <v>Password = string()</v>
- </type>
<desc>
<p>Decodes a PEM entry. <c>pem_decode/1</c> returns a list of PEM
entries. Notice that if the PEM entry is of type
@@ -404,51 +295,36 @@
</desc>
</func>
- <func>
- <name>pem_entry_encode(Asn1Type, Entity) -> pem_entry()</name>
- <name>pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry()</name>
+ <func>
+ <name name="pem_entry_encode" arity="2"/>
+ <name name="pem_entry_encode" arity="3"/>
<fsummary>Creates a PEM entry that can be fed to <c>pem_encode/1</c>.</fsummary>
- <type>
- <v>Asn1Type = pki_asn1_type()</v>
- <v>Entity = term()</v>
- <d>Erlang representation of
- <c>Asn1Type</c>. If <c>Asn1Type</c> is 'SubjectPublicKeyInfo',
+ <desc>
+ <p>Creates a PEM entry that can be feed to <c>pem_encode/1</c>.</p>
+ <p>If <c>Asn1Type</c> is <c>'SubjectPublicKeyInfo'</c>,
<c>Entity</c> must be either an <c>rsa_public_key()</c>,
<c>dsa_public_key()</c> or an <c>ec_public_key()</c>
and this function creates the appropriate
- 'SubjectPublicKeyInfo' entry.
- </d>
- <v>CipherInfo = cipher_info()</v>
- <v>Password = string()</v>
- </type>
- <desc>
- <p>Creates a PEM entry that can be feed to <c>pem_encode/1</c>.</p>
- </desc>
+ <c>'SubjectPublicKeyInfo'</c> entry.
+ </p>
+ </desc>
</func>
-
+
<func>
- <name>pkix_decode_cert(Cert, otp|plain) -> #'Certificate'{} | #'OTPCertificate'{}</name>
+ <name name="pkix_decode_cert" arity="2"/>
<fsummary>Decodes an ASN.1 DER-encoded PKIX x509 certificate.</fsummary>
- <type>
- <v>Cert = der_encoded()</v>
- </type>
- <desc>
- <p>Decodes an ASN.1 DER-encoded PKIX certificate. Option <c>otp</c>
- uses the customized ASN.1 specification OTP-PKIX.asn1 for
- decoding and also recursively decode most of the standard
- parts.</p>
- </desc>
+ <desc>
+ <p>Decodes an ASN.1 DER-encoded PKIX certificate. Option <c>otp</c>
+ uses the customized ASN.1 specification OTP-PKIX.asn1 for
+ decoding and also recursively decode most of the standard
+ parts.</p>
+ </desc>
</func>
<func>
- <name>pkix_encode(Asn1Type, Entity, otp | plain) -> der_encoded()</name>
+ <name name="pkix_encode" arity="3"/>
<fsummary>DER encodes a PKIX x509 certificate or part of such a
certificate.</fsummary>
- <type>
- <v>Asn1Type = atom()</v>
- <d>The ASN.1 type can be 'Certificate', 'OTPCertificate' or a subtype of either.</d>
- <v>Entity = #'Certificate'{} | #'OTPCertificate'{} | a valid subtype</v>
- </type>
<desc>
<p>DER encodes a PKIX x509 certificate or part of such a
certificate. This function must be used for encoding certificates or parts of certificates
@@ -458,69 +334,47 @@
</func>
<func>
- <name>pkix_is_issuer(Cert, IssuerCert) -> boolean()</name>
- <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{} | #'CertificateList'{}</v>
- <v>IssuerCert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</p>
- </desc>
- </func>
+ <name name="pkix_is_issuer" arity="2"/>
+ <fsummary>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</fsummary>
+ <desc>
+ <p>Checks if <c>IssuerCert</c> issued <c>Cert</c>.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_is_fixed_dh_cert(Cert) -> boolean()</name>
- <fsummary>Checks if a certificate is a fixed Diffie-Hellman certificate.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if a certificate is a fixed Diffie-Hellman certificate.</p>
- </desc>
- </func>
+ <func>
+ <name name="pkix_is_fixed_dh_cert" arity="1"/>
+ <fsummary>Checks if a certificate is a fixed Diffie-Hellman certificate.</fsummary>
+ <desc>
+ <p>Checks if a certificate is a fixed Diffie-Hellman certificate.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_is_self_signed(Cert) -> boolean()</name>
- <fsummary>Checks if a certificate is self-signed.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- </type>
- <desc>
- <p>Checks if a certificate is self-signed.</p>
- </desc>
- </func>
+ <func>
+ <name name="pkix_is_self_signed" arity="1"/>
+ <fsummary>Checks if a certificate is self-signed.</fsummary>
+ <desc>
+ <p>Checks if a certificate is self-signed.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_issuer_id(Cert, IssuedBy) -> {ok, IssuerID} | {error, Reason}</name>
- <fsummary>Returns the issuer id.</fsummary>
- <type>
- <v>Cert = der_encoded() | #'OTPCertificate'{}</v>
- <v>IssuedBy = self | other</v>
- <v>IssuerID = {integer(), issuer_name()}</v>
- <d>The issuer id consists of the serial number and the issuers name.</d>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Returns the issuer id.</p>
- </desc>
- </func>
-
+ <func>
+ <name name="pkix_issuer_id" arity="2"/>
+ <fsummary>Returns the issuer id.</fsummary>
+ <desc>
+ <p>Returns the issuer id.</p>
+ </desc>
+ </func>
- <func>
- <name>pkix_normalize_name(Issuer) -> Normalized</name>
- <fsummary>Normalizes an issuer name so that it can be easily
- compared to another issuer name.</fsummary>
- <type>
- <v>Issuer = issuer_name()</v>
- <v>Normalized = issuer_name()</v>
- </type>
- <desc>
- <p>Normalizes an issuer name so that it can be easily
- compared to another issuer name.</p>
- </desc>
- </func>
-
+ <func>
+ <name name="pkix_normalize_name" arity="1"/>
+ <fsummary>Normalizes an issuer name so that it can be easily
+ compared to another issuer name.</fsummary>
+ <desc>
+ <p>Normalizes an issuer name so that it can be easily
+ compared to another issuer name.</p>
+ </desc>
+ </func>
+
<func>
<name>pkix_path_validation(TrustedCert, CertChain, Options) -> {ok, {PublicKeyInfo, PolicyTree}} | {error, {bad_cert, Reason}} </name>
<fsummary>Performs a basic path validation according to RFC 5280.</fsummary>
@@ -622,26 +476,16 @@ fun(OtpCert :: #'OTPCertificate'{},
</func>
<func>
- <name>pkix_crl_issuer(CRL) -> issuer_name()</name>
+ <name name="pkix_crl_issuer" arity="1"/>
<fsummary>Returns the issuer of the <c>CRL</c>.</fsummary>
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- </type>
<desc>
<p>Returns the issuer of the <c>CRL</c>.</p>
</desc>
</func>
<func>
- <name>pkix_crls_validate(OTPCertificate, DPAndCRLs, Options) -> CRLStatus()</name>
+ <name name="pkix_crls_validate" arity="3"/>
<fsummary>Performs CRL validation.</fsummary>
- <type>
- <v>OTPCertificate = #'OTPCertificate'{}</v>
- <v>DPAndCRLs = [{DP::#'DistributionPoint'{}, {DerCRL::der_encoded(), CRL::#'CertificateList'{}}}] </v>
- <v>Options = proplists:proplist()</v>
- <v>CRLStatus() = valid | {bad_cert, revocation_status_undetermined} | {bad_cert, {revocation_status_undetermined,
- {bad_crls, Details::term()}}} | {bad_cert, {revoked, crl_reason()}}</v>
- </type>
<desc>
<p>Performs CRL validation. It is intended to be called from
the verify fun of <seealso marker="#pkix_path_validation-3"> pkix_path_validation/3
@@ -682,7 +526,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<tag>{undetermined_details, boolean()}</tag>
<item>
- <p>Defaults to false. When revocation status can not be
+ <p>Defaults to false. When revocation status cannot be
determined, and this option is set to true, details of why no
CRLs where accepted are included in the return value.</p>
</item>
@@ -692,24 +536,16 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_crl_verify(CRL, Cert) -> boolean()</name>
+ <name name="pkix_crl_verify" arity="2"/>
<fsummary> Verify that <c>Cert</c> is the <c> CRL</c> signer. </fsummary>
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- <v>Cert = der_encoded() | #'OTPCertificate'{} </v>
- </type>
<desc>
<p>Verify that <c>Cert</c> is the <c>CRL</c> signer.</p>
</desc>
</func>
<func>
- <name>pkix_dist_point(Cert) -> DistPoint</name>
+ <name name="pkix_dist_point" arity="1"/>
<fsummary>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.</fsummary>
- <type>
- <v> Cert = der_encoded() | #'OTPCertificate'{} </v>
- <v> DistPoint = #'DistributionPoint'{}</v>
- </type>
<desc>
<p>Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.
Can be used as input to <seealso
@@ -719,26 +555,17 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_dist_points(Cert) -> DistPoints</name>
+ <name name="pkix_dist_points" arity="1"/>
<fsummary> Extracts distribution points from the certificates extensions.</fsummary>
- <type>
- <v> Cert = der_encoded() | #'OTPCertificate'{} </v>
- <v> DistPoints = [#'DistributionPoint'{}]</v>
- </type>
<desc>
<p> Extracts distribution points from the certificates extensions.</p>
</desc>
</func>
<func>
- <name>pkix_match_dist_point(CRL, DistPoint) -> boolean()</name>
+ <name name="pkix_match_dist_point" arity="2"/>
<fsummary>Checks whether the given distribution point matches the
Issuing Distribution Point of the CRL.</fsummary>
-
- <type>
- <v>CRL = der_encoded() | #'CertificateList'{} </v>
- <v>DistPoint = #'DistributionPoint'{}</v>
- </type>
<desc>
<p>Checks whether the given distribution point matches the
Issuing Distribution Point of the CRL, as described in RFC 5280.
@@ -748,11 +575,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_sign(#'OTPTBSCertificate'{}, Key) -> der_encoded()</name>
+ <name name="pkix_sign" arity="2"/>
<fsummary>Signs certificate.</fsummary>
- <type>
- <v>Key = rsa_private_key() | dsa_private_key()</v>
- </type>
<desc>
<p>Signs an 'OTPTBSCertificate'. Returns the corresponding
DER-encoded certificate.</p>
@@ -760,17 +584,12 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_sign_types(AlgorithmId) -> {DigestType, SignatureType}</name>
+ <name name="pkix_sign_types" arity="1"/>
<fsummary>Translates signature algorithm OID to Erlang digest and signature algorithm types.</fsummary>
- <type>
- <v>AlgorithmId = oid()</v>
- <d>Signature OID from a certificate or a certificate revocation list.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type()</v>
- <v>SignatureType = rsa | dsa | ecdsa</v>
- </type>
<desc>
<p>Translates signature algorithm OID to Erlang digest and signature types.
</p>
+ <p>The <c>AlgorithmId</c> is the signature OID from a certificate or a certificate revocation list.</p>
</desc>
</func>
@@ -902,7 +721,7 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
<note><p>
Note that the generated certificates and keys does not provide a formally correct PKIX-trust-chain
- and they can not be used to achieve real security. This function is provided for testing purposes only.
+ and they cannot be used to achieve real security. This function is provided for testing purposes only.
</p></note>
</desc>
</func>
@@ -938,12 +757,8 @@ fun(#'DistributionPoint'{}, #'CertificateList'{},
</func>
<func>
- <name>pkix_verify(Cert, Key) -> boolean()</name>
+ <name name="pkix_verify" arity="2"/>
<fsummary>Verifies PKIX x.509 certificate signature.</fsummary>
- <type>
- <v>Cert = der_encoded()</v>
- <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
- </type>
<desc>
<p>Verifies PKIX x.509 certificate signature.</p>
</desc>
@@ -1059,41 +874,30 @@ end
<func>
- <name>sign(Msg, DigestType, Key) -> binary()</name>
- <name>sign(Msg, DigestType, Key, Options) -> binary()</name>
+ <name name="sign" arity="3"/>
+ <name name="sign" arity="4"/>
<fsummary>Creates a digital signature.</fsummary>
- <type>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The <c>Msg</c> is either the binary "plain text" data to be
- signed or it is the hashed value of "plain text", that is, the
- digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Key = rsa_private_key() | dsa_private_key() | ec_private_key()</v>
- <v>Options = public_sign_options()</v>
- </type>
<desc>
<p>Creates a digital signature.</p>
+ <p>The <c>Msg</c> is either the binary "plain text" data to be
+ signed or it is the hashed value of "plain text", that is, the
+ digest.</p>
</desc>
</func>
<func>
- <name>ssh_decode(SshBin, Type) -> [{public_key(), Attributes::list()}]</name>
+ <name name="ssh_decode" arity="2"/>
<fsummary>Decodes an SSH file-binary.</fsummary>
- <type>
- <v>SshBin = binary()</v>
- <d>Example <c>{ok, SshBin} = file:read_file("known_hosts")</c>.</d>
- <v>Type = public_key | ssh_file()</v>
- <d>If <c>Type</c> is <c>public_key</c> the binary can be either
- an RFC4716 public key or an OpenSSH public key.</d>
- </type>
- <desc>
- <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or
- <c>auth_keys</c>, the binary can include one or more lines of the
- file. Returns a list of public keys and their attributes, possible
- attribute values depends on the file type represented by the
- binary.
- </p>
-
+ <desc>
+ <p>Decodes an SSH file-binary. In the case of <c>known_hosts</c> or
+ <c>auth_keys</c>, the binary can include one or more lines of the
+ file. Returns a list of public keys and their attributes, possible
+ attribute values depends on the file type represented by the
+ binary.
+ </p>
+ <p>If the <c>Type</c> is <c>ssh2_pubkey</c>, the result will be
+ <c>Decoded_ssh2_pubkey</c>. Otherwise it will be <c>Decoded_OtherType</c>.
+ </p>
<taglist>
<tag>RFC4716 attributes - see RFC 4716.</tag>
<item><p>{headers, [{string(), utf8_string()}]}</p></item>
@@ -1106,23 +910,25 @@ end
<item>{comment, string()}</item>
<item><p>{bits, integer()} - In SSH version 1 files.</p></item>
</taglist>
-
+ <p>Example: <c>{ok, SshBin} = file:read_file("known_hosts")</c>.
+ </p>
+ <p>If <c>Type</c> is <c>public_key</c> the binary can be either
+ an RFC4716 public key or an OpenSSH public key.</p>
</desc>
</func>
<func>
- <name>ssh_encode([{Key, Attributes}], Type) -> binary()</name>
+ <name name="ssh_encode" arity="2"/>
<fsummary>Encodes a list of SSH file entries to a binary.</fsummary>
- <type>
- <v>Key = public_key()</v>
- <v>Attributes = list()</v>
- <v>Type = ssh_file()</v>
- </type>
- <desc>
- <p>Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible
- attributes depend on the file type, see <seealso
- marker="#ssh_decode-2"> ssh_decode/2 </seealso>.</p>
- </desc>
+ <desc>
+ <p>Encodes a list of SSH file entries (public keys and attributes) to a binary. Possible
+ attributes depend on the file type, see
+ <seealso marker="#ssh_decode-2"> ssh_decode/2 </seealso>.
+ </p>
+ <p>If the <c>Type</c> is <c>ssh2_pubkey</c>, the <c>InData</c> shall be
+ <c>InData_ssh2_pubkey</c>. Otherwise it shall be <c>OtherInData</c>.
+ </p>
+ </desc>
</func>
<func>
@@ -1131,8 +937,8 @@ end
<name>ssh_hostkey_fingerprint([DigestType], HostKey) -> [string()]</name>
<fsummary>Calculates a ssh fingerprint for a hostkey.</fsummary>
<type>
- <v>Key = public_key()</v>
- <v>DigestType = digest_type()</v>
+ <v>HostKey = <seealso marker="#type-public_key">public_key()</seealso></v>
+ <v>DigestType = <seealso marker="#type-digest_type">digest_type()</seealso></v>
</type>
<desc>
<p>Calculates a ssh fingerprint from a public host key as openssh does.</p>
@@ -1161,29 +967,19 @@ end
</func>
<func>
- <name>verify(Msg, DigestType, Signature, Key) -> boolean()</name>
- <name>verify(Msg, DigestType, Signature, Key, Options) -> boolean()</name>
+ <name name="verify" arity="4"/>
+ <name name="verify" arity="5"/>
<fsummary>Verifies a digital signature.</fsummary>
- <type>
- <v>Msg = binary() | {digest,binary()}</v>
- <d>The <c>Msg</c> is either the binary "plain text" data
- or it is the hashed value of "plain text", that is, the digest.</d>
- <v>DigestType = rsa_digest_type() | dss_digest_type() | ecdsa_digest_type()</v>
- <v>Signature = binary()</v>
- <v>Key = rsa_public_key() | dsa_public_key() | ec_public_key()</v>
- <v>Options = public_sign_options()</v>
- </type>
<desc>
<p>Verifies a digital signature.</p>
+ <p>The <c>Msg</c> is either the binary "plain text" data
+ or it is the hashed value of "plain text", that is, the digest.</p>
</desc>
</func>
<func>
- <name>short_name_hash(Name) -> string()</name>
+ <name name="short_name_hash" arity="1"/>
<fsummary>Generates a short hash of an issuer name.</fsummary>
- <type>
- <v>Name = issuer_name()</v>
- </type>
<desc>
<p>Generates a short hash of an issuer name. The hash is
returned as a string containing eight hexadecimal digits.</p>
diff --git a/lib/public_key/doc/src/specs.xml b/lib/public_key/doc/src/specs.xml
new file mode 100644
index 0000000000..e358ea1154
--- /dev/null
+++ b/lib/public_key/doc/src/specs.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_public_key.xml"/>
+</specs>
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index b34f905fc3..dca1e0766e 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -76,7 +76,7 @@
-type dsa_private_key() :: #'DSAPrivateKey'{}.
-type dsa_public_key() :: {integer(), #'Dss-Parms'{}}.
-type ecpk_parameters() :: {ecParameters, #'ECParameters'{}} | {namedCurve, Oid::tuple()}.
--type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::atom()}.
+-type ecpk_parameters_api() :: ecpk_parameters() | #'ECParameters'{} | {namedCurve, Name::crypto:ec_named_curve()}.
-type ec_public_key() :: {#'ECPoint'{}, ecpk_parameters_api()}.
-type ec_private_key() :: #'ECPrivateKey'{}.
-type key_params() :: #'DHParameter'{} | {namedCurve, oid()} | #'ECParameters'{} |
@@ -88,28 +88,41 @@
'CertificationRequest' | 'CertificateList' |
'ECPrivateKey' | 'EcpkParameters'.
-type pem_entry() :: {pki_asn1_type(),
- binary(), %% DER or Encrypted DER
- not_encrypted | {Cipher :: string(), Salt :: binary()} |
- {Cipher :: string(), #'PBES2-params'{}} |
- {Cipher :: string(), {#'PBEParameter'{}, atom()}} %% hash type
+ der_or_encrypted_der(),
+ not_encrypted | cipher_info()
}.
+-type der_or_encrypted_der() :: binary().
+-type cipher_info() :: {cipher(),
+ cipher_info_params()} .
+-type cipher() :: string() . % "RC2-CBC" | "DES-CBC" | "DES-EDE3-CBC",
+-type cipher_info_params() :: salt()
+ | {#'PBEParameter'{}, digest_type()}
+ | #'PBES2-params'{} .
+
+-type salt() :: binary(). % crypto:strong_rand_bytes(8)
+%% -type cipher_info() :: {Cipher :: string(), Salt :: binary()} |
+%% {Cipher :: string(), #'PBES2-params'{}} |
+%% {Cipher :: string(), {#'PBEParameter'{}, atom()}} %% hash type
+%% .
+
-type asn1_type() :: atom(). %% see "OTP-PUB-KEY.hrl
-type ssh_file() :: openssh_public_key | rfc4716_public_key | known_hosts |
auth_keys.
--type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
- | 'rsa_no_padding'.
--type rsa_sign_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_pss_padding'.
--type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
--type rsa_digest_type() :: 'md5' | 'ripemd160' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
--type dss_digest_type() :: 'none' | 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'. %% None is for backwards compatibility
--type ecdsa_digest_type() :: 'sha' | 'sha224' | 'sha256' | 'sha384' | 'sha512'.
--type public_sign_options() :: [{rsa_pad, rsa_sign_padding()} | {rsa_pss_saltlen, integer()}].
--type digest_type() :: rsa_digest_type() | dss_digest_type() | ecdsa_digest_type().
+-type digest_type() :: none % None is for backwards compatibility
+ | crypto:rsa_digest_type()
+ | crypto:dss_digest_type()
+ | crypto:ecdsa_digest_type().
-type crl_reason() :: unspecified | keyCompromise | cACompromise | affiliationChanged | superseded
| cessationOfOperation | certificateHold | privilegeWithdrawn | aACompromise.
-type oid() :: tuple().
-type chain_type() :: server_chain | client_chain.
+-type issuer_id() :: {SerialNr::integer(), issuer_name()} .
+
+-type issuer_name() :: {rdnSequence,[#'AttributeTypeAndValue'{}]} .
+
+
+
-define(UINT32(X), X:32/unsigned-big-integer).
-define(DER_NULL, <<5, 0>>).
@@ -134,11 +147,11 @@ pem_encode(PemEntries) when is_list(PemEntries) ->
iolist_to_binary(pubkey_pem:encode(PemEntries)).
%%--------------------------------------------------------------------
--spec pem_entry_decode(pem_entry(), string()) -> term().
-%
%% Description: Decodes a pem entry. pem_decode/1 returns a list of
%% pem entries.
%%--------------------------------------------------------------------
+-spec pem_entry_decode(PemEntry) -> term() when PemEntry :: pem_entry() .
+
pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
{_, {'AlgorithmIdentifier', AlgId, Params}, Key0}
= der_decode('SubjectPublicKeyInfo', Der),
@@ -156,6 +169,9 @@ pem_entry_decode({'SubjectPublicKeyInfo', Der, _}) ->
pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
is_binary(Der) ->
der_decode(Asn1Type, Der).
+
+-spec pem_entry_decode(PemEntry, Password) -> term() when PemEntry :: pem_entry(),
+ Password :: string() .
pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
is_binary(Der) ->
der_decode(Asn1Type, Der);
@@ -181,11 +197,12 @@ pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
%%--------------------------------------------------------------------
--spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry().
--spec pem_entry_encode(pki_asn1_type(), term(), term()) -> pem_entry().
%%
%% Description: Creates a pem entry that can be feed to pem_encode/1.
%%--------------------------------------------------------------------
+-spec pem_entry_encode(Asn1Type, Entity) -> pem_entry() when Asn1Type :: pki_asn1_type(),
+ Entity :: term() .
+
pem_entry_encode('SubjectPublicKeyInfo', Entity=#'RSAPublicKey'{}) ->
Der = der_encode('RSAPublicKey', Entity),
Spki = {'SubjectPublicKeyInfo',
@@ -208,6 +225,13 @@ pem_entry_encode('SubjectPublicKeyInfo',
pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
Der = der_encode(Asn1Type, Entity),
{Asn1Type, Der, not_encrypted}.
+
+-spec pem_entry_encode(Asn1Type, Entity, InfoPwd) ->
+ pem_entry() when Asn1Type :: pki_asn1_type(),
+ Entity :: term(),
+ InfoPwd :: {CipherInfo,Password},
+ CipherInfo :: cipher_info(),
+ Password :: string() .
pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo,
Password}) when is_atom(Asn1Type) andalso
is_list(Password) andalso
@@ -229,7 +253,9 @@ pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo,
do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password).
%%--------------------------------------------------------------------
--spec der_decode(asn1_type(), Der::binary()) -> term().
+-spec der_decode(Asn1Type, Der) -> Entity when Asn1Type :: asn1_type(),
+ Der :: binary(),
+ Entity :: term().
%%
%% Description: Decodes a public key asn1 der encoded entity.
%%--------------------------------------------------------------------
@@ -269,7 +295,9 @@ der_priv_key_decode(PKCS8Key) ->
PKCS8Key.
%%--------------------------------------------------------------------
--spec der_encode(asn1_type(), term()) -> Der::binary().
+-spec der_encode(Asn1Type, Entity) -> Der when Asn1Type :: asn1_type(),
+ Entity :: term(),
+ Der :: binary() .
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
@@ -311,8 +339,10 @@ der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
end.
%%--------------------------------------------------------------------
--spec pkix_decode_cert(Cert::binary(), plain | otp) ->
- #'Certificate'{} | #'OTPCertificate'{}.
+-spec pkix_decode_cert(Cert, Type) ->
+ #'Certificate'{} | #'OTPCertificate'{}
+ when Cert :: der_encoded(),
+ Type :: plain | otp .
%%
%% Description: Decodes an asn1 der encoded pkix certificate. The otp
%% option will use the customized asn1 specification OTP-PKIX.asn1 for
@@ -332,7 +362,11 @@ pkix_decode_cert(DerCert, otp) when is_binary(DerCert) ->
end.
%%--------------------------------------------------------------------
--spec pkix_encode(asn1_type(), term(), otp | plain) -> Der::binary().
+-spec pkix_encode(Asn1Type, Entity, Type) -> Der
+ when Asn1Type :: asn1_type(),
+ Entity :: term(),
+ Type :: otp | plain,
+ Der :: der_encoded() .
%%
%% Description: Der encodes a certificate or part of a certificate.
%% This function must be used for encoding certificates or parts of certificates
@@ -347,16 +381,21 @@ pkix_encode(Asn1Type, Term0, otp) when is_atom(Asn1Type) ->
der_encode(Asn1Type, Term).
%%--------------------------------------------------------------------
--spec decrypt_private(CipherText :: binary(), rsa_private_key()) ->
- PlainText :: binary().
--spec decrypt_private(CipherText :: binary(), rsa_private_key(),
- public_crypt_options()) -> PlainText :: binary().
%%
%% Description: Public key decryption using the private key.
%%--------------------------------------------------------------------
+-spec decrypt_private(CipherText, Key) ->
+ PlainText when CipherText :: binary(),
+ Key :: rsa_private_key(),
+ PlainText :: binary() .
decrypt_private(CipherText, Key) ->
decrypt_private(CipherText, Key, []).
+-spec decrypt_private(CipherText, Key, Options) ->
+ PlainText when CipherText :: binary(),
+ Key :: rsa_private_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
decrypt_private(CipherText,
#'RSAPrivateKey'{} = Key,
Options)
@@ -366,61 +405,69 @@ decrypt_private(CipherText,
crypto:private_decrypt(rsa, CipherText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
--spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key()) ->
- PlainText :: binary().
--spec decrypt_public(CipherText :: binary(), rsa_public_key() | rsa_private_key(),
- public_crypt_options()) -> PlainText :: binary().
-%% NOTE: The rsa_private_key() is not part of the documented API it is
-%% here for testing purposes, in a real situation this is not a relevant
-%% thing to do.
-%%
%% Description: Public key decryption using the public key.
%%--------------------------------------------------------------------
+-spec decrypt_public(CipherText, Key) ->
+ PlainText
+ when CipherText :: binary(),
+ Key :: rsa_public_key(),
+ PlainText :: binary() .
decrypt_public(CipherText, Key) ->
decrypt_public(CipherText, Key, []).
+-spec decrypt_public(CipherText, Key, Options) ->
+ PlainText
+ when CipherText :: binary(),
+ Key :: rsa_public_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ PlainText :: binary() .
decrypt_public(CipherText, #'RSAPublicKey'{modulus = N, publicExponent = E},
Options) when is_binary(CipherText), is_list(Options) ->
- decrypt_public(CipherText, N,E, Options);
-
-decrypt_public(CipherText,#'RSAPrivateKey'{modulus = N, publicExponent = E},
- Options) when is_binary(CipherText), is_list(Options) ->
- decrypt_public(CipherText, N,E, Options).
+ Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
+ crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
%%--------------------------------------------------------------------
--spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key()) ->
- CipherText :: binary().
--spec encrypt_public(PlainText :: binary(), rsa_public_key() | rsa_private_key(),
- public_crypt_options()) -> CipherText :: binary().
-
-%% NOTE: The rsa_private_key() is not part of the documented API it is
-%% here for testing purposes, in a real situation this is not a relevant
-%% thing to do.
-%%
%% Description: Public key encryption using the public key.
%%--------------------------------------------------------------------
+-spec encrypt_public(PlainText, Key) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_public_key(),
+ CipherText :: binary() .
encrypt_public(PlainText, Key) ->
encrypt_public(PlainText, Key, []).
-encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
- Options) when is_binary(PlainText), is_list(Options) ->
- encrypt_public(PlainText, N,E, Options);
-encrypt_public(PlainText, #'RSAPrivateKey'{modulus=N,publicExponent=E},
+-spec encrypt_public(PlainText, Key, Options) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_public_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ CipherText :: binary() .
+encrypt_public(PlainText, #'RSAPublicKey'{modulus=N,publicExponent=E},
Options) when is_binary(PlainText), is_list(Options) ->
- encrypt_public(PlainText, N,E, Options).
+ Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
+ crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
%%--------------------------------------------------------------------
--spec encrypt_private(PlainText :: binary(), rsa_private_key()) ->
- CipherText :: binary().
--spec encrypt_private(PlainText :: binary(), rsa_private_key(),
- public_crypt_options()) -> CipherText :: binary().
%%
%% Description: Public key encryption using the private key.
%%--------------------------------------------------------------------
+-spec encrypt_private(PlainText, Key) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_private_key(),
+ CipherText :: binary() .
encrypt_private(PlainText, Key) ->
encrypt_private(PlainText, Key, []).
+
+-spec encrypt_private(PlainText, Key, Options) ->
+ CipherText
+ when PlainText :: binary(),
+ Key :: rsa_private_key(),
+ Options :: crypto:pk_encrypt_decrypt_opts(),
+ CipherText :: binary() .
encrypt_private(PlainText,
#'RSAPrivateKey'{modulus = N, publicExponent = E,
privateExponent = D} = Key,
@@ -432,22 +479,42 @@ encrypt_private(PlainText,
crypto:private_encrypt(rsa, PlainText, format_rsa_private_key(Key), Padding).
%%--------------------------------------------------------------------
+%% Description: List available group sizes among the pre-computed dh groups
+%%--------------------------------------------------------------------
+-spec dh_gex_group_sizes() -> [pos_integer()].
dh_gex_group_sizes() ->
pubkey_ssh:dh_gex_group_sizes().
+%%--------------------------------------------------------------------
+%% Description: Select a precomputed group
+%%--------------------------------------------------------------------
+-spec dh_gex_group(MinSize, SuggestedSize, MaxSize, Groups) ->
+ {ok,{Size,Group}} | {error,term()}
+ when MinSize :: pos_integer(),
+ SuggestedSize :: pos_integer(),
+ MaxSize :: pos_integer(),
+ Groups :: undefined | [{Size,[Group]}],
+ Size :: pos_integer(),
+ Group :: {G,P},
+ G :: pos_integer(),
+ P :: pos_integer() .
dh_gex_group(Min, N, Max, Groups) ->
pubkey_ssh:dh_gex_group(Min, N, Max, Groups).
%%--------------------------------------------------------------------
--spec generate_key(#'DHParameter'{}) ->
- {Public::binary(), Private::binary()};
- (ecpk_parameters_api()) ->
- #'ECPrivateKey'{};
- ({rsa, Size::pos_integer(), PubExp::pos_integer()}) ->
- #'RSAPrivateKey'{}.
-
-%% Description: Generates a new keypair
+%% Description: Generate a new key pair
%%--------------------------------------------------------------------
+-spec generate_key(DHparams | ECparams | RSAparams) ->
+ DHkeys | ECkey | RSAkey
+ when DHparams :: #'DHParameter'{},
+ DHkeys :: {PublicDH::binary(), PrivateDH::binary()},
+ ECparams :: ecpk_parameters_api(),
+ ECkey :: #'ECPrivateKey'{},
+ RSAparams :: {rsa, Size, PubExp},
+ Size::pos_integer(),
+ PubExp::pos_integer(),
+ RSAkey :: #'RSAPrivateKey'{} .
+
generate_key(#'DHParameter'{prime = P, base = G}) ->
crypto:generate_key(dh, [P, G]);
generate_key({namedCurve, _} = Params) ->
@@ -494,24 +561,34 @@ generate_key({rsa, ModulusSize, PublicExponent}) ->
end.
%%--------------------------------------------------------------------
--spec compute_key(#'ECPoint'{} , #'ECPrivateKey'{}) -> binary().
--spec compute_key(OthersKey ::binary(), MyKey::binary(), #'DHParameter'{}) -> binary().
%% Description: Compute shared secret
%%--------------------------------------------------------------------
+-spec compute_key(OthersECDHkey, MyECDHkey) ->
+ SharedSecret
+ when OthersECDHkey :: #'ECPoint'{},
+ MyECDHkey :: #'ECPrivateKey'{},
+ SharedSecret :: binary().
compute_key(#'ECPoint'{point = Point}, #'ECPrivateKey'{privateKey = PrivKey,
parameters = Param}) ->
ECCurve = ec_curve_spec(Param),
crypto:compute_key(ecdh, Point, PrivKey, ECCurve).
+-spec compute_key(OthersDHkey, MyDHkey, DHparms) ->
+ SharedSecret
+ when OthersDHkey :: crypto:dh_public(), % Was: binary(),
+ MyDHkey :: crypto:dh_private(), % Was: binary(),
+ DHparms :: #'DHParameter'{},
+ SharedSecret :: binary().
compute_key(PubKey, PrivKey, #'DHParameter'{prime = P, base = G}) ->
crypto:compute_key(dh, PubKey, PrivKey, [P, G]).
%%--------------------------------------------------------------------
--spec pkix_sign_types(SignatureAlg::oid()) ->
- %% Relevant dsa digest type is subpart of rsa digest type
- { DigestType :: rsa_digest_type(),
- SignatureType :: rsa | dsa | ecdsa
- }.
+-spec pkix_sign_types(AlgorithmId) ->
+ {DigestType, SignatureType}
+ when AlgorithmId :: oid(),
+ %% Relevant dsa digest type is a subset of rsa_digest_type()
+ DigestType :: crypto:rsa_digest_type(),
+ SignatureType :: rsa | dsa | ecdsa .
%% Description:
%%--------------------------------------------------------------------
pkix_sign_types(?sha1WithRSAEncryption) ->
@@ -532,6 +609,10 @@ pkix_sign_types(?'id-dsa-with-sha1') ->
{sha, dsa};
pkix_sign_types(?'id-dsaWithSHA1') ->
{sha, dsa};
+pkix_sign_types(?'id-dsa-with-sha224') ->
+ {sha224, dsa};
+pkix_sign_types(?'id-dsa-with-sha256') ->
+ {sha256, dsa};
pkix_sign_types(?'ecdsa-with-SHA1') ->
{sha, ecdsa};
pkix_sign_types(?'ecdsa-with-SHA256') ->
@@ -542,24 +623,24 @@ pkix_sign_types(?'ecdsa-with-SHA512') ->
{sha512, ecdsa}.
%%--------------------------------------------------------------------
--spec sign(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- rsa_private_key() | dsa_private_key() | ec_private_key()
- ) -> Signature :: binary().
-
--spec sign(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- rsa_private_key() | dsa_private_key() | ec_private_key(),
- public_sign_options()
- ) -> Signature :: binary().
-
%% Description: Create digital signature.
%%--------------------------------------------------------------------
+-spec sign(Msg, DigestType, Key) ->
+ Signature when Msg :: binary() | {digest,binary()},
+ DigestType :: digest_type(),
+ Key :: private_key(),
+ Signature :: binary() .
sign(DigestOrPlainText, DigestType, Key) ->
sign(DigestOrPlainText, DigestType, Key, []).
-%% Backwards compatible
+-spec sign(Msg, DigestType, Key, Options) ->
+ Signature when Msg :: binary() | {digest,binary()},
+ DigestType :: digest_type(),
+ Key :: private_key(),
+ Options :: crypto:pk_sign_verify_opts(),
+ Signature :: binary() .
sign(Digest, none, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) ->
+ %% Backwards compatible
sign({digest, Digest}, sha, Key, Options);
sign(DigestOrPlainText, DigestType, Key, Options) ->
case format_sign_key(Key) of
@@ -570,30 +651,26 @@ sign(DigestOrPlainText, DigestType, Key, Options) ->
end.
%%--------------------------------------------------------------------
--spec verify(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- Signature :: binary(),
- rsa_public_key() | dsa_public_key() | ec_public_key()
- | rsa_private_key() | dsa_private_key() | ec_private_key()
- ) -> boolean().
-
--spec verify(binary() | {digest, binary()},
- rsa_digest_type() | dss_digest_type() | ecdsa_digest_type(),
- Signature :: binary(),
- rsa_public_key() | dsa_public_key() | ec_public_key()
- | rsa_private_key() | dsa_private_key() | ec_private_key(),
- public_sign_options()
- ) -> boolean().
-
%% Description: Verifies a digital signature.
%%--------------------------------------------------------------------
+-spec verify(Msg, DigestType, Signature, Key) ->
+ boolean() when Msg :: binary() | {digest, binary()},
+ DigestType :: digest_type(),
+ Signature :: binary(),
+ Key :: public_key() .
+
verify(DigestOrPlainText, DigestType, Signature, Key) ->
verify(DigestOrPlainText, DigestType, Signature, Key, []).
-%% Backwards compatible
+-spec verify(Msg, DigestType, Signature, Key, Options) ->
+ boolean() when Msg :: binary() | {digest, binary()},
+ DigestType :: digest_type(),
+ Signature :: binary(),
+ Key :: public_key(),
+ Options :: crypto:pk_sign_verify_opts().
+
verify(Digest, none, Signature, Key = {_, #'Dss-Parms'{}}, Options) when is_binary(Digest) ->
- verify({digest, Digest}, sha, Signature, Key, Options);
-verify(Digest, none, Signature, Key = #'DSAPrivateKey'{}, Options) when is_binary(Digest) ->
+ %% Backwards compatible
verify({digest, Digest}, sha, Signature, Key, Options);
verify(DigestOrPlainText, DigestType, Signature, Key, Options) when is_binary(Signature) ->
case format_verify_key(Key) of
@@ -608,8 +685,8 @@ verify(_,_,_,_,_) ->
false.
%%--------------------------------------------------------------------
--spec pkix_dist_point(der_encoded() | #'OTPCertificate'{}) ->
- #'DistributionPoint'{}.
+-spec pkix_dist_point(Cert) -> DistPoint when Cert :: der_encoded() | #'OTPCertificate'{},
+ DistPoint :: #'DistributionPoint'{}.
%% Description: Creates a distribution point for CRLs issued by the same issuer as <c>Cert</c>.
%%--------------------------------------------------------------------
pkix_dist_point(OtpCert) when is_binary(OtpCert) ->
@@ -632,8 +709,8 @@ pkix_dist_point(OtpCert) ->
reasons = asn1_NOVALUE,
distributionPoint = Point}.
%%--------------------------------------------------------------------
--spec pkix_dist_points(der_encoded() | #'OTPCertificate'{}) ->
- [#'DistributionPoint'{}].
+-spec pkix_dist_points(Cert) -> DistPoints when Cert :: der_encoded() | #'OTPCertificate'{},
+ DistPoints :: [ #'DistributionPoint'{} ].
%% Description: Extracts distributionpoints specified in the certificates extensions.
%%--------------------------------------------------------------------
pkix_dist_points(OtpCert) when is_binary(OtpCert) ->
@@ -647,8 +724,10 @@ pkix_dist_points(OtpCert) ->
[], Value).
%%--------------------------------------------------------------------
--spec pkix_match_dist_point(der_encoded() | #'CertificateList'{},
- #'DistributionPoint'{}) -> boolean().
+-spec pkix_match_dist_point(CRL, DistPoint) ->
+ boolean()
+ when CRL :: der_encoded() | #'CertificateList'{},
+ DistPoint :: #'DistributionPoint'{}.
%% Description: Check whether the given distribution point matches
%% the "issuing distribution point" of the CRL.
%%--------------------------------------------------------------------
@@ -679,8 +758,9 @@ pkix_match_dist_point(#'CertificateList'{
end.
%%--------------------------------------------------------------------
--spec pkix_sign(#'OTPTBSCertificate'{},
- rsa_private_key() | dsa_private_key() | ec_private_key()) -> Der::binary().
+-spec pkix_sign(Cert, Key) -> Der when Cert :: #'OTPTBSCertificate'{},
+ Key :: private_key(),
+ Der :: der_encoded() .
%%
%% Description: Sign a pkix x.509 certificate. Returns the corresponding
%% der encoded 'Certificate'{}
@@ -699,8 +779,8 @@ pkix_sign(#'OTPTBSCertificate'{signature =
pkix_encode('OTPCertificate', Cert, otp).
%%--------------------------------------------------------------------
--spec pkix_verify(Cert::binary(), rsa_public_key()|
- dsa_public_key() | ec_public_key()) -> boolean().
+-spec pkix_verify(Cert, Key) -> boolean() when Cert :: der_encoded(),
+ Key :: public_key() .
%%
%% Description: Verify pkix x.509 certificate signature.
%%--------------------------------------------------------------------
@@ -720,7 +800,9 @@ pkix_verify(DerCert, Key = {#'ECPoint'{}, _})
verify(PlainText, DigestType, Signature, Key).
%%--------------------------------------------------------------------
--spec pkix_crl_verify(CRL::binary() | #'CertificateList'{}, Cert::binary() | #'OTPCertificate'{}) -> boolean().
+-spec pkix_crl_verify(CRL, Cert) -> boolean()
+ when CRL :: der_encoded() | #'CertificateList'{},
+ Cert :: der_encoded() | #'OTPCertificate'{} .
%%
%% Description: Verify that Cert is the CRL signer.
%%--------------------------------------------------------------------
@@ -739,9 +821,12 @@ pkix_crl_verify(#'CertificateList'{} = CRL, #'OTPCertificate'{} = Cert) ->
PublicKey, PublicKeyParams).
%%--------------------------------------------------------------------
--spec pkix_is_issuer(Cert :: der_encoded()| #'OTPCertificate'{} | #'CertificateList'{},
- IssuerCert :: der_encoded()|
- #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_issuer(Cert, IssuerCert) ->
+ boolean() when Cert :: der_encoded()
+ | #'OTPCertificate'{}
+ | #'CertificateList'{},
+ IssuerCert :: der_encoded()
+ | #'OTPCertificate'{} .
%%
%% Description: Checks if <IssuerCert> issued <Cert>.
%%--------------------------------------------------------------------
@@ -761,7 +846,7 @@ pkix_is_issuer(#'CertificateList'{tbsCertList = TBSCRL},
pubkey_cert_records:transform(TBSCRL#'TBSCertList'.issuer, decode)).
%%--------------------------------------------------------------------
--spec pkix_is_self_signed(Cert::binary()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_self_signed(Cert) -> boolean() when Cert::der_encoded()| #'OTPCertificate'{}.
%%
%% Description: Checks if a Certificate is self signed.
%%--------------------------------------------------------------------
@@ -772,7 +857,7 @@ pkix_is_self_signed(Cert) when is_binary(Cert) ->
pkix_is_self_signed(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_is_fixed_dh_cert(Cert::binary()| #'OTPCertificate'{}) -> boolean().
+-spec pkix_is_fixed_dh_cert(Cert) -> boolean() when Cert::der_encoded()| #'OTPCertificate'{}.
%%
%% Description: Checks if a Certificate is a fixed Diffie-Hellman Cert.
%%--------------------------------------------------------------------
@@ -783,13 +868,12 @@ pkix_is_fixed_dh_cert(Cert) when is_binary(Cert) ->
pkix_is_fixed_dh_cert(OtpCert).
%%--------------------------------------------------------------------
--spec pkix_issuer_id(Cert::binary()| #'OTPCertificate'{},
- IssuedBy :: self | other) ->
- {ok, {SerialNr :: integer(),
- Issuer :: {rdnSequence,
- [#'AttributeTypeAndValue'{}]}}}
- | {error, Reason :: term()}.
-%
+-spec pkix_issuer_id(Cert, IssuedBy) ->
+ {ok, issuer_id()} | {error, Reason}
+ when Cert::der_encoded()| #'OTPCertificate'{},
+ IssuedBy :: self | other,
+ Reason :: term() .
+
%% Description: Returns the issuer id.
%%--------------------------------------------------------------------
pkix_issuer_id(#'OTPCertificate'{} = OtpCert, Signed) when (Signed == self) or
@@ -800,9 +884,9 @@ pkix_issuer_id(Cert, Signed) when is_binary(Cert) ->
pkix_issuer_id(OtpCert, Signed).
%%--------------------------------------------------------------------
--spec pkix_crl_issuer(CRL::binary()| #'CertificateList'{}) ->
- {rdnSequence,
- [#'AttributeTypeAndValue'{}]}.
+-spec pkix_crl_issuer(CRL| #'CertificateList'{}) ->
+ Issuer when CRL :: der_encoded(),
+ Issuer :: issuer_name() .
%
%% Description: Returns the issuer.
%%--------------------------------------------------------------------
@@ -813,10 +897,9 @@ pkix_crl_issuer(#'CertificateList'{} = CRL) ->
CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode).
%%--------------------------------------------------------------------
--spec pkix_normalize_name({rdnSequence,
- [#'AttributeTypeAndValue'{}]}) ->
- {rdnSequence,
- [#'AttributeTypeAndValue'{}]}.
+-spec pkix_normalize_name(Issuer) -> Normalized
+ when Issuer :: issuer_name(),
+ Normalized :: issuer_name() .
%%
%% Description: Normalizes a issuer name so that it can be easily
%% compared to another issuer name.
@@ -827,7 +910,7 @@ pkix_normalize_name(Issuer) ->
%%--------------------------------------------------------------------
-spec pkix_path_validation(Cert::binary()| #'OTPCertificate'{} | atom(),
CertChain :: [binary()] ,
- Options :: proplists:proplist()) ->
+ Options :: [{atom(),term()}]) ->
{ok, {PublicKeyInfo :: term(),
PolicyTree :: term()}} |
{error, {bad_cert, Reason :: term()}}.
@@ -863,11 +946,19 @@ pkix_path_validation(#'OTPCertificate'{} = TrustedCert, CertChain, Options)
path_validation(CertChain, ValidationState).
%--------------------------------------------------------------------
--spec pkix_crls_validate(#'OTPCertificate'{},
- [{DP::#'DistributionPoint'{}, {DerCRL::binary(), CRL::#'CertificateList'{}}}],
- Options :: proplists:proplist()) -> valid | {bad_cert, revocation_status_undetermined} |
- {bad_cert, {revocation_status_undetermined, Reason::term()}} |
- {bad_cert, {revoked, crl_reason()}}.
+-spec pkix_crls_validate(OTPcertificate, DPandCRLs, Options) ->
+ CRLstatus when OTPcertificate :: #'OTPCertificate'{},
+ DPandCRLs :: [DPandCRL],
+ DPandCRL :: {DP, {DerCRL, CRL}},
+ DP :: #'DistributionPoint'{},
+ DerCRL :: der_encoded(),
+ CRL :: #'CertificateList'{},
+ Options :: [{atom(),term()}],
+ CRLstatus :: valid
+ | {bad_cert, BadCertReason},
+ BadCertReason :: revocation_status_undetermined
+ | {revocation_status_undetermined, Reason::term()}
+ | {revoked, crl_reason()}.
%% Description: Performs a CRL validation according to RFC 5280.
%%--------------------------------------------------------------------
@@ -884,20 +975,10 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
Options, pubkey_crl:init_revokation_state()).
%--------------------------------------------------------------------
--spec pkix_verify_hostname(#'OTPCertificate'{} | binary(),
- referenceIDs()
- ) -> boolean().
-
--spec pkix_verify_hostname(#'OTPCertificate'{} | binary(),
- referenceIDs(),
- proplists:proplist()) -> boolean().
-
-type referenceIDs() :: [referenceID()] .
-type referenceID() :: {uri_id | dns_id | ip | srv_id | oid(), string()}
| {ip, inet:ip_address()} .
--spec pkix_verify_hostname_match_fun(high_level_alg()) -> match_fun() .
-
-type high_level_alg() :: https .
-type match_fun() :: fun((ReferenceID::referenceID() | string(),
PresentedID::{atom()|oid(),string()}) -> match_fun_result() ) .
@@ -905,9 +986,20 @@ pkix_crls_validate(OtpCert, DPAndCRLs0, Options) ->
%% Description: Validates a hostname to RFC 6125
%%--------------------------------------------------------------------
+-spec pkix_verify_hostname(Cert, ReferenceIDs) -> boolean()
+ when Cert :: der_encoded()
+ | #'OTPCertificate'{},
+ ReferenceIDs :: referenceIDs() .
pkix_verify_hostname(Cert, ReferenceIDs) ->
pkix_verify_hostname(Cert, ReferenceIDs, []).
+-spec pkix_verify_hostname(Cert, ReferenceIDs, Options) ->
+ boolean()
+ when Cert :: der_encoded()
+ | #'OTPCertificate'{},
+ ReferenceIDs :: referenceIDs(),
+ Options :: [{atom(),term()}] .
+
pkix_verify_hostname(BinCert, ReferenceIDs, Options) when is_binary(BinCert) ->
pkix_verify_hostname(pkix_decode_cert(BinCert,otp), ReferenceIDs, Options);
@@ -966,15 +1058,25 @@ pkix_verify_hostname(Cert = #'OTPCertificate'{tbsCertificate = TbsCert}, Referen
end
end.
+
+-spec pkix_verify_hostname_match_fun(high_level_alg()) -> match_fun() .
+
pkix_verify_hostname_match_fun(https) ->
fun({dns_id,FQDN=[_|_]}, {dNSName,Name=[_|_]}) -> verify_hostname_match_wildcard(FQDN, Name);
(_, _) -> default
end.
%%--------------------------------------------------------------------
--spec ssh_decode(binary(), public_key | ssh_file()) -> [{public_key(), Attributes::list()}]
- ; (binary(), ssh2_pubkey) -> public_key()
- .
+-spec ssh_decode(SshBin, Type) ->
+ Decoded
+ when SshBin :: binary(),
+ Type :: ssh2_pubkey | OtherType,
+ OtherType :: public_key | ssh_file(),
+ Decoded :: Decoded_ssh2_pubkey
+ | Decoded_OtherType,
+ Decoded_ssh2_pubkey :: public_key(),
+ Decoded_OtherType :: [{public_key(), Attributes}],
+ Attributes :: [{atom(),term()}] .
%%
%% Description: Decodes a ssh file-binary. In the case of know_hosts
%% or auth_keys the binary may include one or more lines of the
@@ -992,9 +1094,15 @@ ssh_decode(SshBin, Type) when is_binary(SshBin),
pubkey_ssh:decode(SshBin, Type).
%%--------------------------------------------------------------------
--spec ssh_encode([{public_key(), Attributes::list()}], ssh_file()) -> binary()
- ; (public_key(), ssh2_pubkey) -> binary()
- .
+-spec ssh_encode(InData, Type) ->
+ binary()
+ when Type :: ssh2_pubkey | OtherType,
+ OtherType :: public_key | ssh_file(),
+ InData :: InData_ssh2_pubkey | OtherInData,
+ InData_ssh2_pubkey :: public_key(),
+ OtherInData :: [{Key,Attributes}],
+ Key :: public_key(),
+ Attributes :: [{atom(),term()}] .
%%
%% Description: Encodes a list of ssh file entries (public keys and
%% attributes) to a binary. Possible attributes depends on the file
@@ -1029,13 +1137,14 @@ oid2ssh_curvename(?'secp521r1') -> <<"nistp521">>.
%%--------------------------------------------------------------------
-spec ssh_hostkey_fingerprint(public_key()) -> string().
--spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string()
- ; ([digest_type()], public_key()) -> [string()]
- .
ssh_hostkey_fingerprint(Key) ->
sshfp_string(md5, public_key:ssh_encode(Key,ssh2_pubkey) ).
+
+-spec ssh_hostkey_fingerprint( digest_type(), public_key()) -> string()
+ ; ([digest_type()], public_key()) -> [string()]
+ .
ssh_hostkey_fingerprint(HashAlgs, Key) when is_list(HashAlgs) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
[sshfp_full_string(HashAlg,EncKey) || HashAlg <- HashAlgs];
@@ -1073,8 +1182,7 @@ fp_fmt(b64, Bin) ->
[lists:nth(C+1,B64Chars) || <<C:6>> <= <<Bin/binary,0:Padding>> ].
%%--------------------------------------------------------------------
--spec short_name_hash({rdnSequence, [#'AttributeTypeAndValue'{}]}) ->
- string().
+-spec short_name_hash(Name) -> string() when Name :: issuer_name() .
%% Description: Generates OpenSSL-style hash of a name.
%%--------------------------------------------------------------------
@@ -1105,10 +1213,11 @@ pkix_test_data(#{} = Chain) ->
pubkey_cert:gen_test_certs(maps:merge(Default, Chain)).
%%--------------------------------------------------------------------
--spec pkix_test_root_cert(
- Name :: string(), Opts :: [pubkey_cert:cert_opt()]) ->
- pubkey_cert:test_root_cert().
-
+-spec pkix_test_root_cert(Name, Options) ->
+ RootCert
+ when Name :: string(),
+ Options :: [{atom(),term()}], %[cert_opt()],
+ RootCert :: pubkey_cert:test_root_cert().
%% Description: Generates a root cert suitable for pkix_test_data/1
%%--------------------------------------------------------------------
@@ -1154,14 +1263,6 @@ do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
Der = pubkey_pem:decipher(PemEntry, Password),
der_decode(Asn1Type, Der).
-encrypt_public(PlainText, N, E, Options)->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:public_encrypt(rsa, PlainText, [E,N], Padding).
-
-decrypt_public(CipherText, N,E, Options) ->
- Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
- crypto:public_decrypt(rsa, CipherText,[E, N], Padding).
-
path_validation([], #path_validation_state{working_public_key_algorithm
= Algorithm,
working_public_key =
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index cfd8e7a34b..878489eb0f 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -44,7 +44,9 @@ all() ->
encrypt_decrypt,
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
- pkix_iso_rsa_oid, pkix_iso_dsa_oid, pkix_crl, general_name,
+ pkix_iso_rsa_oid, pkix_iso_dsa_oid,
+ pkix_dsa_sha2_oid,
+ pkix_crl, general_name,
pkix_verify_hostname_cn,
pkix_verify_hostname_subjAltName,
pkix_verify_hostname_subjAltName_IP,
@@ -718,12 +720,8 @@ encrypt_decrypt(Config) when is_list(Config) ->
Msg = list_to_binary(lists:duplicate(5, "Foo bar 100")),
RsaEncrypted = public_key:encrypt_private(Msg, PrivateKey),
Msg = public_key:decrypt_public(RsaEncrypted, PublicKey),
- Msg = public_key:decrypt_public(RsaEncrypted, PrivateKey),
RsaEncrypted2 = public_key:encrypt_public(Msg, PublicKey),
- RsaEncrypted3 = public_key:encrypt_public(Msg, PrivateKey),
Msg = public_key:decrypt_private(RsaEncrypted2, PrivateKey),
- Msg = public_key:decrypt_private(RsaEncrypted3, PrivateKey),
-
ok.
%%--------------------------------------------------------------------
@@ -1118,6 +1116,13 @@ pkix_iso_dsa_oid(Config) when is_list(Config) ->
{_, dsa} = public_key:pkix_sign_types(SigAlg#'SignatureAlgorithm'.algorithm).
%%--------------------------------------------------------------------
+pkix_dsa_sha2_oid() ->
+ [{doc, "Test support dsa_sha2 oid"}].
+pkix_dsa_sha2_oid(Config) when is_list(Config) ->
+ {sha224, dsa} = public_key:pkix_sign_types(?'id-dsa-with-sha224'),
+ {sha256, dsa} = public_key:pkix_sign_types(?'id-dsa-with-sha256').
+
+%%--------------------------------------------------------------------
pkix_crl() ->
[{doc, "test pkix_crl_* functions"}].
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 5e9e463323..4e52028c36 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 1.6.1
+PUBLIC_KEY_VSN = 1.6.2
diff --git a/lib/reltool/doc/src/Makefile b/lib/reltool/doc/src/Makefile
index 8daafb7a2b..dce8059616 100644
--- a/lib/reltool/doc/src/Makefile
+++ b/lib/reltool/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2009-2016. All Rights Reserved.
+# Copyright Ericsson AB 2009-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml
index 52419259c6..e201ad4e23 100644
--- a/lib/reltool/doc/src/notes.xml
+++ b/lib/reltool/doc/src/notes.xml
@@ -38,7 +38,22 @@
thus constitutes one section in this document. The title of each
section is the version number of Reltool.</p>
- <section><title>Reltool 0.7.6</title>
+ <section><title>Reltool 0.7.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Reltool 0.7.6</title>
<section><title>Improvements and New Features</title>
<list>
diff --git a/lib/reltool/doc/src/reltool.xml b/lib/reltool/doc/src/reltool.xml
index 5bfbee966b..874cda8369 100644
--- a/lib/reltool/doc/src/reltool.xml
+++ b/lib/reltool/doc/src/reltool.xml
@@ -5,7 +5,7 @@
<header>
<copyright>
<year>2009</year>
- <year>2016</year>
+ <year>2018</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
@@ -806,7 +806,7 @@ target_spec() = [target_spec()]
<name>stop(Pid) -> ok | {error, Reason}</name>
<fsummary>Stop a server or window process</fsummary>
<type>
- <v>Pid = server_pid() | window_pid()()</v>
+ <v>Pid = server_pid() | window_pid()</v>
<v>Reason = reason()</v>
</type>
<desc><p>Stop a server or window process</p></desc>
diff --git a/lib/reltool/doc/src/reltool_examples.xml b/lib/reltool/doc/src/reltool_examples.xml
index 2a103119e6..f9a6fcf342 100644
--- a/lib/reltool/doc/src/reltool_examples.xml
+++ b/lib/reltool/doc/src/reltool_examples.xml
@@ -160,7 +160,7 @@ Eshell V9.0 (abort with ^G)
{mod,erts_internal,[]},
{mod,erts_literal_area_collector,[]},
{mod,init,[]},
- {mod,otp_ring0,...},
+ {mod,erl_init,...},
{mod,...},
{...}|...]}]},
{app,compiler,
@@ -331,7 +331,7 @@ Eshell V10.0 (abort with ^G)
{ok,{script,{"NAME","VSN"},
[{preLoaded,[erl_prim_loader,erl_tracer,erlang,
erts_code_purger,erts_dirty_process_signal_handler,
- erts_internal,erts_literal_area_collector,init,otp_ring0,
+ erts_internal,erts_literal_area_collector,init,erl_init,
prim_eval,prim_file,prim_inet,prim_zip,zlib]},
{progress,preloaded},
{path,["$ROOT/lib/kernel-5.2/ebin",
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index af71b0cf2a..47aba77835 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -526,7 +526,7 @@ analyse(#state{sys=Sys} = S, Apps, Status) ->
%% is included in a release (rel spec - see apps_in_rels above).
%% Then initiate the same for each module, and check that there
%% are no duplicated module names (in different applications)
- %% where we can not decide which one to use.
+ %% where we cannot decide which one to use.
%% Write all #app to app_tab and all #mod to mod_tab.
Status2 = apps_init_is_included(S, Apps, RelApps, Status),
diff --git a/lib/reltool/test/reltool_server_SUITE.erl b/lib/reltool/test/reltool_server_SUITE.erl
index 4e1937d479..fc976bfb94 100644
--- a/lib/reltool/test/reltool_server_SUITE.erl
+++ b/lib/reltool/test/reltool_server_SUITE.erl
@@ -1038,7 +1038,7 @@ create_standalone_app(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Generate standalone system with inlined archived application
-%% Check that the inlined app can not be explicitly configured
+%% Check that the inlined app cannot be explicitly configured
create_standalone_app_clash(Config) ->
%% Create archive
@@ -1658,7 +1658,7 @@ set_apps_inlined(Config) ->
?m(true, Someapp1#app.is_included),
?m(true, Someapp1#app.is_pre_included),
- %% Check that inlined app can not be configured
+ %% Check that inlined app cannot be configured
Someapp2 = Someapp1#app{incl_cond=exclude},
?msym({error,
"Application someapp is inlined in '*escript* someapp'. "
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index c698790ede..6bfc8c60ea 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.7.6
+RELTOOL_VSN = 0.7.7
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 4530a83aee..75b3a98d56 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -36,7 +36,7 @@ CC = $(DED_CC)
CFLAGS = $(DED_CFLAGS) -I./
LD = $(DED_LD)
SHELL = /bin/sh
-LIBS = $(DED_LIBS)
+LIBS = $(DED_LIBS) @LIBS@
LDFLAGS += $(DED_LDFLAGS)
TRACE_LIBNAME = dyntrace trace_file_drv trace_ip_drv
@@ -58,7 +58,7 @@ TYPE_FLAGS = $(CFLAGS)
endif
endif
-ALL_CFLAGS = @DEFS@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \
+ALL_CFLAGS = @DEFS@ @ERTS_CONFIG_H_IDIR@ $(TYPE_FLAGS) $(TRACE_DRV_INCLUDES) \
-I$(OBJDIR) -I$(ERL_TOP)/erts/emulator/$(TARGET)
ROOTDIR = $(ERL_TOP)/lib
@@ -75,7 +75,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/runtime_tools-$(VSN)
# Misc Macros
# ----------------------------------------------------
-TRACE_LIBS = $(foreach LIB, $(TRACE_LIBNAME), $(LIBDIR)/$(LIB)$(TYPEMARKER).@DED_EXT@)
+TRACE_LIBS = $(foreach LIB, $(TRACE_LIBNAME), $(LIBDIR)/$(LIB)$(TYPEMARKER).$(DED_EXT))
# ----------------------------------------------------
# Targets
@@ -94,7 +94,7 @@ $(LIBDIR):
$(OBJDIR)/%$(TYPEMARKER).o: %.c dyntrace_lttng.h
$(V_CC) -c -o $@ $(ALL_CFLAGS) $<
-$(LIBDIR)/%$(TYPEMARKER).@DED_EXT@: $(OBJDIR)/%$(TYPEMARKER).o
+$(LIBDIR)/%$(TYPEMARKER).$(DED_EXT): $(OBJDIR)/%$(TYPEMARKER).o
$(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index 3262cafefc..ae60b610ed 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -113,7 +113,7 @@
<p>The imported variables will be replaced by match_spec
<c>const</c> expressions, which is consistent with the
static scoping for Erlang <c>fun()</c>s. Local or global
- function calls can not be in the guard or body of the fun
+ function calls cannot be in the guard or body of the fun
however. Calls to builtin match_spec functions of course is
allowed:</p>
<pre>
@@ -756,7 +756,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<c>cant_add_local_node</c> is returned.
</p>
<p>If a trace port (see <seealso marker="#trace_port-2"><c>trace_port/2</c></seealso>) is
- running on the local node, remote nodes can not be traced with
+ running on the local node, remote nodes cannot be traced with
a tracer process. The error reason
<c>cant_trace_remote_pid_to_local_port</c> is returned. A
trace port can however be started on the remote node with the
diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml
index 5692df2ab4..810bb8207c 100644
--- a/lib/runtime_tools/doc/src/notes.xml
+++ b/lib/runtime_tools/doc/src/notes.xml
@@ -32,6 +32,23 @@
<p>This document describes the changes made to the Runtime_Tools
application.</p>
+<section><title>Runtime_Tools 1.13.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Optimize <c>observer</c> by using new
+ <c>system_info(ets_count)</c> instead of more expensive
+ <c>length(ets:all())</c>.</p>
+ <p>
+ Own Id: OTP-15163 Aux Id: PR-1844 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Runtime_Tools 1.13</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
index a0e3806981..a9399a5d53 100644
--- a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
+++ b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
@@ -6829,7 +6829,7 @@
{native,false},
{compiler,"4.9.1"},
{md5,"55bb9fddcdf820938be2efee15eccd82"}]},
- {otp_ring0,
+ {erl_init,
[{loaded,true},
{native,false},
{compiler,"4.9.1"},
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index 0a4ad61537..aa3d702997 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.13
+RUNTIME_TOOLS_VSN = 1.13.1
diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml
index 3dda5b06e8..fce032136d 100644
--- a/lib/sasl/doc/src/notes.xml
+++ b/lib/sasl/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the SASL application.</p>
+<section><title>SASL 3.2.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SASL 3.2</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/sasl/src/rb.erl b/lib/sasl/src/rb.erl
index 28829132a1..bef4268d3a 100644
--- a/lib/sasl/src/rb.erl
+++ b/lib/sasl/src/rb.erl
@@ -890,7 +890,7 @@ read_rep(Fd, FilePosition, Device, Abort, Log) ->
handle_bad_form(Date, Msg, Device, Abort, Log) ->
io:format("rb: ERROR! A report on bad form was encountered. " ++
- "It can not be printed to the log.~n~n"),
+ "It cannot be printed to the log.~n~n"),
io:format("Details:~n~p ~tp~n~n", [Date,Msg]),
case {Abort,Device,open_log_file(Log)} of
{true,standard_io,standard_io} ->
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index 7570b74c1a..48feac1a21 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -1120,7 +1120,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[FC]} ->
FC;
{error,Error1} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,FromFile,Error1]),
[]
end,
@@ -1130,7 +1130,7 @@ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
{ok,[ToConfig]} ->
[lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]];
{error,Error2} ->
- io:format("Warning: ~w can not read ~tp: ~tp~n",
+ io:format("Warning: ~w cannot read ~tp: ~tp~n",
[?MODULE,ToFile,Error2]),
[false,false,false]
end,
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index ca97515299..bf18691687 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -147,7 +147,7 @@ split_instructions([], Before) ->
%% If PrePurgeMethod == soft_purge, the function will succeed
%% only if there is no process running old code of any of the
%% modules. Else it will throw {error,Mod}, where Mod is the
-%% first module found that can not be soft_purged.
+%% first module found that cannot be soft_purged.
%%
%% If PrePurgeMethod == brutal_purge, the function will
%% always succeed and return a list of all modules that are
diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src
index 83ee328af2..d37c5b3d95 100644
--- a/lib/sasl/src/sasl.appup.src
+++ b/lib/sasl/src/sasl.appup.src
@@ -19,10 +19,10 @@
{"%VSN%",
%% Up from - max one major revision back
[{<<"3\\.0\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0
- {<<"3\\.1(\\.[0-2]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"3\\.1(\\.[3-9]+)*">>,[restart_new_emulator]}], % OTP-21
+ {<<"3\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
+ {<<"3\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-21.*
%% Down to - max one major revision back
[{<<"3\\.0\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.*
- {<<"3\\.1(\\.[0-2]+)*">>,[restart_new_emulator]}, % OTP-20.1+
- {<<"3\\.1(\\.[3-9]+)*">>,[restart_new_emulator]}] % OTP-21
+ {<<"3\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+
+ {<<"3\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21.*
}.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 6916107623..a0331fafd1 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -1562,10 +1562,10 @@ mandatory_modules() ->
preloaded() ->
%% Sorted
- [erl_prim_loader,erl_tracer,erlang,
+ [erl_init,erl_prim_loader,erl_tracer,erlang,
erts_code_purger,erts_dirty_process_signal_handler,
erts_internal,erts_literal_area_collector,
- init,otp_ring0,prim_buffer,prim_eval,prim_file,
+ init,prim_buffer,prim_eval,prim_file,
prim_inet,prim_zip,zlib].
%%______________________________________________________________________
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
index e38d0cfa7b..5429008a5f 100644
--- a/lib/sasl/test/installer.erl
+++ b/lib/sasl/test/installer.erl
@@ -905,7 +905,7 @@ start_client(TestNode,Client,Sname) ->
wait_started(TestNode,Node)
after 30000 ->
?print([{start_client,failed,Node},net_adm:ping(Node)]),
- ?fail({"can not start", Node})
+ ?fail({"cannot start", Node})
end.
start_client_unix(TestNode,Sname,Node) ->
diff --git a/lib/sasl/test/rb_SUITE.erl b/lib/sasl/test/rb_SUITE.erl
index 2b6e452d14..e5ca1775d5 100644
--- a/lib/sasl/test/rb_SUITE.erl
+++ b/lib/sasl/test/rb_SUITE.erl
@@ -423,7 +423,7 @@ start_stop_log(Config) ->
StdioResult2 = capture(fun() -> rb:log_list() end),
{ok,<<>>} = file:read_file(OutFile),
- %% Test that standard_io is used if log file can not be opened
+ %% Test that standard_io is used if log file cannot be opened
ok = rb:start_log(filename:join(nonexistingdir,"newfile.txt")),
StdioResult = capture(fun() -> rb:show(1) end),
{ok,<<>>} = file:read_file(OutFile),
diff --git a/lib/sasl/test/sasl_report_SUITE.erl b/lib/sasl/test/sasl_report_SUITE.erl
index a03932133e..e639b55cee 100644
--- a/lib/sasl/test/sasl_report_SUITE.erl
+++ b/lib/sasl/test/sasl_report_SUITE.erl
@@ -106,6 +106,9 @@ gen_server_crash(Config, Encoding) ->
ok = rpc:call(Node,?MODULE,crash_me,[]),
+ ok = rpc:call(Node,logger_std_h,filesync,[default]),
+ ok = rpc:call(Node,logger_std_h,filesync,[sasl]),
+
test_server:stop_node(Node),
ok = logger:remove_primary_filter(no_remote),
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index 1827974866..6c913850b9 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -1654,7 +1654,7 @@ abnormal_relup(Config) when is_list(Config) ->
ok.
-%% make_relup: Check relup can not be created is sasl is not in rel file.
+%% make_relup: Check relup cannot be created is sasl is not in rel file.
no_sasl_relup(Config) when is_list(Config) ->
{ok, OldDir} = file:get_cwd(),
{Dir1,Name1} = create_script(latest1_no_sasl,Config),
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index 0972ae20ba..94b7f9dc56 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 3.2
+SASL_VSN = 3.2.1
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index a6a9477b05..e7ab491eef 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index f64e0cca97..423d90fef6 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -34,7 +34,46 @@
</header>
- <section><title>SNMP 5.2.11</title>
+ <section><title>SNMP 5.2.12</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Conversion of (agent) Audit Trail Log (ATL) failed due
+ to invalid log entries.</p> <p>The conversion aborted
+ completely midway because the ATL contained invalid
+ entries. The conversion has been improved so that it now
+ firstly handles encountered errors and write an
+ informative message (into the converted stream) and
+ secondly keeps count of the number of successful or
+ failed entry conversions. See <seealso
+ marker="snmpa#log_to_txt">log_to_txt</seealso> for more
+ info. </p> <p>The reason the ATL contained invalid
+ entries have also been fixed. The reason was that for
+ some outgoing messages (not response):</p> <list
+ type="bulleted"> <item> <p>encrypted (v3 messages)</p>
+ <p>Was logged "as is" (encrypted) without the info to
+ decrypt, making conversion impossible (which was the
+ reason the log contained bad entries).</p> </item> <item>
+ <p>un-encrypted</p> <p>Was not logged at all. </p>
+ </item> </list>
+ <p>
+ Own Id: OTP-15287 Aux Id: ERIERL-206 </p>
+ </item>
+ <item>
+ <p>
+ [compiler] Spurious version message removed. The snmp mib
+ compiler printed an spurious version message if the
+ 'version' option was provided.</p>
+ <p>
+ Own Id: OTP-15290</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SNMP 5.2.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -48,7 +87,7 @@
</list>
</section>
-</section>
+ </section>
<section><title>SNMP 5.2.10</title>
diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml
index 801193675c..480ed2e825 100644
--- a/lib/snmp/doc/src/snmp.xml
+++ b/lib/snmp/doc/src/snmp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2016</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -341,10 +341,10 @@
</func>
<func>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -355,6 +355,9 @@
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
<v>Block = boolean()</v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
@@ -394,16 +397,25 @@
and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual
version of the protocol data unit. There is a new line
between <c>Vsn</c> and <c>PDU</c>.</p>
+
+ <p>If the entire log is successfully converted, the function
+ will return <c>ok</c>.
+ If one of more entries fail to convert, the function will instead
+ return <c>{ok, {NumOK, NumERR}}</c>, where the counters indicate
+ how many valid and erroneous entries where found.
+ If instead <c>{error, Reason}</c> is returned, the conversion
+ encountered a fatal error and where either never done of aborted
+ midway. </p>
<marker id="log_to_io"></marker>
</desc>
</func>
<func>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Block | Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop, Block) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -412,6 +424,9 @@
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = term()</v>
</type>
<desc>
diff --git a/lib/snmp/doc/src/snmp_impl_example_agent.xml b/lib/snmp/doc/src/snmp_impl_example_agent.xml
index e576fa51f3..7dda3dd5cd 100644
--- a/lib/snmp/doc/src/snmp_impl_example_agent.xml
+++ b/lib/snmp/doc/src/snmp_impl_example_agent.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
index d756ff7a65..b78f14da01 100644
--- a/lib/snmp/doc/src/snmpa.xml
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -559,13 +559,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -576,6 +576,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -597,14 +600,14 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -614,6 +617,9 @@ notification_delivery_info() = #snmpa_notification_delivery_info{}
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index 4818aeb697..be4cd58a1a 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1216,13 +1216,13 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<func>
<name>log_to_txt(LogDir)</name>
<name>log_to_txt(LogDir, Block | Mibs)</name>
- <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, Block | OutFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1233,6 +1233,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
@@ -1254,15 +1257,15 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
</func>
<func>
- <name>log_to_io(LogDir) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Block | Mibs) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Block | Mibs) -> ok | {ok, Cnt} | {error, Reason}</name>
<name>log_to_io(LogDir, Mibs) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
- <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, Block | LogName) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, Block | LogFile) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block | Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
+ <name>log_to_io(LogDir, Mibs, LogName, LogFile, Block, Start, Stop) -> ok | {ok, Cnt} | {error, Reason}</name>
<fsummary>Convert an Audit Trail Log to text format</fsummary>
<type>
<v>LogDir = string()</v>
@@ -1272,6 +1275,9 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
<v>LogName = string()</v>
<v>LogFile = string()</v>
<v>Start = Stop = null | calendar:datetime() | {local_time, calendar:datetime()} | {universal_time, calendar:datetime()} </v>
+ <v>Cnt = {NumOK, NumERR}</v>
+ <v>NumOK = non_neg_integer()</v>
+ <v>NumERR = pos_integer()</v>
<v>Reason = disk_log_open_error() | file_open_error() | term()</v>
<v>disk_log_open_error() = {LogName, term()}</v>
<v>file_open_error() = {OutFile, term()}</v>
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 2350194077..77893cbdc8 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -41,14 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
# Common macros
# ----------------------------------------------------
-# NOTE:
-# The OTP-REG mib actually belongs to another
-# application (otp_mibs), and is exported by this
-# app. But since that app is built later, we have
-# to built it here in order to be able to build
-# OTP-SNMPEA-MIB (that needs otpModules and
-# otpApplications).
-MIBS_A = \
+MIBS = \
RFC1213-MIB \
STANDARD-MIB \
SNMPv2-TM \
@@ -62,16 +55,10 @@ MIBS_A = \
SNMP-VIEW-BASED-ACM-MIB \
SNMP-USM-AES-MIB \
INET-ADDRESS-MIB \
- TRANSPORT-ADDRESS-MIB
-
-MIBS_B = OTP-SNMPEA-MIB
-
-BUILD_MIBS = \
- $(MIBS_A) \
+ TRANSPORT-ADDRESS-MIB \
OTP-REG \
- $(MIBS_B)
-
-MIBS = $(MIBS_A) $(MIBS_B)
+ OTP-TC \
+ OTP-SNMPEA-MIB
STD_v1_MIB_FILES = \
RFC1155-SMI.mib \
@@ -100,8 +87,8 @@ HRL_FILES = $(SNMP_HRL_TARGET_DIR)/SNMPv2-TC.hrl \
TARGET_FILES = \
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 \
- $(BUILD_MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
- $(HRL_TARGETS) \
+ $(MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
+ $(HRL_TARGETS) \
$(V1_MIB_FILES)
@@ -136,21 +123,18 @@ endif
# Targets
# ----------------------------------------------------
-OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
- else echo sasl; fi)
-
debug opt: $(TARGET_FILES)
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
$(gen_verbose)$(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
$(V_at)chmod 755 $@
-$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
- $(snmp_verbose)$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
-
# To support parallel make, we'll need explicit dependencies
# to ensure that an imported MIB has been compiled when it's needed.
+$(SNMP_BIN_TARGET_DIR)/OTP-TC.bin: \
+ $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin
+
$(SNMP_BIN_TARGET_DIR)/STANDARD-MIB.bin: \
$(SNMP_BIN_TARGET_DIR)/RFC1213-MIB.bin
@@ -208,8 +192,6 @@ info:
@echo ""
@echo "TARGET_FILES = $(TARGET_FILES)"
@echo ""
- @echo "OTP_MIBDIR = $(OTP_MIBDIR)"
- @echo ""
@echo "SNMP_VSN = $(SNMP_VSN)"
@echo "VSN = $(VSN)"
@echo "RELSYSDIR = "$(RELSYSDIR)""
diff --git a/lib/otp_mibs/mibs/OTP-REG.mib b/lib/snmp/mibs/OTP-REG.mib
index bf1585061c..bf1585061c 100644
--- a/lib/otp_mibs/mibs/OTP-REG.mib
+++ b/lib/snmp/mibs/OTP-REG.mib
diff --git a/lib/otp_mibs/mibs/OTP-TC.mib b/lib/snmp/mibs/OTP-TC.mib
index efe5451f0c..efe5451f0c 100644
--- a/lib/otp_mibs/mibs/OTP-TC.mib
+++ b/lib/snmp/mibs/OTP-TC.mib
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
index ecf9498ca9..afed4482d2 100644
--- a/lib/snmp/src/agent/snmpa_net_if.erl
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -137,11 +137,10 @@ init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
proc_lib:init_ack({ok, self()}),
try loop(State)
catch
- C:E when C =/= exit, E =/= shutdown ->
+ C:E:S when C =/= exit, E =/= shutdown ->
Fmt =
"loop/1 EXCEPTION ~w:~w~n"
" ~p",
- S = erlang:get_stacktrace(),
case C of
exit ->
%% Externally killed, root cause is elsewhere
@@ -647,10 +646,10 @@ maybe_handle_recv(
case
try FilterMod:accept_recv(From_1, From_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv(~p, ~p) crashed: ~w:~w~n ~p",
- [From_1,From_2,Class,Exception,erlang:get_stacktrace()]),
+ [From_1, From_2, Class, Exception, StackTrace]),
true
end
of
@@ -753,12 +752,11 @@ maybe_handle_recv_pdu(
case
try FilterMod:accept_recv_pdu(From_1, From_2, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_recv_pdu(~p, ~p, ~p) crashed: ~w:~w~n"
" ~p",
- [From_1,From_2,Type,Class,Exception,
- erlang:get_stacktrace()]),
+ [From_1, From_2, Type, Class, Exception, StackTrace]),
true
end
of
@@ -834,11 +832,10 @@ maybe_handle_reply_pdu(
try
FilterMod:accept_send_pdu(Addresses, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [Addresses, Type, Class, Exception,
- erlang:get_stacktrace()]),
+ [Addresses, Type, Class, Exception, StackTrace]),
true
end
of
@@ -872,7 +869,7 @@ handle_reply_pdu(
ACMData, LogF)) of
{ok, Packet} ->
?vinfo("time in agent: ~w mysec", [time_in_agent()]),
- try maybe_udp_send(S, Transport, To, Packet)
+ try maybe_udp_send_wo_log(S, Transport, To, Packet)
catch
{Reason, Sz} ->
error_msg("Cannot send message "
@@ -917,11 +914,10 @@ maybe_handle_send_pdu(
case
try FilterMod:accept_send_pdu(AddressesToFilter, Type)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send_pdu(~p, ~p) crashed: ~w:~w~n ~p",
- [AddressesToFilter,Type,
- Class,Exception,erlang:get_stacktrace()]),
+ [AddressesToFilter, Type, Class, Exception, StackTrace]),
true
end
of
@@ -1049,46 +1045,36 @@ do_handle_send_pdu(S, Type, Pdu, Addresses) ->
[Sz, Reason, Pdu])
end.
-do_handle_send_pdu1(
- #state{transports = Transports} = S,
- Type, Addresses) ->
+do_handle_send_pdu1(S, Type, Addresses) ->
lists:foreach(
- fun ({Domain, Address, Packet}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet)
- end;
- ({Domain, Address, {Packet, LogData}}) when is_binary(Packet) ->
- ?vdebug(
- "[~w] sending encrypted packet:~n"
- " size: ~p~n"
- " to: ~p", [Domain, sz(Packet), Address]),
- To = {Domain, Address},
- case select_transport_from_domain(Domain, Transports) of
- false ->
- error_msg(
- "Can not find transport~n"
- " size: ~p~n"
- " to: ~s",
- [sz(Packet), format_address(To)]);
- Transport ->
- maybe_udp_send(S, Transport, To, Packet, Type, LogData)
- end
+ fun ({Domain, Address, Pkg}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, Pkg, "");
+ ({Domain, Address, {Pkg, LogPkg}}) when is_binary(Pkg) ->
+ do_handle_send_pdu2(S, Type, Domain, Address,
+ Pkg, LogPkg, " encrypted")
end,
Addresses).
-maybe_udp_send(
+do_handle_send_pdu2(#state{transports = Transports} = S,
+ Type, Domain, Address, Pkg, LogPkg, EncrStr) ->
+ ?vdebug("[~w] sending~s packet:"
+ "~n size: ~p"
+ "~n to: ~p", [Domain, EncrStr, sz(Pkg), Address]),
+ To = {Domain, Address},
+ case select_transport_from_domain(Domain, Transports) of
+ false ->
+ error_msg("Can not find transport: "
+ "~n size: ~p"
+ "~n to: ~s",
+ [sz(Pkg), format_address(To)]);
+ Transport ->
+ maybe_udp_send_w_log(S, Transport, To, Pkg, LogPkg, Type)
+ end.
+
+
+%% This function is used when logging has already been done!
+maybe_udp_send_wo_log(
#state{filter = FilterMod, transports = Transports},
#transport{socket = Socket},
To, Packet) ->
@@ -1096,10 +1082,10 @@ maybe_udp_send(
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed: ~w:~w~n ~p",
- [To_1,To_2,Class,Exception,erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1118,18 +1104,18 @@ maybe_udp_send(
udp_send(Socket, To, Packet)
end.
-maybe_udp_send(
+maybe_udp_send_w_log(
#state{log = Log, filter = FilterMod, transports = Transports},
#transport{socket = Socket},
- To, Packet, Type, _LogData) ->
+ To, Pkg, LogPkg, Type) ->
{To_1, To_2} = fix_filter_address(Transports, To),
case
try FilterMod:accept_send(To_1, To_2)
catch
- Class:Exception ->
+ Class:Exception:StackTrace ->
error_msg(
"FilterMod:accept_send(~p, ~p) crashed for: ~w:~w~n ~p",
- [To_1, To_2, Class, Exception, erlang:get_stacktrace()]),
+ [To_1, To_2, Class, Exception, StackTrace]),
true
end
of
@@ -1143,10 +1129,10 @@ maybe_udp_send(
_ ->
error_msg(
"FilterMod:accept_send(~p, ~p) returned: ~p",
- [To_1,To_2,Other])
+ [To_1, To_2, Other])
end,
- log(Log, Type, Packet, To),
- udp_send(Socket, To, Packet)
+ log(Log, Type, LogPkg, To),
+ udp_send(Socket, To, Pkg)
end.
udp_send(Socket, To, B) ->
@@ -1168,11 +1154,10 @@ udp_send(Socket, To, B) ->
ok ->
ok
catch
- error:ExitReason ->
+ error:ExitReason:StackTrace ->
error_msg("[exit] cannot send message "
"(destination: ~p:~p, size: ~p, reason: ~p, at: ~p)",
- [IpAddr, IpPort, sz(B), ExitReason,
- erlang:get_stacktrace()])
+ [IpAddr, IpPort, sz(B), ExitReason, StackTrace])
end.
sz(L) when is_list(L) -> length(L);
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 57507a36e8..97b8ddf7c4 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -46,9 +46,9 @@
%%* 6) IF value is outside the acceptable range THEN wrongValue.
%% 7) IF variable does not exist and could not ever be created
%% THEN noCreation.
-%% 8) IF variable can not be created now THEN inconsistentName.
-%% 9) IF value can not be set now THEN inconsistentValue.
-%%* 9) IF instances of the variable can not be modified THEN notWritable.
+%% 8) IF variable cannot be created now THEN inconsistentName.
+%% 9) IF value cannot be set now THEN inconsistentValue.
+%%* 9) IF instances of the variable cannot be modified THEN notWritable.
%% 10) IF an unavailable resource is needed THEN resourceUnavailable.
%% 11) IF any other error THEN genErr.
%% 12) Otherwise ok!
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
index e75016f7ec..293d1f3ccf 100644
--- a/lib/snmp/src/agent/snmpa_trap.erl
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -830,11 +830,11 @@ do_send_v1_trap(Enter, Spec, V1Res, NVbs, ExtraInfo, NetIf, SysUpTime) ->
case lists:keyfind(transportDomainUdpIpv4, 1, Transports) of
false ->
?vtrace(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]),
user_err(
- "snmpa_trap: can not send v1 trap "
+ "snmpa_trap: cannot send v1 trap "
"without IPv4 domain: ~p",
[Transports]);
DomainAddr ->
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
index 7f627d66d9..c810bfcd41 100644
--- a/lib/snmp/src/compile/snmpc.erl
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -169,11 +169,7 @@ get_version() ->
MI = ?MODULE:module_info(),
Attr = get_info(attributes, MI),
Vsn = get_info(app_vsn, Attr),
- Comp = get_info(compile, MI),
- Time = get_info(time, Comp),
- {Year, Month, Day, Hour, Min, Sec} = Time,
- io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
- [Vsn, Year, Month, Day, Hour, Min, Sec]).
+ Vsn.
maybe_display_options(Opts) ->
case lists:member(options, Opts) of
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
index 767d801eee..5713c14912 100644
--- a/lib/snmp/src/misc/snmp_log.erl
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -649,13 +649,14 @@ do_log_to_file(Log, TextFile, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format(Fd, "~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format(Fd, "~s", [S]),
+ Tag;
+ Ignore ->
+ Ignore
end
end,
- Res = (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
file:close(Fd),
Res;
@@ -668,39 +669,63 @@ do_log_to_io(Log, Mibs, Start, Stop) ->
MiniMib = snmp_mini_mib:create(Mibs),
Write = fun(X) ->
case format_msg(X, MiniMib, Start, Stop) of
- {ok, S} ->
- io:format("~s", [S]);
- _ ->
- ok
+ {Tag, S} when (Tag =:= ok) orelse (Tag =:= error) ->
+ io:format("~s", [S]),
+ Tag;
+ X ->
+ X
end
end,
- (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ Res = (catch loop(Log, Write)),
snmp_mini_mib:delete(MiniMib),
- ok.
+ Res.
+
+loop(Log, Write) ->
+ loop(disk_log:chunk(Log, start), Log, Write, 0, 0).
-loop(eof, _Log, _Write) ->
+loop(eof, _Log, _Write, _NumOK, 0 = _NumERR) ->
ok;
-loop({error, _} = Error, _Log, _Write) ->
+loop(eof, _Log, _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop({error, _} = Error, _Log, _Write, _NumOK, _NumERR) ->
Error;
-loop({Cont, Terms}, Log, Write) ->
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
+loop({Cont, Terms}, Log, Write, NumOK, NumERR) ->
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
end;
-loop({Cont, Terms, BadBytes}, Log, Write) ->
+loop({Cont, Terms, BadBytes}, Log, Write, NumOK, NumERR) ->
error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n",
[BadBytes, Log]),
- case (catch lists:foreach(Write, Terms)) of
- {'EXIT', Reason} ->
- {error, Reason};
- _ ->
- loop(disk_log:chunk(Log, Cont), Log, Write)
- end;
-loop(Error, _Log, _Write) ->
- Error.
+ try loop_terms(Terms, Write) of
+ {ok, {AddedOK, AddedERR}} ->
+ loop(disk_log:chunk(Log, Cont), Log, Write,
+ NumOK+AddedOK, NumERR+AddedERR)
+ catch
+ C:E:S ->
+ {error, {C, E, S}}
+ end.
+
+
+loop_terms(Terms, Write) ->
+ loop_terms(Terms, Write, 0, 0).
+
+loop_terms([], _Write, NumOK, NumERR) ->
+ {ok, {NumOK, NumERR}};
+loop_terms([Term|Terms], Write, NumOK, NumERR) ->
+ case Write(Term) of
+ ok ->
+ loop_terms(Terms, Write, NumOK+1, NumERR);
+ error ->
+ loop_terms(Terms, Write, NumOK, NumERR+1);
+ _ ->
+ loop_terms(Terms, Write, NumOK, NumERR)
+ end.
format_msg(Entry, Mib, Start, Stop) ->
@@ -733,88 +758,149 @@ do_format_msg({Timestamp, SeqNo, Packet, Ip, Port}, Mib) ->
%% This is crap...
do_format_msg(_, _) ->
- format_tab("** unknown entry in log file\n\n", []).
+ {error, format_tab("** unknown entry in log file\n\n", [])}.
do_format_msg(TimeStamp, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), AddrStr, Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), "", Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab("** error in log file ~p\n\n", [Reason])
+ try f(ts2str(TimeStamp), "", Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, AddrStr, DecT, DecE)
+
end.
-
+
+sm2atom(?SEC_ANY) -> any;
+sm2atom(?SEC_V1) -> v1;
+sm2atom(?SEC_V2C) -> v2c;
+sm2atom(?SEC_USM) -> usm;
+sm2atom(_) -> unknown.
+
do_format_msg(TimeStamp, SeqNo, {V3Hdr, ScopedPdu}, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ try snmp_pdus:dec_scoped_pdu(ScopedPdu) of
ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
Msg = #message{version = 'version-3',
vsn_hdr = V3Hdr,
data = ScopedPDU},
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file at ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+ catch
+ FormatT:FormatE ->
+ format_error("format scoped pdu",
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode scoped pdu",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end;
do_format_msg(TimeStamp, SeqNo, Packet, AddrStr, Mib) ->
- case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ try snmp_pdus:dec_message(binary_to_list(Packet)) of
Msg when is_record(Msg, message) ->
- f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib);
- {'EXIT', Reason} ->
- format_tab(
- "** error in log file ~s from ~s ~p\n\n",
- [ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason])
+ try f(ts2str(TimeStamp), sn2str(SeqNo), Msg, AddrStr, Mib) of
+ {ok, _} = OK ->
+ OK
+
+ catch
+ FormatT:FormatE ->
+ %% Provide info about the message
+ Extra =
+ case Msg#message.version of
+ 'version-3' ->
+ #v3_hdr{msgID = ID,
+ msgFlags = Flags,
+ msgSecurityModel = SecModel} =
+ Msg#message.vsn_hdr,
+ SecLevel = snmp_misc:get_sec_level(Flags),
+ f("msg-id: ~w, sec-level: ~w, sec-model: ~w",
+ [ID, SecLevel, sm2atom(SecModel)]);
+ _ -> %% Community
+ f("community: ~s", [Msg#message.vsn_hdr])
+ end,
+ format_error(f("format ~p message; ~s",
+ [Msg#message.version, Extra]),
+ TimeStamp, SeqNo, AddrStr, FormatT, FormatE)
+ end
+ catch
+ DecT:DecE ->
+ format_error("decode message",
+ TimeStamp, SeqNo, AddrStr, DecT, DecE)
end.
-
-
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}},
-%% Mib, Start, Stop) ->
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop);
-%% format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
-%% Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
-%% ScopedPDU when record(ScopedPDU, scopedPdu) ->
-%% Msg = #message{version = 'version-3',
-%% vsn_hdr = V3Hdr,
-%% data = ScopedPDU},
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
-%% [ts2str(TimeStamp), ip(Addr), Port, Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) ->
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop);
-%% format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) ->
-%% case timestamp_filter(TimeStamp, Start, Stop) of
-%% true ->
-%% case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
-%% Msg when record(Msg, message) ->
-%% f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
-%% {'EXIT', Reason} ->
-%% format_tab("** error in log file ~p\n\n", [Reason])
-%% end;
-%% false ->
-%% ignore
-%% end;
-%% format_msg(_, _Mib, _Start, _Stop) ->
-%% format_tab("** unknown entry in log file\n\n", []).
+
+
+format_error(WhatStr, TimeStamp, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s from ~s: "
+ "~n ~w: ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), AddrStr, T, E]),
+ {error, Str}.
+
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, throw, {error, Reason}) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, Reason]),
+ {error, Str};
+format_error(WhatStr, TimeStamp, SeqNo, AddrStr, T, E) ->
+ {ok, Str} =
+ format_tab(
+ "** error (~s) in log file at ~s~s from ~s: "
+ "~n ~w, ~p\n\n",
+ [WhatStr, ts2str(TimeStamp), sn2str(SeqNo), AddrStr, T, E]),
+ {error, Str}.
+
f(TimeStamp, SeqNo,
#message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
@@ -838,51 +924,21 @@ f(TimeStamp, SeqNo,
end,
format_tab(
"~w ~s - ~s [~s]~s ~w\n~s",
- [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f(TimeStamp, SeqNo,
-%% #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
-%% Addr, Port, Mib) ->
-%% Str = format_pdu(Data, Mib),
-%% HdrStr = format_header(Vsn, VsnHdr),
-%% case get_type(Data) of
-%% trappdu ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'snmpv2-trap' ->
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'inform-request' ->
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% 'get-response' ->
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% report ->
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port);
-%% _ ->
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port)
-%% end.
-
-%% f_request(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("request ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_response(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("response ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
-
-%% f_report(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("report ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+ [Class, AddrStr, HdrStr, TimeStamp, SeqNo, Vsn, Str]);
+f(TimeStamp, SeqNo, Msg, AddrStr, _Mib) ->
+ io:format("<ERROR> Unexpected data: "
+ "~n TimeStamp: ~s~s"
+ "~n Msg: ~p"
+ "~n AddrStr: ~p"
+ "~n", [TimeStamp, SeqNo, Msg, AddrStr]),
+ throw({error, 'invalid-message'}).
-%% f_trap(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("trap ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
-%% f_inform(TimeStamp, SeqNo, Vsn, HdrStr, Str, Addr, Port) ->
-%% format_tab("inform ~s:~w - ~s [~s]~s ~w\n~s",
-%% [ip(Addr), Port, HdrStr, TimeStamp, SeqNo, Vsn, Str]).
ipPort2Str(Ip, Port) ->
snmp_conf:mk_addr_string({Ip, Port}).
- %% io_lib:format("~s:~w", [ip(Ip), Port]).
%% Convert a timestamp 2-tupple to a printable string
%%
@@ -973,7 +1029,13 @@ format_pdu(#scopedPdu{contextName = Context, data = Pdu}, Mib) ->
io_lib:format("Context: \"~s\"\n~s",
[Context, snmp_misc:format_pdu(Pdu, Mib)]);
format_pdu(Pdu, Mib) ->
- snmp_misc:format_pdu(Pdu, Mib).
+ try snmp_misc:format_pdu(Pdu, Mib) of
+ Str ->
+ Str
+ catch
+ _:_ ->
+ throw({error, 'invalid-pdu'})
+ end.
get_type(#scopedPdu{data = Pdu}) ->
get_type(Pdu);
@@ -983,12 +1045,6 @@ get_type(#pdu{type = Type}) ->
Type.
-%% ip(Domain, Addr) ->
-%% snmp_conf:mk_addr_string(Domain, Addr).
-%% ip({A,B,C,D}) ->
-%% io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
-
-
%% -------------------------------------------------------------------
%% Various utility functions
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 2ed2c4580c..f9c18af6ea 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
index 0a7b729d1f..2e48d5134d 100644
--- a/lib/snmp/test/snmp_compiler_test.erl
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -234,14 +234,14 @@ agent_capabilities(Config) when is_list(Config) ->
AcMib = join(Dir,"AC-TEST-MIB.mib"),
?line {ok, MibFile1} = snmpc:compile(AcMib, [options,
version,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib1} = snmp_misc:read_mib(MibFile1),
?line {ok, MibFile2} = snmpc:compile(AcMib, [options,
version,
agent_capabilities,
- {i, [SnmpMibsDir, OtpMibsMibsDir]},
+ {i, [SnmpMibsDir]},
{outdir, Dir},
{verbosity, trace}]),
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
@@ -290,7 +290,7 @@ module_compliance(Config) when is_list(Config) ->
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
MEDiff = Mib2#mib.mes -- Mib1#mib.mes,
%% This is a rather pathetic test, but it is somthing...
- io:format("agent_capabilities -> "
+ io:format("module_compliance -> "
"~n MEDiff: ~p"
"~n Mib1: ~p"
"~n Mib2: ~p"
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index 6a3466b6e4..b83c7461d1 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/snmp/test/test-mibs/ALARM-MIB.mib b/lib/snmp/test/test-mibs/ALARM-MIB.mib
index 18e43d4b4b..10d2adbff9 100644
--- a/lib/snmp/test/test-mibs/ALARM-MIB.mib
+++ b/lib/snmp/test/test-mibs/ALARM-MIB.mib
@@ -330,7 +330,7 @@ alarmModelRowStatus OBJECT-TYPE
cannot be used as an alarm suppression mechanism. Entries
that are notInService will disappear as described in RFC2579.
- This row can not be modified while it is being
+ This row cannot be modified while it is being
referenced by a value of alarmActiveModelPointer. In these
cases, an error of `inconsistentValue' will be returned to
the manager.
diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
index fd6a728ab5..1d75c4bbd8 100644
--- a/lib/snmp/test/test-mibs/SNMPv2-TC.mib
+++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
@@ -454,7 +454,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
@@ -576,7 +576,7 @@ value | | see 1| ->C| ->D
associated with this column or that there is no
conceptual row for which this column would be
accessible in the MIB view used by the retrieval. As
- such, the management station can not issue any
+ such, the management station cannot issue any
management protocol set operations to create an
instance of this column.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 96123f02f5..f305497cd3 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2017. All Rights Reserved.
+# Copyright Ericsson AB 1997-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 5.2.11
+SNMP_VSN = 5.3
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index 77fa356092..4e32dd9976 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -45,6 +45,7 @@ XML_REF3_FILES = \
ssh_connection.xml \
ssh_server_channel.xml \
ssh_server_key_api.xml \
+ ssh_file.xml \
ssh_sftp.xml \
ssh_sftpd.xml \
@@ -56,8 +57,8 @@ XML_CHAPTER_FILES = \
notes.xml \
introduction.xml \
using_ssh.xml \
+ terminology.xml \
configure_algos.xml
-# ssh_protocol.xml \
BOOK_FILES = book.xml
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index 2478a8950b..c9809ce1e3 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,45 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.7.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Extended the undocumented <c>ssh_dbg</c> debug module
+ with an api for a circular trace buffer. This makes it
+ easy to record the last low-level events before an error
+ is detected. It is intended for solving difficult errors.</p>
+ <p>
+ Own Id: OTP-15020</p>
+ </item>
+ <item>
+ <p>
+ The key exchange methods
+ <c>'[email protected]'</c>,
+ <c>'curve25519-sha256'</c> and <c>'curve448-sha512'</c>
+ are implemented. The last two are defined in
+ https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves</p>
+ <p>
+ They all depends on that OpenSSL 1.1.1 or higher is used
+ as cryptolib.</p>
+ <p>
+ Own Id: OTP-15133 Aux Id: OTP-15240 </p>
+ </item>
+ <item>
+ <p>
+ The cipher '<c>[email protected]</c>' is now
+ supported if OpenSSL 1.1.1 or higher is used as
+ cryptolib.</p>
+ <p>
+ Own Id: OTP-15209 Aux Id: OTP-15164 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
@@ -2765,7 +2804,7 @@
</item>
<item>
<p>
- Fixed internal error on when client and server can not
+ Fixed internal error on when client and server cannot
agree o which authmethod to use.</p>
<p>
Own Id: OTP-10731 Aux Id: seq12237 </p>
diff --git a/lib/ssh/doc/src/ref_man.xml b/lib/ssh/doc/src/ref_man.xml
index df37b0244f..60572b985b 100644
--- a/lib/ssh/doc/src/ref_man.xml
+++ b/lib/ssh/doc/src/ref_man.xml
@@ -40,6 +40,7 @@
<xi:include href="ssh_connection.xml"/>
<xi:include href="ssh_client_key_api.xml"/>
<xi:include href="ssh_server_key_api.xml"/>
+ <xi:include href="ssh_file.xml"/>
<xi:include href="ssh_sftp.xml"/>
<xi:include href="ssh_sftpd.xml"/>
</application>
diff --git a/lib/ssh/doc/src/specs.xml b/lib/ssh/doc/src/specs.xml
index acdbe2ddfd..a6517f3660 100644
--- a/lib/ssh/doc/src/specs.xml
+++ b/lib/ssh/doc/src/specs.xml
@@ -6,6 +6,7 @@
<xi:include href="../specs/specs_ssh_connection.xml"/>
<xi:include href="../specs/specs_ssh_server_channel.xml"/>
<xi:include href="../specs/specs_ssh_server_key_api.xml"/>
+ <xi:include href="../specs/specs_ssh_file.xml"/>
<xi:include href="../specs/specs_ssh_sftp.xml"/>
<xi:include href="../specs/specs_ssh_sftpd.xml"/>
</specs>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index f238bf2ca8..93e52ce023 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -46,7 +46,7 @@
In that encrypted connection one or more channels could be opened with
<seealso marker="ssh_connection#session_channel/2">ssh_connection:session_channel/2,4</seealso>.
</p>
- <p>Each channel is an isolated "pipe" between a client-side process and a server-side process. Thoose process
+ <p>Each channel is an isolated "pipe" between a client-side process and a server-side process. Those process
pairs could handle for example file transfers (sftp) or remote command execution (shell, exec and/or cli).
If a custom shell is implemented, the user of the client could execute the special commands remotely. Note that
the user is not necessarily a human but probably a system interfacing the SSH app.
@@ -99,8 +99,8 @@
</p>
<p>The paths could easily be changed by options:
- <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso> and
- <seealso marker="#type-system_dir_daemon_option"><c>system_dir</c></seealso>.
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> and
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.
</p>
<p>A completly different storage could be interfaced by writing call-back modules
using the behaviours
@@ -123,12 +123,12 @@
<item><c>ssh_host_ecdsa_key</c> and <c>ssh_host_ecdsa_key.pub</c></item>
</list>
<p>The host keys directory could be changed with the option
- <seealso marker="#type-system_dir_daemon_option"><c>system_dir</c></seealso>.</p>
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.</p>
</item>
<item>Optional: one or more <i>User's public key</i> in case of <c>publickey</c> authorization.
Default is to store them concatenated in the file <c>.ssh/authorized_keys</c> in the user's home directory.
<p>The user keys directory could be changed with the option
- <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso>.</p>
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>.</p>
</item>
</list>
</section>
@@ -138,7 +138,7 @@
<p>The keys and some other data are by default stored in files in the directory <c>.ssh</c>
in the user's home directory.</p>
<p>The directory could be changed with the option
- <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso>.
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>.
</p>
<list>
<item>Optional: a list of <i>Host public key(s)</i> for previously connected hosts. This list
@@ -192,22 +192,13 @@
<p>If there is no public key of a specified type available, the corresponding entry is ignored.
Note that the available set is dependent on the underlying cryptolib and current user's public keys.
</p>
- <p>See also the option <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso>
+ <p>See also the option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
for specifying the path to the user's keys.
</p>
</desc>
</datatype>
<datatype>
- <name name="pubkey_passphrase_client_options"/>
- <desc>
- <p>If the user's DSA, RSA or ECDSA key is protected by a passphrase, it can be
- supplied with thoose options.
- </p>
- </desc>
- </datatype>
-
- <datatype>
<name name="host_accepting_client_options"/>
<name name="accept_hosts"/>
<name name="fp_digest_alg"/>
@@ -220,7 +211,7 @@
<p>This option guides the <c>connect</c> function on how to act when the connected server presents a Host
Key that the client has not seen before. The default is to ask the user with a question on stdio of whether to
accept or reject the new Host Key.
- See the option <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso>
+ See the option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
for specifying the path to the file <c>known_hosts</c> where previously accepted Host Keys are recorded.
See also the option
<seealso marker="#type-key_cb_common_option">key_cb</seealso>
@@ -276,7 +267,7 @@
accept question the next time the same host is connected. If the option
<seealso marker="#type-key_cb_common_option"><c>key_cb</c></seealso>
is not present, the key is saved in the file "known_hosts". See option
- <seealso marker="#type-user_dir_common_option"><c>user_dir</c></seealso> for
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> for
the location of that file.
</p>
<p>If <c>false</c>, the key is not saved and the key will still be unknown
@@ -478,18 +469,6 @@
<name name="pwdfun_4"/>
<desc>
<taglist>
- <tag><marker id="type-system_dir_daemon_option"/><c>system_dir</c></tag>
- <item>
- <p>Sets the system directory, containing the host key files
- that identify the host keys for <c>ssh</c>. Defaults to
- <c>/etc/ssh</c>.</p>
- <p>For security reasons, this directory is normally accessible only to the root user.</p>
- <p>See also the option
- <seealso marker="#type-key_cb_common_option">key_cb</seealso>
- for the general way to handle keys.
- </p>
- </item>
-
<tag><c>auth_method_kb_interactive_data</c></tag>
<item>
<p>Sets the text strings that the daemon sends to the client for presentation to the user when
@@ -502,7 +481,7 @@
</p>
</item>
- <tag><c>user_passwords</c></tag>
+ <tag><marker id="option-user_passwords"/><c>user_passwords</c></tag>
<item>
<p>Provides passwords for password authentication. The passwords are used when someone tries
to connect to the server and public key user-authentication fails. The option provides
@@ -510,7 +489,7 @@
</p>
</item>
- <tag><c>password</c></tag>
+ <tag><marker id="option-password"/><c>password</c></tag>
<item>
<p>Provides a global password that authenticates any user.</p>
<warning>
@@ -519,7 +498,9 @@
</warning>
</item>
- <tag><c>pwdfun</c> with <c>pwdfun_4()</c></tag>
+ <tag><marker id="option-pwdfun"/><c>pwdfun</c> with
+ <seealso marker="#type-pwdfun_4"><c>pwdfun_4()</c></seealso>
+ </tag>
<item>
<p>Provides a function for password validation. This could used for calling an external system or handeling
passwords stored as hash values.
@@ -546,7 +527,9 @@
can be used for this. The return value <c>disconnect</c> is useful for this.</p>
</item>
- <tag><c>pwdfun</c> with <c>pwdfun_2()</c></tag>
+ <tag><c>pwdfun</c> with
+ <seealso marker="#type-pwdfun_2"><c>pwdfun_2()</c></seealso>
+ </tag>
<item>
<p>Provides a function for password validation. This function is called with user and password
as strings, and returns:</p>
@@ -725,21 +708,6 @@
</datatype>
<datatype>
- <name name="user_dir_common_option"/>
- <desc>
- <p>Sets the user directory. That is, the directory containing <c>ssh</c> configuration
- files for the user, such as
- <c>known_hosts</c>, <c>id_rsa</c>, <c>id_dsa</c>>, <c>id_ecdsa</c> and <c>authorized_key</c>.
- Defaults to the directory normally referred to as <c>~/.ssh</c>.
- </p>
- <p>See also the option
- <seealso marker="#type-key_cb_common_option">key_cb</seealso>
- for the general way to handle keys.
- </p>
- </desc>
- </datatype>
-
- <datatype>
<name name="profile_common_option"/>
<desc>
<p>Used together with <c>ip-address</c> and <c>port</c> to
@@ -795,7 +763,8 @@
</p>
<p>The <c>Opts</c> defaults to <c>[]</c> when only the <c>Module</c> is specified.
</p>
- <p>The default value of this option is <c>{ssh_file, []}</c>.
+ <p>The default value of this option is <c>{ssh_file, []}</c>. See also the manpage of
+ <seealso marker="ssh:ssh_file">ssh_file</seealso>.
</p>
<p>A call to the call-back function <c>F</c> will be</p>
<code>
@@ -804,7 +773,10 @@
<p>where <c>...</c> are arguments to <c>F</c> as in
<seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and/or
<seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
- The <c>UserOptions</c> are the options given to <c>ssh:connect</c>, <c>ssh:shell</c> or <c>ssh:daemon</c>.
+ The <c>UserOptions</c> are the options given to
+ <seealso marker="ssh:ssh#connect-3">ssh:connect</seealso>,
+ <seealso marker="ssh:ssh#shell-1">ssh:shell</seealso> or
+ <seealso marker="ssh:ssh#daemon-2">ssh:daemon</seealso>.
</p>
</desc>
diff --git a/lib/ssh/doc/src/ssh_app.xml b/lib/ssh/doc/src/ssh_app.xml
index 9ec909d733..eb804e67dc 100644
--- a/lib/ssh/doc/src/ssh_app.xml
+++ b/lib/ssh/doc/src/ssh_app.xml
@@ -74,13 +74,18 @@
<c>id_ecdsa_key</c>,
<c>known_hosts</c>, and <c>authorized_keys</c> in ~/.ssh,
and for the host key files in <c>/etc/ssh</c>. These locations can be changed
- by the options <c>user_dir</c> and <c>system_dir</c>.
+ by the options
+ <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso> and
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>.
</p>
<p>Public key handling can also be customized through a callback module that
implements the behaviors
<seealso marker="ssh_client_key_api">ssh_client_key_api</seealso> and
<seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
</p>
+ <p>See also the default callback module documentation in
+ <seealso marker="ssh_file">ssh_file</seealso>.
+ </p>
</section>
<section>
@@ -151,6 +156,9 @@
<item>diffie-hellman-group16-sha512</item>
<item>diffie-hellman-group18-sha512</item>
<item>diffie-hellman-group14-sha256</item>
+ <item>curve25519-sha256</item>
+ <item>[email protected]</item>
+ <item>curve448-sha512</item>
<item>diffie-hellman-group14-sha1</item>
<item>diffie-hellman-group-exchange-sha1</item>
<item>(diffie-hellman-group1-sha1, retired: It can be enabled with the
@@ -186,6 +194,7 @@
<tag>Encryption algorithms (ciphers)</tag>
<item>
<list type="bulleted">
+ <item>[email protected]</item>
<item>[email protected]</item>
<item>aes256-ctr</item>
<item>aes192-ctr</item>
@@ -365,6 +374,10 @@
</list>
<p/>
</item>
+
+ <item>
+ <url href="https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves">Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448 (work in progress)</url>
+ </item>
</list>
diff --git a/lib/ssh/doc/src/ssh_file.xml b/lib/ssh/doc/src/ssh_file.xml
new file mode 100644
index 0000000000..ae6ba2e1d9
--- /dev/null
+++ b/lib/ssh/doc/src/ssh_file.xml
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2018</year><year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>ssh_file</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ </header>
+ <module>ssh_file</module>
+ <modulesummary>Default callback module for the client's and server's database operations in the ssh application</modulesummary>
+ <description>
+ <p>This module is the default callback handler for the client's and the server's user and host "database" operations.
+ All data, for instance key pairs, are stored in files in the normal file system. This page documents the files, where they
+ are stored and configuration options for this callback module.
+ </p>
+ <p>The intention is to be compatible with the
+ <url href="http://www.openssh.com">OpenSSH</url>
+ storage in files. Therefore it mimics directories and filenames of
+ <url href="http://www.openssh.com">OpenSSH</url>.
+ </p>
+
+ <p>Ssh_file implements the <seealso marker="ssh:ssh_server_key_api">ssh_server_key_api</seealso> and
+ the <seealso marker="ssh:ssh_client_key_api">ssh_client_key_api</seealso>.
+ This enables the user to make an own interface using for example a database handler.
+ </p>
+ <p>Such another callback module could be used by setting the option
+ <seealso marker="ssh:ssh#type-key_cb_common_option"><c>key_cb</c></seealso>
+ when starting a client or a server (with for example
+ <seealso marker="ssh:ssh#connect-3">ssh:connect</seealso>,
+ <seealso marker="ssh:ssh#daemon-2">ssh:daemon</seealso> of
+ <seealso marker="ssh:ssh#shell-1">ssh:shell</seealso>
+ ).
+ </p>
+
+ <note>
+ <p>The functions are <i>Callbacks</i> for the SSH app. They are not intended to be called from the user's code!
+ </p>
+ </note>
+ </description>
+
+ <section>
+ <title>Files, directories and who uses them</title>
+ <section>
+ <title>Daemons</title>
+ <p>Daemons uses all files stored in the <seealso marker="#SYSDIR">SYSDIR</seealso> directory.
+ </p>
+ <p>Optionaly, in case of <c>publickey</c> authorization, one or more of the remote user's public keys
+ in the <seealso marker="#USERDIR">USERDIR</seealso> directory are used.
+ See the files
+ <seealso marker="#USERDIR-authorized_keys"><c>USERDIR/authorized_keys</c></seealso> and
+ <seealso marker="#USERDIR-authorized_keys2"><c>USERDIR/authorized_keys2</c></seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Clients</title>
+ <p>Clients uses all files stored in the <seealso marker="#USERDIR">USERDIR</seealso> directory.
+ </p>
+ </section>
+
+ <section>
+ <title>Directory contents</title>
+ <taglist>
+ <tag><marker id="LOCALUSER"/>LOCALUSER</tag>
+ <item><p>The user name of the OS process running the Erlang virtual machine (emulator).</p>
+ </item>
+
+ <tag><marker id="SYSDIR"/>SYSDIR</tag>
+ <item><p>This is the directory holding the server's files:</p>
+ <list>
+ <item><marker id="SYSDIR-ssh_host_dsa_key"/><c>ssh_host_dsa_key</c> - private dss host key (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_rsa_key"/><c>ssh_host_rsa_key</c> - private rsa host key (optional)</item>
+ <item><marker id="SYSDIR-ssh_host_ecdsa_key"/><c>ssh_host_ecdsa_key</c> - private ecdsa host key (optional)</item>
+ </list>
+ <p>At least one host key must be defined. The default value of SYSDIR is <marker id="#/etc/ssh"/><c>/etc/ssh</c>.
+ </p>
+ <p>For security reasons, this directory is normally accessible only to the root user.
+ </p>
+ <p>To change the SYSDIR, see the <seealso marker="#type-system_dir_daemon_option">system_dir</seealso> option.
+ </p>
+ </item>
+
+ <tag><marker id="USERDIR"/>USERDIR</tag>
+ <item><p>This is the directory holding the files:</p>
+ <list>
+ <item><marker id="USERDIR-authorized_keys"/><c>authorized_keys</c>
+ and, as second alternative
+ <marker id="USERDIR-authorized_keys2"/><c>authorized_keys2</c> -
+ the user's public keys are stored concatenated in one of those files.
+ </item>
+ <item><marker id="USERDIR-known_hosts"/><c>known_hosts</c> - host keys from hosts visited
+ concatenated. The file is created and used by the client.</item>
+ <item><marker id="USERDIR-id_dsa"/><c>id_dsa</c> - private dss user key (optional)</item>
+ <item><marker id="USERDIR-id_rsa"/><c>id_rsa</c> - private rsa user key (optional)</item>
+ <item><marker id="USERDIR-id_ecdsa"/><c>id_ecdsa</c> - private ecdsa user key (optional)</item>
+ </list>
+ <p>The default value of USERDIR is <c>/home/</c><seealso marker="#LOCALUSER"><c>LOCALUSER</c></seealso><c>/.ssh</c>.
+ </p>
+ <p>To change the USERDIR, see the <seealso marker="#type-user_dir_common_option">user_dir</seealso> option
+ </p>
+ </item>
+ </taglist>
+ </section>
+ </section>
+
+ <datatypes>
+ <datatype_title>Options for the default ssh_file callback module</datatype_title>
+ <datatype>
+ <name name="user_dir_common_option"/>
+ <desc>
+ <p>Sets the <seealso marker="#USERDIR">user directory</seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="user_dir_fun_common_option"/>
+ <name name="user2dir"/>
+ <desc>
+ <p>Sets the <seealso marker="#USERDIR">user directory</seealso> dynamically
+ by evaluating the <c>user2dir</c> function.
+ </p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="system_dir_daemon_option"/>
+ <desc>
+ <p>Sets the <seealso marker="#SYSDIR">system directory</seealso>.</p>
+ </desc>
+ </datatype>
+
+ <datatype>
+ <name name="pubkey_passphrase_client_options"/>
+ <desc>
+ <p>If the user's DSA, RSA or ECDSA key is protected by a passphrase, it can be
+ supplied with thoose options.
+ </p>
+ </desc>
+ </datatype>
+
+ </datatypes>
+
+ <funcs>
+ <func>
+ <name>host_key(Algorithm, DaemonOptions) -> {ok, Key} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_server_key_api#Module:host_key-2">ssh_server_key_api, Module:host_key/2</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-system_dir_daemon_option">system_dir</seealso></item>
+ <!-- item>dsa_pass_phrase</item -->
+ <!-- item>rsa_pass_phrase</item -->
+ <!-- item>ecdsa_pass_phrase</item -->
+ </list>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#SYSDIR-ssh_host_rsa_key"><c>SYSDIR/ssh_host_rsa_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_dsa_key"><c>SYSDIR/ssh_host_dsa_key</c></seealso></item>
+ <item><seealso marker="#SYSDIR-ssh_host_ecdsa_key"><c>SYSDIR/ssh_host_ecdsa_key</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name>is_auth_key(PublicUserKey, User, DaemonOptions) -> Result</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_server_key_api#Module:is_auth_key-3">ssh_server_key_api: Module:is_auth_key/3</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_fun_common_option">user_dir_fun</seealso></item>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-authorized_keys"><c>USERDIR/authorized_keys</c></seealso></item>
+ <item><seealso marker="#USERDIR-authorized_keys2"><c>USERDIR/authorized_keys2</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name>add_host_key(HostNames, PublicHostKey, ConnectOptions) -> ok | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:add_host_key-3">ssh_client_key_api, Module:add_host_key/3</seealso>.
+ </p>
+ <p><strong>Option</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>File</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-known_hosts"><c>USERDIR/known_hosts</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name>is_host_key(Key, Host, Algorithm, ConnectOptions) -> Result</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:is_host_key-4">ssh_client_key_api, Module:is_host_key/4</seealso>.
+ </p>
+ <p><strong>Option</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ </list>
+ <p><strong>File</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-known_hosts"><c>USERDIR/known_hosts</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ <func>
+ <name>user_key(Algorithm, ConnectOptions) -> {ok, PrivateKey} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <desc>
+ <p><strong>Types and description</strong></p>
+ <p>See the api description in
+ <seealso marker="ssh:ssh_client_key_api#Module:user_key-2">ssh_client_key_api, Module:user_key/2</seealso>.
+ </p>
+ <p><strong>Options</strong></p>
+ <list>
+ <item><seealso marker="#type-user_dir_common_option">user_dir</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">dsa_pass_phrase</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">rsa_pass_phrase</seealso></item>
+ <item><seealso marker="#type-pubkey_passphrase_client_options">ecdsa_pass_phrase</seealso></item>
+ </list>
+ <p><strong>Files</strong></p>
+ <list>
+ <item><seealso marker="#USERDIR-id_dsa"><c>USERDIR/id_dsa</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_rsa"><c>USERDIR/id_rsa</c></seealso></item>
+ <item><seealso marker="#USERDIR-id_ecdsa"><c>USERDIR/id_ecdsa</c></seealso></item>
+ </list>
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml
index ea55126cb3..8c105147d6 100644
--- a/lib/ssh/doc/src/ssh_sftp.xml
+++ b/lib/ssh/doc/src/ssh_sftp.xml
@@ -425,7 +425,6 @@
<type>
<v>ChannelPid = pid()</v>
<v>Handle = term()</v>
- <v>Position = integer()</v>
<v>Len = integer()</v>
<v>Timeout = timeout()</v>
<v>Data = string() | binary()</v>
diff --git a/lib/ssh/doc/src/terminology.xml b/lib/ssh/doc/src/terminology.xml
new file mode 100644
index 0000000000..db1e08970d
--- /dev/null
+++ b/lib/ssh/doc/src/terminology.xml
@@ -0,0 +1,185 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2018</year>
+ <year>2018</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Terminology</title>
+ <prepared></prepared>
+ <docno></docno>
+ <approved></approved>
+ <date></date>
+ <rev></rev>
+ <file>terminology.xml</file>
+ </header>
+
+ <section>
+ <title>General Information</title>
+ <p>In the following terms that may cause confusion are explained.
+ </p>
+ </section>
+
+ <section>
+ <title>The term "user"</title>
+ <p>A "user" is a term that everyone understands intuitively. However, the understandings may differ which can
+ cause confusion.
+ </p>
+ <p>The term is used differently in <url href="http://www.openssh.com">OpenSSH</url> and SSH in Erlang/OTP.
+ The reason is the different environments and use cases that are not immediatly obvious.
+ </p>
+ <p>This chapter aims at explaining the differences and giving a rationale for why Erlang/OTP handles "user" as
+ it does.
+ </p>
+
+ <section>
+ <title>In OpenSSH</title>
+ <p>Many have been in contact with the command 'ssh' on a Linux machine (or similar) to remotly log in on
+ another machine. One types
+ </p>
+ <code>ssh host</code>
+ <p>to log in on the machine named <c>host</c>. The command prompts for your password on the remote <c>host</c> and
+ then you can read, write and execute as your <i>user name</i> has rights on the remote <c>host</c>. There are
+ stronger variants with pre-distributed keys or certificates, but that are for now just details in the
+ authentication process.
+ </p>
+ <p>You could log in as the user <c>anotheruser</c> with
+ </p>
+ <code>ssh anotheruser@host</code>
+ <p>and you will then be enabled to act as <c>anotheruser</c> on the <c>host</c> if authorized correctly.
+ </p>
+ <p>So what does <i>"your user name has rights"</i> mean? In a UNIX/Linux/etc context it is exactly as that context:
+ The <i>user</i> could read, write and execute programs according to the OS rules.
+ In addition, the user has a home directory (<c>$HOME</c>) and there is a <c>$HOME/.ssh/</c> directory
+ with ssh-specific files.
+ </p>
+ <section>
+ <title>SSH password authentication</title>
+ <p>When SSH tries to log in to a host, the ssh protocol communicates the user name (as a string) and a password.
+ The remote ssh server checks that there is such a user defined and that the provided password is acceptable.
+ </p>
+ <p>If so, the user is authorized.
+ </p>
+ </section>
+ <section>
+ <title>SSH public key authentication</title>
+ <p>This is a stronger method where the ssh protocol brings the user name, the user's public key and some
+ cryptographic information which we could ignore here.
+ </p>
+ <p>The ssh server on the remote host checks:
+ </p>
+ <list>
+ <item>That the <i>user</i> has a home directory,</item>
+ <item>that home directory contains a .ssh/ directory and</item>
+ <item>the .ssh/ directory contains the public key just received in the <c>authorized_keys</c> file</item>
+ </list>
+ <p>if so, the user is authorized.
+ </p>
+ </section>
+ <section>
+ <title>The SSH server on UNIX/Linux/etc after a succesful authentication</title>
+ <p>After a succesful incoming authentication, a new process runs as the just authenticated user.</p>
+ <p>Next step is to start a service according to the ssh request. In case of a request of a shell,
+ a new one is started which handles the OS-commands that arrives from the client (that's "you").
+ </p>
+ <p>In case of a sftp request, an sftp server is started in with the user's rights. So it could read, write or delete
+ files if allowed for that user.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>In Erlang/OTP SSH</title>
+ <p>For the Erlang/OTP SSH server the situation is different. The server executes in an Erlang process
+ in the Erlang emulator which in turn executes in an OS process. The emulator does not try to change its
+ user when authenticated over the SSH protocol.
+ So the remote user name is only for authentication purposes in the Erlang/OTP SSH application.
+ </p>
+ <section>
+ <title>Password authentication in Erlang SSH</title>
+ <p>The Erlang/OTP SSH server checks the user name and password in the following order:
+ </p>
+ <list type="ordered">
+ <item>If a
+ <seealso marker="ssh:ssh#option-pwdfun"><c>pwdfun</c></seealso>
+ is defined, that one is called and the returned boolean is the authentication result.
+ </item>
+ <item>Else, if the
+ <seealso marker="ssh:ssh#option-user_passwords"><c>user_passwords</c></seealso>
+ option is defined and the username and the password matches, the authentication is a success.
+ </item>
+ <item>Else, if the option
+ <seealso marker="ssh:ssh#option-password"><c>password</c></seealso>
+ is defined and matches the password the authentication is a success.
+ Note that the use of this option is not recommended in non-test code.
+ </item>
+ </list>
+ </section>
+ <section>
+ <title>Public key authentication in Erlang SSH</title>
+ <p>The user name, public key and cryptographic data (a signature) that is sent by the client, are used as follows
+ (some steps left out for clearity):
+ </p>
+ <list type="ordered">
+ <item>A callback module is selected using the options
+ <seealso marker="ssh:ssh#type-key_cb_common_option"><c>key_cb</c></seealso>.
+ </item>
+ <item>The callback module is used to check that the provided public key is one of the user's pre-stored.
+ In case of the default callback module, the files <c>authorized_keys</c> and <c>authorized_keys2</c>
+ are searched in a directory found in the following order:
+ <list>
+ <item>If the option
+ <seealso marker="ssh:ssh_file#type-user_dir_fun_common_option"><c>user_dir_fun</c></seealso>
+ is defined, that fun is called and the returned directory is used,
+ </item>
+ <item>Else, If the option
+ <seealso marker="ssh:ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ is defined, that directory is used,
+ </item>
+ <item>Else the subdirectory <c>.ssh</c> in the home directory of the user executing
+ the OS process of the Erlang emulator is used.
+ </item>
+ </list>
+ If the provided public key is not found, the authentication fails.
+ </item>
+ <item>Finally, if the provided public key is found, the signature provided by the client is checked with
+ the public key.
+ </item>
+ </list>
+ </section>
+ <section>
+ <title>The Erlang/OTP SSH server after a succesful authentication</title>
+ <p>After a successful authentication an <i>Erlang process</i> is handling the service request from the remote
+ ssh client. The rights of that process are those of the user of the OS process running the Erlang emulator.
+ </p>
+ <p>If a shell service request arrives to the server, an <i>Erlang shell</i> is opened in the server's emulator.
+ The rights in that shell is independent of the just authenticated user.
+ </p>
+ <p>In case of an sftp request, an sftp server is started with the rights of the user of the Erlang emulator's OS
+ process. So with sftp the authenticated user does not influence the rights.
+ </p>
+ <p>So after an authentication, the user name is not used anymore and has no influence.
+ </p>
+ </section>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/ssh/doc/src/usersguide.xml b/lib/ssh/doc/src/usersguide.xml
index 38ffa48cde..8a4df208d8 100644
--- a/lib/ssh/doc/src/usersguide.xml
+++ b/lib/ssh/doc/src/usersguide.xml
@@ -36,5 +36,6 @@
</description>
<xi:include href="introduction.xml"/>
<xi:include href="using_ssh.xml"/>
+ <xi:include href="terminology.xml"/>
<xi:include href="configure_algos.xml"/>
</part>
diff --git a/lib/ssh/doc/src/using_ssh.xml b/lib/ssh/doc/src/using_ssh.xml
index 80662e9a70..4455d5ecc5 100644
--- a/lib/ssh/doc/src/using_ssh.xml
+++ b/lib/ssh/doc/src/using_ssh.xml
@@ -74,16 +74,17 @@
<marker id="Running an Erlang ssh Daemon"></marker>
<title>Running an Erlang ssh Daemon</title>
- <p>The <c>system_dir</c> option must be a directory containing a host
- key file and it defaults to <c>/etc/ssh</c>. For details, see Section
- Configuration Files in <seealso
- marker="SSH_app">ssh(6)</seealso>.
+ <p>The
+ <seealso marker="ssh_file#type-system_dir_daemon_option"><c>system_dir</c></seealso>
+ option must be a directory containing a host key file and it defaults to <c>/etc/ssh</c>.
+ For details, see Section Configuration Files in <seealso marker="SSH_app">ssh(6)</seealso>.
</p>
<note><p>Normally, the <c>/etc/ssh</c> directory is only readable by root.</p>
</note>
- <p>The option <c>user_dir</c> defaults to directory <c>users ~/.ssh</c>.</p>
+ <p>The option <seealso marker="ssh_file#type-user_dir_common_option"><c>user_dir</c></seealso>
+ defaults to directory <c>users ~/.ssh</c>.</p>
<p><em>Step 1.</em> To run the example without root privileges,
generate new keys and host keys:</p>
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 9631427749..3ac74c4925 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -118,6 +118,9 @@
'diffie-hellman-group14-sha256' |
'diffie-hellman-group16-sha512' |
'diffie-hellman-group18-sha512' |
+ 'curve25519-sha256' |
+ 'curve448-sha512' |
'ecdh-sha2-nistp256' |
'ecdh-sha2-nistp384' |
'ecdh-sha2-nistp521'
@@ -140,7 +143,8 @@
'aes192-ctr' |
'aes256-ctr' |
.
-type mac_alg() :: 'AEAD_AES_128_GCM' |
@@ -169,7 +173,7 @@
-type common_options() :: [ common_option() ].
-type common_option() ::
- user_dir_common_option()
+ ssh_file:user_dir_common_option()
| profile_common_option()
| max_idle_time_common_option()
| key_cb_common_option()
@@ -187,8 +191,6 @@
-define(COMMON_OPTION, common_option()).
-
--type user_dir_common_option() :: {user_dir, false | string()}.
-type profile_common_option() :: {profile, atom() }.
-type max_idle_time_common_option() :: {idle_time, timeout()}.
-type rekey_limit_common_option() :: {rekey_limit, Bytes::limit_bytes() |
@@ -219,14 +221,14 @@
{transport, {atom(),atom(),atom()} }
| {vsn, {non_neg_integer(),non_neg_integer()} }
| {tstflg, list(term())}
- | {user_dir_fun, fun()}
+ | ssh_file:user_dir_fun_common_option()
| {max_random_length_padding, non_neg_integer()} .
-type client_option() ::
pref_public_key_algs_client_option()
- | pubkey_passphrase_client_options()
+ | ssh_file:pubkey_passphrase_client_options()
| host_accepting_client_options()
| authentication_client_options()
| diffie_hellman_group_exchange_client_option()
@@ -242,10 +244,6 @@
-type pref_public_key_algs_client_option() :: {pref_public_key_algs, [pubkey_alg()] } .
--type pubkey_passphrase_client_options() :: {dsa_pass_phrase, string()}
- | {rsa_pass_phrase, string()}
- | {ecdsa_pass_phrase, string()} .
-
-type host_accepting_client_options() ::
{silently_accept_hosts, accept_hosts()}
| {user_interaction, boolean()}
@@ -256,13 +254,7 @@
| accept_callback()
| {HashAlgoSpec::fp_digest_alg(), accept_callback()}.
--type fp_digest_alg() :: 'md5' |
- 'sha' |
- 'sha224' |
- 'sha256' |
- 'sha384' |
- 'sha512'
- .
+-type fp_digest_alg() :: 'md5' | crypto:sha1() | crypto:sha2() .
-type accept_callback() :: fun((PeerName::string(), fingerprint() ) -> boolean()) .
-type fingerprint() :: string() | [string()].
@@ -313,7 +305,7 @@
-type send_ext_info_daemon_option() :: {send_ext_info, boolean()} .
-type authentication_daemon_options() ::
- {system_dir, string()}
+ ssh_file:system_dir_daemon_option()
| {auth_method_kb_interactive_data, prompt_texts() }
| {user_passwords, [{UserName::string(),Pwd::string()}]}
| {password, string()}
@@ -492,4 +484,29 @@
-define(wr_record(N), ?wr_record(N, [])).
+%% Circular trace buffer macros
+
+-record(circ_buf_entry,
+ {
+ module,
+ line,
+ function,
+ pid = self(),
+ value
+ }).
+
+-define(CIRC_BUF_IN(VALUE),
+ ssh_dbg:cbuf_in(
+ #circ_buf_entry{module = ?MODULE,
+ line = ?LINE,
+ function = {?FUNCTION_NAME,?FUNCTION_ARITY},
+ pid = self(),
+ value = (VALUE)
+ })
+ ).
+
+-define(CIRC_BUF_IN_ONCE(VALUE),
+ ((fun(V) -> ?CIRC_BUF_IN(V), V end)(VALUE))
+ ).
+
-endif. % SSH_HRL defined
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 8e4831a601..4b41c10cbb 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -356,6 +356,8 @@ alg(ConnectionHandler) ->
| undefined,
encrypted_data_buffer = <<>> :: binary()
| undefined,
+ aead_data = <<>> :: binary()
+ | undefined,
undecrypted_packet_length :: undefined | non_neg_integer(),
key_exchange_init_msg :: #ssh_msg_kexinit{}
| undefined,
@@ -1308,14 +1310,16 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
try ssh_transport:handle_packet_part(
D0#data.decrypted_data_buffer,
<<(D0#data.encrypted_data_buffer)/binary, NewData/binary>>,
- D0#data.undecrypted_packet_length,
+ D0#data.aead_data,
+ D0#data.undecrypted_packet_length,
D0#data.ssh_params)
of
{packet_decrypted, DecryptedBytes, EncryptedDataRest, Ssh1} ->
D1 = D0#data{ssh_params =
Ssh1#ssh{recv_sequence = ssh_transport:next_seqnum(Ssh1#ssh.recv_sequence)},
decrypted_data_buffer = <<>>,
- undecrypted_packet_length = undefined,
+ undecrypted_packet_length = undefined,
+ aead_data = <<>>,
encrypted_data_buffer = EncryptedDataRest},
try
ssh_message:decode(set_kex_overload_prefix(DecryptedBytes,D1))
@@ -1353,14 +1357,15 @@ handle_event(info, {Proto, Sock, NewData}, StateName, D0 = #data{socket = Sock,
StateName, D1),
{stop, Shutdown, D}
end;
-
- {get_more, DecryptedBytes, EncryptedDataRest, RemainingSshPacketLen, Ssh1} ->
+
+ {get_more, DecryptedBytes, EncryptedDataRest, AeadData, RemainingSshPacketLen, Ssh1} ->
%% Here we know that there are not enough bytes in
%% EncryptedDataRest to use. We must wait for more.
inet:setopts(Sock, [{active, once}]),
{keep_state, D0#data{encrypted_data_buffer = EncryptedDataRest,
decrypted_data_buffer = DecryptedBytes,
- undecrypted_packet_length = RemainingSshPacketLen,
+ undecrypted_packet_length = RemainingSshPacketLen,
+ aead_data = AeadData,
ssh_params = Ssh1}};
{bad_mac, Ssh1} ->
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index b53c09b17d..4fe15b24d3 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -54,7 +54,13 @@
start_tracer/0, start_tracer/1,
on/1, on/0,
off/1, off/0,
- go_on/0
+ go_on/0,
+ %% Circular buffer
+ cbuf_start/0, cbuf_start/1,
+ cbuf_stop_clear/0,
+ cbuf_in/1,
+ cbuf_list/0,
+ fmt_cbuf_items/0, fmt_cbuf_item/1
]).
-export([shrink_bin/1,
@@ -71,6 +77,8 @@
-behaviour(gen_server).
-define(SERVER, ?MODULE).
+-define(CALL_TIMEOUT, 15000). % 3x the default
+
%%%================================================================
-define(ALL_DBG_TYPES, get_all_dbg_types()).
@@ -107,7 +115,7 @@ start_tracer(WriteFun) when is_function(WriteFun,3) ->
start_tracer(WriteFun, InitAcc) when is_function(WriteFun, 3) ->
Handler =
fun(Arg, Acc0) ->
- try_all_types_in_all_modules(gen_server:call(?SERVER, get_on),
+ try_all_types_in_all_modules(gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
Arg, WriteFun,
Acc0)
end,
@@ -122,7 +130,7 @@ off() -> off(?ALL_DBG_TYPES). % A bit overkill...
off(Type) -> switch(off, Type).
go_on() ->
- IsOn = gen_server:call(?SERVER, get_on),
+ IsOn = gen_server:call(?SERVER, get_on, ?CALL_TIMEOUT),
on(IsOn).
%%%----------------------------------------------------------------
@@ -253,7 +261,7 @@ switch(X, Types) when is_list(Types) ->
end,
case lists:usort(Types) -- ?ALL_DBG_TYPES of
[] ->
- gen_server:call(?SERVER, {switch,X,Types});
+ gen_server:call(?SERVER, {switch,X,Types}, ?CALL_TIMEOUT);
L ->
{error, {unknown, L}}
end.
@@ -331,3 +339,103 @@ ts({_,_,Usec}=Now) when is_integer(Usec) ->
io_lib:format("~.2.0w:~.2.0w:~.2.0w.~.6.0w",[HH,MM,SS,Usec]);
ts(_) ->
"-".
+
+%%%================================================================
+-define(CIRC_BUF, circ_buf).
+
+cbuf_start() ->
+ cbuf_start(20).
+
+cbuf_start(CbufMaxLen) ->
+ put(?CIRC_BUF, {CbufMaxLen,queue:new()}),
+ ok.
+
+
+cbuf_stop_clear() ->
+ case erase(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+cbuf_in(Value) ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ disabled;
+ {CbufMaxLen,Queue} ->
+ UpdatedQueue =
+ try queue:head(Queue) of
+ {Value, TS0, Cnt0} ->
+ %% Same Value as last saved in the queue
+ queue:in_r({Value, TS0, Cnt0+1},
+ queue:drop(Queue)
+ );
+ _ ->
+ queue:in_r({Value, erlang:timestamp(), 1},
+ truncate_cbuf(Queue, CbufMaxLen)
+ )
+ catch
+ error:empty ->
+ queue:in_r({Value, erlang:timestamp(), 1}, Queue)
+ end,
+ put(?CIRC_BUF, {CbufMaxLen,UpdatedQueue}),
+ ok
+ end.
+
+
+cbuf_list() ->
+ case get(?CIRC_BUF) of
+ undefined ->
+ [];
+ {_CbufMaxLen,Queue} ->
+ queue:to_list(Queue)
+ end.
+
+
+truncate_cbuf(Q, CbufMaxLen) ->
+ case queue:len(Q) of
+ N when N>=CbufMaxLen ->
+ truncate_cbuf(element(2,queue:out_r(Q)), CbufMaxLen);
+ _ ->
+ Q
+ end.
+
+fmt_cbuf_items() ->
+ lists:flatten(
+ io_lib:format("Circular trace buffer. Latest item first.~n~s~n",
+ [case get(?CIRC_BUF) of
+ {Max,_} ->
+ L = cbuf_list(),
+ [io_lib:format("==== ~.*w: ~s~n",[num_digits(Max),N,fmt_cbuf_item(X)]) ||
+ {N,X} <- lists:zip(lists:seq(1,length(L)), L)
+ ];
+ _ ->
+ io_lib:format("Not started.~n",[])
+ end])).
+
+
+num_digits(0) -> 1;
+num_digits(N) when N>0 -> 1+trunc(math:log10(N)).
+
+
+fmt_cbuf_item({Value, TimeStamp, N}) ->
+ io_lib:format("~s~s~n~s~n",
+ [fmt_ts(TimeStamp),
+ [io_lib:format(" (Repeated ~p times)",[N]) || N>1],
+ fmt_value(Value)]).
+
+
+fmt_ts(TS = {_,_,Us}) ->
+ {{YY,MM,DD},{H,M,S}} = calendar:now_to_universal_time(TS),
+ io_lib:format("~w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w.~.6.0w UTC",[YY,MM,DD,H,M,S,Us]).
+
+fmt_value(#circ_buf_entry{module = M,
+ line = L,
+ function = {F,A},
+ pid = Pid,
+ value = V}) ->
+ io_lib:format("~p:~p ~p/~p ~p~n~s",[M,L,F,A,Pid,fmt_value(V)]);
+fmt_value(Value) ->
+ io_lib:format("~p",[Value]).
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 832952ed52..669b0f9be2 100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
@@ -39,6 +39,23 @@
is_auth_key/3]).
+-export_type([system_dir_daemon_option/0,
+ user_dir_common_option/0,
+ user_dir_fun_common_option/0,
+ pubkey_passphrase_client_options/0
+ ]).
+
+-type system_dir_daemon_option() :: {system_dir, string()}.
+-type user_dir_common_option() :: {user_dir, string()}.
+-type user_dir_fun_common_option() :: {user_dir_fun, user2dir()}.
+-type user2dir() :: fun((RemoteUserName::string()) -> UserDir :: string()) .
+
+-type pubkey_passphrase_client_options() :: {dsa_pass_phrase, string()}
+ | {rsa_pass_phrase, string()}
+ | {ecdsa_pass_phrase, string()} .
+
+
+
-define(PERM_700, 8#700).
-define(PERM_644, 8#644).
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 55c0548c9b..da4027a763 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -289,12 +289,12 @@ encode(#ssh_msg_kex_dh_gex_reply{
<<?Ebyte(?SSH_MSG_KEX_DH_GEX_REPLY), ?Ebinary(EncKey), ?Empint(F), ?Ebinary(EncSign)>>;
encode(#ssh_msg_kex_ecdh_init{q_c = Q_c}) ->
- <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Empint(Q_c)>>;
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_INIT), ?Ebinary(Q_c)>>;
encode(#ssh_msg_kex_ecdh_reply{public_host_key = {Key,SigAlg}, q_s = Q_s, h_sig = Sign}) ->
EncKey = public_key:ssh_encode(Key, ssh2_pubkey),
EncSign = encode_signature(Key, SigAlg, Sign),
- <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Empint(Q_s), ?Ebinary(EncSign)>>;
+ <<?Ebyte(?SSH_MSG_KEX_ECDH_REPLY), ?Ebinary(EncKey), ?Ebinary(Q_s), ?Ebinary(EncSign)>>;
encode(#ssh_msg_ignore{data = Data}) ->
<<?Ebyte(?SSH_MSG_IGNORE), ?Estring_utf8(Data)>>;
@@ -504,13 +504,13 @@ decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REPLY), ?DEC_BIN(Key,__0), ?DEC_MPINT(F,__1),
h_sig = decode_signature(Hashsign)
};
-decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_MPINT(Q_c,__0)>>) ->
+decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_INIT), ?DEC_BIN(Q_c,__0)>>) ->
#ssh_msg_kex_ecdh_init{
q_c = Q_c
};
decode(<<"ecdh",?BYTE(?SSH_MSG_KEX_ECDH_REPLY),
- ?DEC_BIN(Key,__1), ?DEC_MPINT(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
+ ?DEC_BIN(Key,__1), ?DEC_BIN(Q_s,__2), ?DEC_BIN(Sig,__3)>>) ->
#ssh_msg_kex_ecdh_reply{
public_host_key = public_key:ssh_decode(Key, ssh2_pubkey),
q_s = Q_s,
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 9ec16b420d..c5b0704925 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -36,7 +36,7 @@
default_algorithms/0, default_algorithms/1,
algo_classes/0, algo_class/1,
algo_two_spec_classes/0, algo_two_spec_class/1,
- handle_packet_part/4,
+ handle_packet_part/5,
handle_hello_version/1,
key_exchange_init_msg/1,
key_init/3, new_keys_message/1,
@@ -104,17 +104,14 @@ algo_two_spec_class(_) -> false.
default_algorithms(kex) ->
supported_algorithms(kex, [
- %% Under devolpment:
- 'curve25519-sha256',
- 'curve448-sha512',
%% Gone in OpenSSH 7.3.p1:
'diffie-hellman-group1-sha1'
]);
default_algorithms(cipher) ->
supported_algorithms(cipher, same(['AEAD_AES_128_GCM',
- 'AEAD_AES_256_GCM']));
+ 'AEAD_AES_256_GCM'
+ ]));
default_algorithms(mac) ->
supported_algorithms(mac, same(['AEAD_AES_128_GCM',
'AEAD_AES_256_GCM']));
@@ -128,18 +125,18 @@ supported_algorithms() -> [{K,supported_algorithms(K)} || K <- algo_classes()].
supported_algorithms(kex) ->
select_crypto_supported(
[
- {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {ec_curve,secp384r1}, {hashs,sha384}]},
- {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {ec_curve,secp521r1}, {hashs,sha512}]},
- {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {ec_curve,secp256r1}, {hashs,sha256}]},
- %% https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves
- %% Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448
- {'curve25519-sha256', [{public_keys,eddh}, {curves,x25519}, {hashs,sha256}]},
- {'[email protected]', [{public_keys,eddh}, {curves,x25519}, {hashs,sha256}]},
- {'curve448-sha512', [{public_keys,eddh}, {curves,x448}, {hashs,sha512}]},
+ {'ecdh-sha2-nistp384', [{public_keys,ecdh}, {curves,secp384r1}, {hashs,sha384}]},
+ {'ecdh-sha2-nistp521', [{public_keys,ecdh}, {curves,secp521r1}, {hashs,sha512}]},
+ {'ecdh-sha2-nistp256', [{public_keys,ecdh}, {curves,secp256r1}, {hashs,sha256}]},
{'diffie-hellman-group-exchange-sha256', [{public_keys,dh}, {hashs,sha256}]},
{'diffie-hellman-group16-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group18-sha512', [{public_keys,dh}, {hashs,sha512}]}, % In OpenSSH 7.3.p1
{'diffie-hellman-group14-sha256', [{public_keys,dh}, {hashs,sha256}]}, % In OpenSSH 7.3.p1
+ %% https://tools.ietf.org/html/draft-ietf-curdle-ssh-curves
+ %% Secure Shell (SSH) Key Exchange Method using Curve25519 and Curve448
+ {'curve25519-sha256', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
+ {'[email protected]', [{public_keys,ecdh}, {curves,x25519}, {hashs,sha256}]},
+ {'curve448-sha512', [{public_keys,ecdh}, {curves,x448}, {hashs,sha512}]},
{'diffie-hellman-group14-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group-exchange-sha1', [{public_keys,dh}, {hashs,sha}]},
{'diffie-hellman-group1-sha1', [{public_keys,dh}, {hashs,sha}]}
@@ -147,9 +144,9 @@ supported_algorithms(kex) ->
supported_algorithms(public_key) ->
select_crypto_supported(
[
- {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {ec_curve,secp384r1}]},
- {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {ec_curve,secp521r1}]},
- {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {ec_curve,secp256r1}]},
+ {'ecdsa-sha2-nistp384', [{public_keys,ecdsa}, {hashs,sha384}, {curves,secp384r1}]},
+ {'ecdsa-sha2-nistp521', [{public_keys,ecdsa}, {hashs,sha512}, {curves,secp521r1}]},
+ {'ecdsa-sha2-nistp256', [{public_keys,ecdsa}, {hashs,sha256}, {curves,secp256r1}]},
{'ssh-rsa', [{public_keys,rsa}, {hashs,sha} ]},
{'rsa-sha2-256', [{public_keys,rsa}, {hashs,sha256} ]},
{'rsa-sha2-512', [{public_keys,rsa}, {hashs,sha512} ]},
@@ -160,6 +157,7 @@ supported_algorithms(cipher) ->
same(
select_crypto_supported(
[
+ {'[email protected]', [{ciphers,chacha20}, {macs,poly1305}]},
{'[email protected]', [{ciphers,{aes_gcm,256}}]},
{'aes256-ctr', [{ciphers,{aes_ctr,256}}]},
{'aes192-ctr', [{ciphers,{aes_ctr,192}}]},
@@ -174,9 +172,9 @@ supported_algorithms(cipher) ->
supported_algorithms(mac) ->
same(
select_crypto_supported(
- [{'hmac-sha2-256', [{hashs,sha256}]},
- {'hmac-sha2-512', [{hashs,sha512}]},
- {'hmac-sha1', [{hashs,sha}]},
+ [{'hmac-sha2-256', [{macs,hmac}, {hashs,sha256}]},
+ {'hmac-sha2-512', [{macs,hmac}, {hashs,sha512}]},
+ {'hmac-sha1', [{macs,hmac}, {hashs,sha}]},
{'AEAD_AES_128_GCM', [{ciphers,{aes_gcm,128}}]},
{'AEAD_AES_256_GCM', [{ciphers,{aes_gcm,256}}]}
]
@@ -982,13 +980,14 @@ select_algorithm(Role, Client, Server, Opts) ->
%%% the exchanged MAC algorithms are ignored and there doesn't have to be
%%% a matching MAC.
-aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan('AEAD_AES_128_GCM', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan('AEAD_AES_256_GCM', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan(_, 'AEAD_AES_128_GCM') -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
-aead_gcm_simultan(_, 'AEAD_AES_256_GCM') -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
-aead_gcm_simultan(Cipher, Mac) -> {Cipher,Mac}.
+aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_128_GCM', 'AEAD_AES_128_GCM'};
+aead_gcm_simultan('[email protected]', _) -> {'AEAD_AES_256_GCM', 'AEAD_AES_256_GCM'};
+aead_gcm_simultan('AEAD_AES_128_GCM'=C, _) -> {C, C};
+aead_gcm_simultan('AEAD_AES_256_GCM'=C, _) -> {C, C};
+aead_gcm_simultan(_, 'AEAD_AES_128_GCM'=C) -> {C, C};
+aead_gcm_simultan(_, 'AEAD_AES_256_GCM'=C) -> {C, C};
+aead_gcm_simultan('[email protected]'=C, _)-> {C, C};
+aead_gcm_simultan(Cipher, Mac) -> {Cipher,Mac}.
select_encrypt_decrypt(client, Client, Server) ->
@@ -1136,7 +1135,7 @@ pack(PlainText,
encrypt = CryptoAlg} = Ssh0, PacketLenDeviationForTests) when is_binary(PlainText) ->
{Ssh1, CompressedPlainText} = compress(Ssh0, PlainText),
- {EcryptedPacket, MAC, Ssh3} =
+ {FinalPacket, Ssh3} =
case pkt_type(CryptoAlg) of
common ->
PaddingLen = padding_length(4+1+size(CompressedPlainText), Ssh0),
@@ -1145,16 +1144,15 @@ pack(PlainText,
PlainPacketData = <<?UINT32(PlainPacketLen),?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>,
{Ssh2, EcryptedPacket0} = encrypt(Ssh1, PlainPacketData),
MAC0 = mac(MacAlg, MacKey, SeqNum, PlainPacketData),
- {EcryptedPacket0, MAC0, Ssh2};
+ {<<EcryptedPacket0/binary,MAC0/binary>>, Ssh2};
aead ->
PaddingLen = padding_length(1+size(CompressedPlainText), Ssh0),
Padding = ssh_bits:random(PaddingLen),
PlainPacketLen = 1 + PaddingLen + size(CompressedPlainText) + PacketLenDeviationForTests,
PlainPacketData = <<?BYTE(PaddingLen), CompressedPlainText/binary, Padding/binary>>,
- {Ssh2, {EcryptedPacket0,MAC0}} = encrypt(Ssh1, {<<?UINT32(PlainPacketLen)>>,PlainPacketData}),
- {<<?UINT32(PlainPacketLen),EcryptedPacket0/binary>>, MAC0, Ssh2}
+ {Ssh2, {EcryptedPacket0,MAC0}} = encrypt(Ssh1, <<?UINT32(PlainPacketLen),PlainPacketData/binary>>),
+ {<<EcryptedPacket0/binary,MAC0/binary>>, Ssh2}
end,
- FinalPacket = [EcryptedPacket, MAC],
Ssh = Ssh3#ssh{send_sequence = (SeqNum+1) band 16#ffffffff},
{FinalPacket, Ssh}.
@@ -1174,31 +1172,31 @@ padding_length(Size, #ssh{encrypt_block_size = BlockSize,
-handle_packet_part(<<>>, Encrypted0, undefined, #ssh{decrypt = CryptoAlg} = Ssh0) ->
+handle_packet_part(<<>>, Encrypted0, AEAD0, undefined, #ssh{decrypt = CryptoAlg} = Ssh0) ->
%% New ssh packet
case get_length(pkt_type(CryptoAlg), Encrypted0, Ssh0) of
get_more ->
%% too short to get the length
- {get_more, <<>>, Encrypted0, undefined, Ssh0};
+ {get_more, <<>>, Encrypted0, AEAD0, undefined, Ssh0};
- {ok, PacketLen, _, _, _} when PacketLen > ?SSH_MAX_PACKET_SIZE ->
+ {ok, PacketLen, _, _, _, _} when PacketLen > ?SSH_MAX_PACKET_SIZE ->
%% far too long message than expected
{error, {exceeds_max_size,PacketLen}};
- {ok, PacketLen, Decrypted, Encrypted1,
+ {ok, PacketLen, Decrypted, Encrypted1, AEAD,
#ssh{recv_mac_size = MacSize} = Ssh1} ->
%% enough bytes so we got the length and can calculate how many
%% more bytes to expect for a full packet
TotalNeeded = (4 + PacketLen + MacSize),
- handle_packet_part(Decrypted, Encrypted1, TotalNeeded, Ssh1)
+ handle_packet_part(Decrypted, Encrypted1, AEAD, TotalNeeded, Ssh1)
end;
-handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0)
+handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0)
when (size(DecryptedPfx)+size(EncryptedBuffer)) < TotalNeeded ->
%% need more bytes to finalize the packet
- {get_more, DecryptedPfx, EncryptedBuffer, TotalNeeded, Ssh0};
+ {get_more, DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded, Ssh0};
-handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded,
+handle_packet_part(DecryptedPfx, EncryptedBuffer, AEAD, TotalNeeded,
#ssh{recv_mac_size = MacSize,
decrypt = CryptoAlg} = Ssh0) ->
%% enough bytes to decode the packet.
@@ -1216,8 +1214,7 @@ handle_packet_part(DecryptedPfx, EncryptedBuffer, TotalNeeded,
{packet_decrypted, DecompressedPayload, NextPacketBytes, Ssh}
end;
aead ->
- PacketLenBin = DecryptedPfx,
- case decrypt(Ssh0, {PacketLenBin,EncryptedSfx,Mac}) of
+ case decrypt(Ssh0, {AEAD,EncryptedSfx,Mac}) of
{Ssh1, error} ->
{bad_mac, Ssh1};
{Ssh1, DecryptedSfx} ->
@@ -1234,21 +1231,29 @@ get_length(common, EncryptedBuffer, #ssh{decrypt_block_size = BlockSize} = Ssh0)
<<EncBlock:BlockSize/binary, EncryptedRest/binary>> = EncryptedBuffer,
{Ssh,
<<?UINT32(PacketLen),_/binary>> = Decrypted} = decrypt(Ssh0, EncBlock),
- {ok, PacketLen, Decrypted, EncryptedRest, Ssh};
+ {ok, PacketLen, Decrypted, EncryptedRest, <<>>, Ssh};
false ->
get_more
end;
+
get_length(aead, EncryptedBuffer, Ssh) ->
- case size(EncryptedBuffer) >= 4 of
- true ->
+ case {size(EncryptedBuffer) >= 4, Ssh#ssh.decrypt} of
+ {true, '[email protected]'} ->
+ <<EncryptedLen:4/binary, EncryptedRest/binary>> = EncryptedBuffer,
+ {Ssh1, PacketLenBin} = decrypt(Ssh, {length,EncryptedLen}),
+ <<?UINT32(PacketLen)>> = PacketLenBin,
+ {ok, PacketLen, PacketLenBin, EncryptedRest, EncryptedLen, Ssh1};
+ {true, _} ->
<<?UINT32(PacketLen), EncryptedRest/binary>> = EncryptedBuffer,
- {ok, PacketLen, <<?UINT32(PacketLen)>>, EncryptedRest, Ssh};
- false ->
+ {ok, PacketLen, <<?UINT32(PacketLen)>>, EncryptedRest, <<?UINT32(PacketLen)>>, Ssh};
+ {false, _} ->
get_more
end.
+
pkt_type('AEAD_AES_128_GCM') -> aead;
pkt_type('AEAD_AES_256_GCM') -> aead;
+pkt_type('[email protected]') -> aead;
pkt_type(_) -> common.
payload(<<PacketLen:32, PaddingLen:8, PayloadAndPadding/binary>>) ->
@@ -1353,11 +1358,32 @@ cipher('aes192-ctr') ->
cipher('aes256-ctr') ->
#cipher_data{key_bytes = 32,
iv_bytes = 16,
- block_bytes = 16}.
+ block_bytes = 16};
+
+cipher('[email protected]') -> % FIXME: Verify!!
+ #cipher_data{key_bytes = 32,
+ iv_bytes = 12,
+ block_bytes = 8}.
+
encrypt_init(#ssh{encrypt = none} = Ssh) ->
{ok, Ssh};
+encrypt_init(#ssh{encrypt = '[email protected]', role = client} = Ssh) ->
+ %% [email protected] uses two independent crypto streams, one (chacha20)
+ %% for the length used in stream mode, and the other (chacha20-poly1305) as AEAD for
+ %% the payload and to MAC the length||payload.
+ %% See draft-josefsson-ssh-chacha20-poly1305-openssh-00
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, "C", 512),
+ {ok, Ssh#ssh{encrypt_keys = {K1,K2}
+ % encrypt_block_size = 16, %default = 8. What to set it to? 64 (openssl chacha.h)
+ % ctx and iv is setup for each packet
+ }};
+encrypt_init(#ssh{encrypt = '[email protected]', role = server} = Ssh) ->
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, "D", 512),
+ {ok, Ssh#ssh{encrypt_keys = {K1,K2}
+ % encrypt_block_size = 16, %default = 8. What to set it to?
+ }};
encrypt_init(#ssh{encrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
IV = hash(Ssh, "A", 12*8),
<<K:16/binary>> = hash(Ssh, "C", 128),
@@ -1458,18 +1484,40 @@ encrypt_final(Ssh) ->
encrypt(#ssh{encrypt = none} = Ssh, Data) ->
{Ssh, Data};
+encrypt(#ssh{encrypt = '[email protected]',
+ encrypt_keys = {K1,K2},
+ send_sequence = Seq} = Ssh,
+ <<LenData:4/binary, PayloadData/binary>>) ->
+ %% Encrypt length
+ IV1 = <<0:8/unit:8, Seq:8/unit:8>>,
+ {_,EncLen} = crypto:stream_encrypt(crypto:stream_init(chacha20, K1, IV1),
+ LenData),
+ %% Encrypt payload
+ IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
+ {_,EncPayloadData} = crypto:stream_encrypt(crypto:stream_init(chacha20, K2, IV2),
+ PayloadData),
+
+ %% MAC tag
+ {_,PolyKey} = crypto:stream_encrypt(crypto:stream_init(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>),
+ <<0:32/unit:8>>),
+ EncBytes = <<EncLen/binary,EncPayloadData/binary>>,
+ Ctag = crypto:poly1305(PolyKey, EncBytes),
+ %% Result
+ {Ssh, {EncBytes,Ctag}};
encrypt(#ssh{encrypt = 'AEAD_AES_128_GCM',
encrypt_keys = K,
- encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) ->
- Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data),
+ encrypt_ctx = IV0} = Ssh,
+ <<LenData:4/binary, PayloadData/binary>>) ->
+ {Ctext,Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, {LenData,PayloadData}),
IV = next_gcm_iv(IV0),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
+ {Ssh#ssh{encrypt_ctx = IV}, {<<LenData/binary,Ctext/binary>>,Ctag}};
encrypt(#ssh{encrypt = 'AEAD_AES_256_GCM',
encrypt_keys = K,
- encrypt_ctx = IV0} = Ssh, Data={_AAD,_Ptext}) ->
- Enc = {_Ctext,_Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, Data),
+ encrypt_ctx = IV0} = Ssh,
+ <<LenData:4/binary, PayloadData/binary>>) ->
+ {Ctext,Ctag} = crypto:block_encrypt(aes_gcm, K, IV0, {LenData,PayloadData}),
IV = next_gcm_iv(IV0),
- {Ssh#ssh{encrypt_ctx = IV}, Enc};
+ {Ssh#ssh{encrypt_ctx = IV}, {<<LenData/binary,Ctext/binary>>,Ctag}};
encrypt(#ssh{encrypt = '3des-cbc',
encrypt_keys = {K1,K2,K3},
encrypt_ctx = IV0} = Ssh, Data) ->
@@ -1502,6 +1550,14 @@ encrypt(#ssh{encrypt = 'aes256-ctr',
decrypt_init(#ssh{decrypt = none} = Ssh) ->
{ok, Ssh};
+decrypt_init(#ssh{decrypt = '[email protected]', role = client} = Ssh) ->
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, "D", 512),
+ {ok, Ssh#ssh{decrypt_keys = {K1,K2}
+ }};
+decrypt_init(#ssh{decrypt = '[email protected]', role = server} = Ssh) ->
+ <<K2:32/binary,K1:32/binary>> = hash(Ssh, "C", 512),
+ {ok, Ssh#ssh{decrypt_keys = {K1,K2}
+ }};
decrypt_init(#ssh{decrypt = 'AEAD_AES_128_GCM', role = client} = Ssh) ->
IV = hash(Ssh, "B", 12*8),
<<K:16/binary>> = hash(Ssh, "D", 128),
@@ -1602,6 +1658,31 @@ decrypt_final(Ssh) ->
decrypt(Ssh, <<>>) ->
{Ssh, <<>>};
+decrypt(#ssh{decrypt = '[email protected]',
+ decrypt_keys = {K1,_K2},
+ recv_sequence = Seq} = Ssh, {length,EncryptedLen}) ->
+ {_State,PacketLenBin} =
+ crypto:stream_decrypt(crypto:stream_init(chacha20, K1, <<0:8/unit:8, Seq:8/unit:8>>),
+ EncryptedLen),
+ {Ssh, PacketLenBin};
+decrypt(#ssh{decrypt = '[email protected]',
+ decrypt_keys = {_K1,K2},
+ recv_sequence = Seq} = Ssh, {AAD,Ctext,Ctag}) ->
+ %% The length is already decoded and used to divide the input
+ %% Check the mac (important that it is timing-safe):
+ {_,PolyKey} =
+ crypto:stream_encrypt(crypto:stream_init(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>),
+ <<0:32/unit:8>>),
+ case equal_const_time(Ctag, crypto:poly1305(PolyKey, <<AAD/binary,Ctext/binary>>)) of
+ true ->
+ %% MAC is ok, decode
+ IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
+ {_,PlainText} =
+ crypto:stream_decrypt(crypto:stream_init(chacha20,K2,IV2), Ctext),
+ {Ssh, PlainText};
+ false ->
+ {Ssh,error}
+ end;
decrypt(#ssh{decrypt = none} = Ssh, Data) ->
{Ssh, Data};
decrypt(#ssh{decrypt = 'AEAD_AES_128_GCM',
@@ -1744,7 +1825,7 @@ send_mac_init(SSH) ->
Key = hash(SSH, "F", KeySize),
{ok, SSH#ssh { send_mac_key = Key }}
end;
- aead ->
+ _ ->
%% Not applicable
{ok, SSH}
end.
@@ -1765,7 +1846,7 @@ recv_mac_init(SSH) ->
Key = hash(SSH, "E", 8*mac_key_bytes(SSH#ssh.recv_mac)),
{ok, SSH#ssh { recv_mac_key = Key }}
end;
- aead ->
+ _ ->
%% Not applicable
{ok, SSH}
end.
@@ -1812,6 +1893,7 @@ hash(K, H, Ki, N, HashAlg) ->
kex_hash(SSH, Key, HashAlg, Args) ->
crypto:hash(HashAlg, kex_plaintext(SSH,Key,Args)).
+
kex_plaintext(SSH, Key, Args) ->
EncodedKey = public_key:ssh_encode(Key, ssh2_pubkey),
<<?Estring(SSH#ssh.c_version), ?Estring(SSH#ssh.s_version),
@@ -1819,8 +1901,13 @@ kex_plaintext(SSH, Key, Args) ->
?Ebinary(EncodedKey),
(kex_alg_dependent(Args))/binary>>.
+
+kex_alg_dependent({Q_c, Q_s, K}) when is_binary(Q_c), is_binary(Q_s) ->
+ %% ecdh
+ <<?Ebinary(Q_c), ?Ebinary(Q_s), ?Empint(K)>>;
+
kex_alg_dependent({E, F, K}) ->
- %% diffie-hellman and ec diffie-hellman (with E = Q_c, F = Q_s)
+ %% diffie-hellman
<<?Empint(E), ?Empint(F), ?Empint(K)>>;
kex_alg_dependent({-1, NBits, -1, Prime, Gen, E, F, K}) ->
@@ -1905,6 +1992,7 @@ mac_key_bytes('hmac-sha2-256')-> 32;
mac_key_bytes('hmac-sha2-512')-> 64;
mac_key_bytes('AEAD_AES_128_GCM') -> 0;
mac_key_bytes('AEAD_AES_256_GCM') -> 0;
+mac_key_bytes('[email protected]') -> 0;
mac_key_bytes(none) -> 0.
mac_digest_size('hmac-sha1') -> 20;
@@ -1915,6 +2003,7 @@ mac_digest_size('hmac-sha2-256') -> 32;
mac_digest_size('hmac-sha2-512') -> 64;
mac_digest_size('AEAD_AES_128_GCM') -> 16;
mac_digest_size('AEAD_AES_256_GCM') -> 16;
+mac_digest_size('[email protected]') -> 16;
mac_digest_size(none) -> 0.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1937,11 +2026,13 @@ parallell_gen_key(Ssh = #ssh{keyex_key = {x, {G, P}},
Ssh#ssh{keyex_key = {{Private, Public}, {G, P}}}.
+generate_key(ecdh = Algorithm, Args) ->
+ crypto:generate_key(Algorithm, Args);
generate_key(Algorithm, Args) ->
{Public,Private} = crypto:generate_key(Algorithm, Args),
{crypto:bytes_to_integer(Public), crypto:bytes_to_integer(Private)}.
-
+
compute_key(Algorithm, OthersPublic, MyPrivate, Args) ->
Shared = crypto:compute_key(Algorithm, OthersPublic, MyPrivate, Args),
crypto:bytes_to_integer(Shared).
@@ -1978,15 +2069,10 @@ supported_algorithms(Key, BlackList) ->
select_crypto_supported(L) ->
- Sup = [{ec_curve,crypto_supported_curves()} | crypto:supports()],
+ Sup = crypto:supports(),
[Name || {Name,CryptoRequires} <- L,
crypto_supported(CryptoRequires, Sup)].
-crypto_supported_curves() ->
- try crypto:ec_curves()
- catch _:_ -> []
- end.
-
crypto_supported(Conditions, Supported) ->
lists:all( fun({Tag,CryptoName}) when is_atom(CryptoName) ->
crypto_name_supported(Tag,CryptoName,Supported);
@@ -1996,7 +2082,11 @@ crypto_supported(Conditions, Supported) ->
end, Conditions).
crypto_name_supported(Tag, CryptoName, Supported) ->
- lists:member(CryptoName, proplists:get_value(Tag,Supported,[])).
+ Vs = case proplists:get_value(Tag,Supported,[]) of
+ [] when Tag == curves -> crypto:ec_curves();
+ L -> L
+ end,
+ lists:member(CryptoName, Vs).
len_supported(Name, Len) ->
try
@@ -2027,6 +2117,20 @@ same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Compare two binaries in a timing safe maner.
+%%% The time spent in comparing should not be different depending on where in the binaries they differ.
+%%% This is to avoid a certain side-channel attac.
+equal_const_time(X1, X2) -> equal_const_time(X1, X2, true).
+
+equal_const_time(<<B1,R1/binary>>, <<B2,R2/binary>>, Truth) ->
+ equal_const_time(R1, R2, Truth and (B1 == B2));
+equal_const_time(<<>>, <<>>, Truth) ->
+ Truth;
+equal_const_time(_, _, _) ->
+ false.
+
+%%%-------- Remove CR, LF and following characters from a line
+
trim_tail(Str) ->
lists:takewhile(fun(C) ->
C=/=$\r andalso C=/=$\n
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index 7bb9c2d101..1d77ccb311 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/ssh/test/.gitignore b/lib/ssh/test/.gitignore
new file mode 100644
index 0000000000..c9d5f086b3
--- /dev/null
+++ b/lib/ssh/test/.gitignore
@@ -0,0 +1,5 @@
+
+
+property_test/ssh_eqc_client_server_dirs/system
+property_test/ssh_eqc_client_server_dirs/user
+
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
index 6d0d8f5d99..f4b521356f 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -58,6 +58,7 @@
%%% Properties:
prop_seq(Config) ->
+ error_logger:tty(false),
{ok,Pid} = ssh_eqc_event_handler:add_report_handler(),
{_, _, Port} = init_daemon(Config),
numtests(1000,
@@ -66,16 +67,25 @@ prop_seq(Config) ->
send_bad_sequence(Port, Delay, Pid),
not any_relevant_error_report(Pid)
catch
- C:E -> io:format('~p:~p~n',[C,E]),
+ C:E:S -> ct:log("~p:~p~n~p",[C,E,S]),
false
end
)).
send_bad_sequence(Port, Delay, Pid) ->
- {ok,S} = gen_tcp:connect("localhost",Port,[]),
- gen_tcp:send(S,"Illegal info-string\r\n"),
- ssh_test_lib:sleep_microsec(Delay),
- gen_tcp:close(S).
+ send_bad_sequence(Port, Delay, Pid, 10).
+
+send_bad_sequence(Port, Delay, Pid, N) ->
+ case gen_tcp:connect("localhost",Port,[]) of
+ {ok,S} ->
+ gen_tcp:send(S,"Illegal info-string\r\n"),
+ ssh_test_lib:sleep_microsec(Delay),
+ gen_tcp:close(S);
+
+ {error,econnreset} when N>0 ->
+ timer:sleep(1),
+ send_bad_sequence(Port, Delay, Pid, N-1)
+ end.
any_relevant_error_report(Pid) ->
{ok, Reports} = ssh_eqc_event_handler:get_reports(Pid),
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_server.erl b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
index 39d0b4e410..acb0faa0c7 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_server.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
@@ -22,25 +22,27 @@
-module(ssh_eqc_client_server).
-compile(export_all).
+
+-proptest([proper]).
--include_lib("common_test/include/ct.hrl").
-
--ifdef(PROPER).
-%% Proper is not supported.
--else.
--ifdef(TRIQ).
-%% Proper is not supported.
+-ifndef(PROPER).
-else.
+%% Only use proper
+%%
+%% Previously only EQC was supported, but the changes to support PROPER is not
+%% just a wrapper. Since we do not have access to eqc we can't test the changes
+%% so therefore eqc is disabeled.
+%% However, with access to eqc it ought to be quite easy to re-enable eqc by
+%% studying the diff.
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-include_lib("common_test/include/ct.hrl").
%% Limit the testing time on CI server... this needs to be improved in % from total budget.
-define(TESTINGTIME(Prop), eqc:testing_time(30,Prop)).
-
--include_lib("eqc/include/eqc.hrl").
--include_lib("eqc/include/eqc_statem.hrl").
--eqc_group_commands(true).
-
-define(SSH_DIR,"ssh_eqc_client_server_dirs").
-define(sec, *1000).
@@ -51,10 +53,6 @@
port
}).
--record(conn,{ref,
- srvr_ref
- }).
-
-record(chan, {ref,
conn_ref,
subsystem,
@@ -65,7 +63,7 @@
initialized = false,
servers = [], % [#srvr{}]
clients = [],
- connections = [], % [#conn{}]
+ connections = [],
channels = [], % [#chan{}]
data_dir
}).
@@ -80,9 +78,8 @@
-define(SUBSYSTEMS, ["echo1", "echo2", "echo3", "echo4"]).
--define(SERVER_ADDRESS, { {127,1,0,choose(1,254)}, % IP
- choose(1024,65535) % Port
- }).
+-define(SERVER_ADDRESS, {127,0,0,1}). % Server listening IP. Darwin, Solaris & FreeBSD
+ % dislikes all other in 127.0.0.0/24
-define(SERVER_EXTRA_OPTIONS, [{parallel_login,bool()}] ).
@@ -104,10 +101,12 @@
%% To be called as eqc:quickcheck( ssh_eqc_client_server:prop_seq() ).
prop_seq() ->
- ?TESTINGTIME(do_prop_seq(?SSH_DIR)).
+ error_logger:tty(false),
+ ?TESTINGTIME(do_prop_seq(?SSH_DIR)).
%% To be called from a common_test test suite
prop_seq(CT_Config) ->
+ error_logger:tty(false),
do_prop_seq(full_path(?SSH_DIR, CT_Config)).
@@ -124,10 +123,12 @@ full_path(SSHdir, CT_Config) ->
SSHdir).
%%%----
prop_parallel() ->
+ error_logger:tty(false),
?TESTINGTIME(do_prop_parallel(?SSH_DIR)).
%% To be called from a common_test test suite
prop_parallel(CT_Config) ->
+ error_logger:tty(false),
do_prop_parallel(full_path(?SSH_DIR, CT_Config)).
do_prop_parallel(DataDir) ->
@@ -139,22 +140,22 @@ do_prop_parallel(DataDir) ->
end).
%%%----
-prop_parallel_multi() ->
- ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR)).
-
-%% To be called from a common_test test suite
-prop_parallel_multi(CT_Config) ->
- do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config)).
-
-do_prop_parallel_multi(DataDir) ->
- setup_rsa(DataDir),
- ?FORALL(Repetitions,?SHRINK(1,[10]),
- ?FORALL(Cmds,parallel_commands(?MODULE),
- ?ALWAYS(Repetitions,
- begin
- {H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
- present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
- end))).
+%% prop_parallel_multi() ->
+%% ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR)).
+
+%% %% To be called from a common_test test suite
+%% prop_parallel_multi(CT_Config) ->
+%% do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config)).
+
+%% do_prop_parallel_multi(DataDir) ->
+%% setup_rsa(DataDir),
+%% ?FORALL(Repetitions,?SHRINK(1,[10]),
+%% ?FORALL(Cmds,parallel_commands(?MODULE),
+%% ?ALWAYS(Repetitions,
+%% begin
+%% {H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
+%% present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
+%% end))).
%%%================================================================
%%% State machine spec
@@ -169,13 +170,50 @@ initial_state(DataDir) ->
ssh:start().
%%%----------------
-weight(S, ssh_send) -> 5*length([C || C<-S#state.channels, has_subsyst(C)]);
-weight(S, ssh_start_subsyst) -> 3*length([C || C<-S#state.channels, no_subsyst(C)]);
+weight(S, ssh_send) -> 20*length([C || C<-S#state.channels, has_subsyst(C)]);
+weight(S, ssh_start_subsyst) -> 10*length([C || C<-S#state.channels, no_subsyst(C)]);
weight(S, ssh_close_channel) -> 2*length([C || C<-S#state.channels, has_subsyst(C)]);
-weight(S, ssh_open_channel) -> length(S#state.connections);
+weight(S, ssh_open_channel) -> 2*length(S#state.connections);
weight(_S, _) -> 1.
%%%----------------
+fns() -> [initial_state,
+ ssh_server,
+ ssh_client,
+ ssh_open_connection,
+ ssh_close_connection,
+ ssh_open_channel,
+ ssh_close_channel,
+ ssh_start_subsyst,
+ ssh_send
+ ].
+
+call_f(Name, Sfx) ->
+ case get({Name,Sfx}) of
+ undefined -> F = list_to_atom(lists:concat([Name,"_",Sfx])),
+ put({Name,Sfx}, F),
+ F;
+ F when is_atom(F) -> F
+ end.
+
+-define(call(Name, What, Args), apply(?MODULE, call_f(Name,What), Args)).
+
+symbolic_call(S,Name) -> {call, ?MODULE, Name, ?call(Name,args,[S])}.
+
+may_generate(S, F) -> ?call(F,pre,[S]).
+
+command(S) ->
+ frequency([{weight(S,F), symbolic_call(S,F)} || F <- fns(),
+ may_generate(S, F)]
+ ).
+
+precondition(S, {call,_M,F,As}) -> try ?call(F, pre, [S,As])
+ catch _:undef -> try ?call(F,pre,[S]) catch _:undef -> true end
+ end.
+next_state(S, Res, {call,_M,F,As}) -> try ?call(F, next, [S,Res,As]) catch _:undef -> S end.
+postcondition(S, {call,_M,F,As}, Res) -> try ?call(F, post, [S,As,Res]) catch _:undef -> true end.
+
+%%%----------------
%%% Initialize
initial_state_pre(S) -> not S#state.initialized.
@@ -200,24 +238,34 @@ ssh_server_pre(S) -> S#state.initialized andalso
ssh_server_args(_) -> [?SERVER_ADDRESS, {var,data_dir}, ?SERVER_EXTRA_OPTIONS].
-ssh_server({IP,Port}, DataDir, ExtraOptions) ->
- ok(ssh:daemon(IP, Port,
- [
- {system_dir, system_dir(DataDir)},
- {user_dir, user_dir(DataDir)},
- {subsystems, [{SS, {ssh_eqc_subsys, [SS]}} || SS <- ?SUBSYSTEMS]}
- | ExtraOptions
- ])).
-
-ssh_server_post(_S, _Args, {error,eaddrinuse}) -> true;
-ssh_server_post(_S, _Args, Result) -> is_ok(Result).
-
-ssh_server_next(S, {error,eaddrinuse}, _) -> S;
-ssh_server_next(S, Result, [{IP,Port},_,_]) ->
- S#state{servers=[#srvr{ref = Result,
- address = IP,
- port = Port}
- | S#state.servers]}.
+ssh_server(IP0, DataDir, ExtraOptions) ->
+ case ssh:daemon(IP0, 0,
+ [
+ {system_dir, system_dir(DataDir)},
+ {user_dir, user_dir(DataDir)},
+ {subsystems, [{SS, {ssh_eqc_subsys, [SS]}} || SS <- ?SUBSYSTEMS]}
+ | ExtraOptions
+ ]) of
+ {ok,DaemonRef} ->
+ case ssh:daemon_info(DaemonRef) of
+ {ok, Props} ->
+ Port = proplists:get_value(port,Props),
+ IP = proplists:get_value(ip,Props),
+ #srvr{ref = DaemonRef,
+ address = IP,
+ port = Port};
+ Other ->
+ Other
+ end;
+ Other ->
+ Other
+ end.
+
+ssh_server_post(_S, _Args, #srvr{port=Port}) -> (0 < Port) andalso (Port < 65536);
+ssh_server_post(_S, _Args, _) -> false.
+
+ssh_server_next(S, Srvr, _) ->
+ S#state{servers=[Srvr | S#state.servers]}.
%%%----------------
%%% Start a new client
@@ -271,8 +319,7 @@ ssh_open_connection(#srvr{address=Ip, port=Port}, DataDir) ->
ssh_open_connection_post(_S, _Args, Result) -> is_ok(Result).
-ssh_open_connection_next(S, ConnRef, [#srvr{ref=SrvrRef},_]) ->
- S#state{connections=[#conn{ref=ConnRef, srvr_ref=SrvrRef}|S#state.connections]}.
+ssh_open_connection_next(S, ConnRef, [_,_]) -> S#state{connections=[ConnRef|S#state.connections]}.
%%%----------------
%%% Stop a new connection
@@ -282,12 +329,12 @@ ssh_close_connection_pre(S) -> S#state.connections /= [].
ssh_close_connection_args(S) -> [oneof(S#state.connections)].
-ssh_close_connection(#conn{ref=ConnectionRef}) -> ssh:close(ConnectionRef).
+ssh_close_connection(ConnectionRef) -> ssh:close(ConnectionRef).
-ssh_close_connection_next(S, _, [Conn=#conn{ref=ConnRef}]) ->
- S#state{connections = S#state.connections--[Conn],
- channels = [C || C <- S#state.channels,
- C#chan.conn_ref /= ConnRef]
+ssh_close_connection_next(S, _, [ConnRef]) ->
+ S#state{connections = S#state.connections--[ConnRef],
+ channels = [C || C <- S#state.channels,
+ C#chan.conn_ref /= ConnRef]
}.
%%%----------------
@@ -299,14 +346,14 @@ ssh_open_channel_pre(S) -> S#state.connections /= [].
ssh_open_channel_args(S) -> [oneof(S#state.connections)].
%%% For re-arrangement in parallel tests.
-ssh_open_channel_pre(S,[C]) -> lists:member(C,S#state.connections).
+ssh_open_channel_pre(S,[C]) when is_record(S,state) -> lists:member(C,S#state.connections).
-ssh_open_channel(#conn{ref=ConnectionRef}) ->
+ssh_open_channel(ConnectionRef) ->
ok(ssh_connection:session_channel(ConnectionRef, 20?sec)).
ssh_open_channel_post(_S, _Args, Result) -> is_ok(Result).
-ssh_open_channel_next(S, ChannelRef, [#conn{ref=ConnRef}]) ->
+ssh_open_channel_next(S, ChannelRef, [ConnRef]) ->
S#state{channels=[#chan{ref=ChannelRef,
conn_ref=ConnRef}
| S#state.channels]}.
@@ -326,9 +373,7 @@ ssh_close_channel_next(S, _, [C]) ->
S#state{channels = [Ci || Ci <- S#state.channels,
sig(C) /= sig(Ci)]}.
-
sig(C) -> {C#chan.ref, C#chan.conn_ref}.
-
%%%----------------
%%% Start a sub system on a channel
@@ -361,9 +406,10 @@ ssh_start_subsyst_next(S, _Result, [C,SS,Pid|_]) ->
ssh_send_pre(S) -> lists:any(fun has_subsyst/1, S#state.channels).
-ssh_send_args(S) -> [oneof(lists:filter(fun has_subsyst/1, S#state.channels)),
- choose(0,1),
- message()].
+ssh_send_args(S) ->
+ [oneof(lists:filter(fun has_subsyst/1, S#state.channels)),
+ choose(0,1),
+ message()].
%% For re-arrangement in parallel tests.
ssh_send_pre(S, [C|_]) -> lists:member(C, S#state.channels).
@@ -388,17 +434,17 @@ ssh_send(C=#chan{conn_ref=ConnectionRef, ref=ChannelRef, client_pid=Pid}, Type,
end).
ssh_send_blocking(_S, _Args) ->
- true.
+ true.
ssh_send_post(_S, [C,_,Msg], Response) when is_binary(Response) ->
- Expected = ssh_eqc_subsys:response(modify_msg(C,Msg), C#chan.subsystem),
+ Expected = ssh_eqc_subsys:response(modify_msg(C,Msg), C#chan.subsystem),
case Response of
Expected -> true;
_ -> {send_failed, size(Response), size(Expected)}
end;
ssh_send_post(_S, _Args, Response) ->
- {error,Response}.
+ {error,Response}.
modify_msg(_, <<>>) -> <<>>;
@@ -440,7 +486,11 @@ present_result(_Module, Cmds, _Triple, true) ->
true)))));
present_result(Module, Cmds, Triple, false) ->
- pretty_commands(Module, Cmds, Triple, [{show_states,true}], false).
+ pretty_comands(Module, Cmds, Triple, [{show_states,true}], false),
+ false. % Proper dislikes non-boolean results while eqc treats non-true as false.
+
+pretty_comands(Module, Cmds, Triple, Opts, Bool) ->
+ ct:log("Module = ~p,~n Cmds = ~p,~n Triple = ~p,~n Opts = ~p,~n Bool = ~p",[Module, Cmds, Triple, Opts, Bool]).
@@ -476,23 +526,35 @@ traverse_commands(Fseq, Fpar, {Seq, ParLs}) -> lists:append([Fseq(Seq)|Fpar(ParL
print_frequencies() -> print_frequencies(10).
print_frequencies(Ngroups) -> fun([]) -> io:format('Empty list!~n',[]);
- (L ) -> print_frequencies(L,Ngroups,0,element(1,lists:last(L)))
+ (L ) ->
+ try
+ M = lists:last(L),
+ Max = if is_integer(M) -> M;
+ is_tuple(M) -> element(1,L)
+ end,
+ print_frequencies(L,Ngroups,0,Max)
+ catch
+ C:E:S ->
+ ct:pal("~p:~p ~p:~p~n~p~n~p",[?MODULE,?LINE,C,E,S,L])
+ end
end.
+
print_frequencies(Ngroups, MaxValue) -> fun(L) -> print_frequencies(L,Ngroups,0,MaxValue) end.
print_frequencies(L, N, Min, Max) when N>Max -> print_frequencies(L++[{N,0}], N, Min, N);
-print_frequencies(L, N, Min, Max) ->
-%%io:format('L=~p~n',[L]),
+print_frequencies(L, N, Min, Max0) ->
try
+ Interval = round((Max0-Min)/N),
+ Max = Max0 + (Max0 rem Interval),
IntervalUpperLimits =
lists:reverse(
- [Max | tl(lists:reverse(lists:seq(Min,Max,round((Max-Min)/N))))]
+ [Max | tl(lists:reverse(lists:seq(Min,Max,Interval)))]
),
{Acc0,_} = lists:mapfoldl(fun(Upper,Lower) ->
{{{Lower,Upper},0}, Upper+1}
end, hd(IntervalUpperLimits), tl(IntervalUpperLimits)),
- Fs0 = get_frequencies(L, Acc0),
+ Fs0 = get_frequencies(L, Acc0),
SumVal = lists:sum([V||{_,V}<-Fs0]),
Fs = with_percentage(Fs0, SumVal),
Mean = mean(L),
@@ -517,7 +579,6 @@ print_frequencies(L, N, Min, Max) ->
|| {Interval={Rlow,Rhigh},Val,Percent} <- Fs],
io:format('~*c ~*c~n',[2*Npos_range,32,Npos_value+2,$-]),
io:format('~*c ~*w~n',[2*Npos_range,32,Npos_value,SumVal])
- %%,io:format('L=~p~n',[L])
catch
C:E ->
io:format('*** Faild printing (~p:~p) for~n~p~n',[C,E,L])
@@ -527,6 +588,8 @@ get_frequencies([{I,Num}|T], [{{Lower,Upper},Cnt}|Acc]) when Lower=<I,I=<Upper -
get_frequencies(T, [{{Lower,Upper},Cnt+Num}|Acc]);
get_frequencies(L=[{I,_Num}|_], [Ah={{_Lower,Upper},_Cnt}|Acc]) when I>Upper ->
[Ah | get_frequencies(L,Acc)];
+get_frequencies([I|T], Acc) when is_integer(I) ->
+ get_frequencies([{I,1}|T], Acc);
get_frequencies([], Acc) ->
Acc.
@@ -616,4 +679,3 @@ erase_dir(Dir) ->
file:del_dir(Dir).
-endif.
--endif.
diff --git a/lib/ssh/test/ssh_bench_SUITE.erl b/lib/ssh/test/ssh_bench_SUITE.erl
index b6c6147646..764c52b624 100644
--- a/lib/ssh/test/ssh_bench_SUITE.erl
+++ b/lib/ssh/test/ssh_bench_SUITE.erl
@@ -1,7 +1,7 @@
%%%-------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -65,10 +65,10 @@ init_per_suite(Config) ->
{preferred_algorithms, Algs},
{modify_algorithms,[{prepend,[{cipher,[none]},
{mac,[none]}
- ]},
- {rm, [{cipher,['[email protected]',
- ]}
+ ]}
+ %% ,{rm, [{cipher,['[email protected]',
+ %% ]}
]},
{max_random_length_padding, 0},
{subsystems, [{"/dev/null", {ssh_bench_dev_null,[DataSize]}}]}
@@ -152,7 +152,8 @@ transfer_text(Config) ->
|| {Crypto,Mac} <- [{ none, none},
{'aes128-ctr', 'hmac-sha1'},
{'aes256-ctr', 'hmac-sha1'},
-%% {'[email protected]', 'hmac-sha1'},
+{'[email protected]', 'hmac-sha1'},
+{'[email protected]', 'hmac-sha1'},
{'aes128-cbc', 'hmac-sha1'},
{'3des-cbc', 'hmac-sha1'},
{'aes128-ctr', 'hmac-sha2-256'},
@@ -182,29 +183,31 @@ gen_data(DataSz) ->
%% {suite, ?MODULE},
%% {name, mk_name(["Transfer 1M bytes ",Cipher,"/",Mac," [µs]"])}]);
connect_measure(Port, Cipher, Mac, Data, Options) ->
- AES_GCM = {cipher,['[email protected]',
+ AES_GCM = {cipher,
+ []},
AlgOpt = case {Cipher,Mac} of
{none,none} ->
[{modify_algorithms,[{prepend, [{cipher,[Cipher]},
- {mac,[Mac]}]},
- {rm,[AES_GCM]}
+ {mac,[Mac]}]}
+%%% ,{rm,[AES_GCM]}
]}];
{none,_} ->
- [{modify_algorithms,[{prepend, [{cipher,[Cipher]}]},
- {rm,[AES_GCM]}
+ [{modify_algorithms,[{prepend, [{cipher,[Cipher]}]}
+%%% ,{rm,[AES_GCM]}
]},
{preferred_algorithms, [{mac,[Mac]}]}];
{_,none} ->
- [{modify_algorithms,[{prepend, [{mac,[Mac]}]},
- {rm,[AES_GCM]}
+ [{modify_algorithms,[{prepend, [{mac,[Mac]}]}
+%%% ,{rm,[AES_GCM]}
]},
{preferred_algorithms, [{cipher,[Cipher]}]}];
_ ->
[{preferred_algorithms, [{cipher,[Cipher]},
- {mac,[Mac]}]},
- {modify_algorithms, [{rm,[AES_GCM]}]}
+ {mac,[Mac]}]}
+%%% ,{modify_algorithms, [{rm,[AES_GCM]}]}
]
end,
Times =
diff --git a/lib/ssh/test/ssh_dbg_SUITE.erl b/lib/ssh/test/ssh_dbg_SUITE.erl
index 5439817d10..ab7918fa90 100644
--- a/lib/ssh/test/ssh_dbg_SUITE.erl
+++ b/lib/ssh/test/ssh_dbg_SUITE.erl
@@ -38,11 +38,20 @@ suite() ->
{timetrap,{seconds,60}}].
all() ->
- [basic,
- dbg_alg_terminate,
- dbg_ssh_messages,
- dbg_connections,
- dbg_channels
+ [{group, dbg},
+ {group, circ_buf}
+ ].
+
+groups() ->
+ [{dbg, [], [dbg_basic,
+ dbg_alg_terminate,
+ dbg_ssh_messages,
+ dbg_connections,
+ dbg_channels]},
+ {circ_buf, [], [cb_basic,
+ cb_print,
+ cb_macros_print
+ ]}
].
%%--------------------------------------------------------------------
@@ -82,7 +91,7 @@ end_per_testcase(_TC, Config) ->
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-basic(_Config) ->
+dbg_basic(_Config) ->
L0 = ssh_dbg:start(),
true = is_pid(whereis(ssh_dbg)),
true = is_list(L0),
@@ -342,6 +351,53 @@ dbg_channels(Config) ->
stop_and_fail_if_unhandled_dbg_msgs(Ref, [C,D], Pid).
%%--------------------------------------------------------------------
+cb_basic(_Config) ->
+ %% Check that the circular buffer is disabled at start:
+ [] = ssh_dbg:cbuf_list(),
+ disabled = ssh_dbg:cbuf_in(anything),
+ [] = ssh_dbg:cbuf_list(),
+ %% Start it and enter three values, first is duplicated;
+ ok = ssh_dbg:cbuf_start(3),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v1),
+ ok = ssh_dbg:cbuf_in(v2),
+ ok = ssh_dbg:cbuf_in(v3),
+ [{v3,_,1}, {v2,_,1}, {v1,_,2}] = ssh_dbg:cbuf_list(),
+ %% Check that a fourth value erase the first entered:
+ ok = ssh_dbg:cbuf_in(v4),
+ [{v4,_,1}, {v3,_,1}, {v2,_,1}] = ssh_dbg:cbuf_list(),
+ %% Check that entering a value that is in the tail but not in the head is treated as a new value:
+ ok = ssh_dbg:cbuf_in(v2),
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_list(),
+ %% Stop and check that the buffer is returned:
+ [{v2,_,1}, {v4,_,1}, {v3,_,1}] = ssh_dbg:cbuf_stop_clear(),
+ %% Stopping a stopped buffer returns empty:
+ [] = ssh_dbg:cbuf_stop_clear(),
+ %% Check that a value can't be entered in a stopped buffer:
+ disabled = ssh_dbg:cbuf_in(v2).
+
+%%--------------------------------------------------------------------
+cb_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ ssh_dbg:cbuf_in(V),
+ ct:log("Enter ~p",[V])
+ end || V <- lists:seq(1,10)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
+cb_macros_print(_Config) ->
+ ssh_dbg:cbuf_start(),
+ [begin
+ V = {test,V0},
+ ?CIRC_BUF_IN(V),
+ ct:log("Enter ~p",[V])
+ end || V0 <- lists:seq(1,5)],
+ ct:log("~s",[ssh_dbg:fmt_cbuf_items()]),
+ ssh_dbg:cbuf_stop_clear().
+
+%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_property_test_SUITE.erl b/lib/ssh/test/ssh_property_test_SUITE.erl
index 3318b86d39..9aaac898a0 100644
--- a/lib/ssh/test/ssh_property_test_SUITE.erl
+++ b/lib/ssh/test/ssh_property_test_SUITE.erl
@@ -46,8 +46,9 @@ groups() ->
[{messages, [], [decode,
decode_encode]},
{client_server, [], [client_server_sequential,
- client_server_parallel,
- client_server_parallel_multi]}
+ client_server_parallel
+ %% client_server_parallel_multi
+ ]}
].
@@ -62,7 +63,7 @@ end_per_suite(Config) ->
%%% if we run proper.
init_per_group(client_server, Config) ->
case proplists:get_value(property_test_tool,Config) of
- eqc -> Config;
+ proper -> Config;
X -> {skip, lists:concat([X," is not supported"])}
end;
init_per_group(_, Config) ->
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index c3572b5b70..ae7b4cf3f2 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.7
+SSH_VSN = 4.7.1
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index d459463322..c72b6d6cc4 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2017. All Rights Reserved.
+# Copyright Ericsson AB 1999-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 917df03b5b..d117641496 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,169 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.0.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct alert handling with new TLS sender process, from
+ ssl-9.0.2. CLOSE ALERTS could under some circumstances be
+ encoded using an incorrect cipher state. This would cause
+ the peer to regard them as unknown messages.</p>
+ <p>
+ Own Id: OTP-15337 Aux Id: ERL-738 </p>
+ </item>
+ <item>
+ <p>
+ Correct handling of socket packet option with new TLS
+ sender process, from ssl-9.0.2. When changing the socket
+ option {packet, 1|2|3|4} with ssl:setopts/2 the option
+ must internally be propagated to the sender process as
+ well as the reader process as this particular option also
+ affects the data to be sent.</p>
+ <p>
+ Own Id: OTP-15348 Aux Id: ERL-747 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Use separate processes for sending and receiving
+ application data for TLS connections to avoid potential
+ deadlock that was most likely to occur when using TLS for
+ Erlang distribution. Note does not change the API.</p>
+ <p>
+ Own Id: OTP-15122</p>
+ </item>
+ <item>
+ <p>
+ Correct handling of empty server SNI extension</p>
+ <p>
+ Own Id: OTP-15168</p>
+ </item>
+ <item>
+ <p>
+ Correct PSK cipher suite handling and add
+ selected_cipher_suite to connection information</p>
+ <p>
+ Own Id: OTP-15172</p>
+ </item>
+ <item>
+ <p>
+ Adopt to the fact that cipher suite sign restriction are
+ relaxed in TLS-1.2</p>
+ <p>
+ Own Id: OTP-15173</p>
+ </item>
+ <item>
+ <p>
+ Enhance error handling of non existing PEM files</p>
+ <p>
+ Own Id: OTP-15174</p>
+ </item>
+ <item>
+ <p>
+ Correct close handling of transport accepted sockets in
+ the error state</p>
+ <p>
+ Own Id: OTP-15216</p>
+ </item>
+ <item>
+ <p>
+ Correct PEM cache to not add references to empty entries
+ when PEM file does not exist.</p>
+ <p>
+ Own Id: OTP-15224</p>
+ </item>
+ <item>
+ <p>
+ Correct handling of all PSK cipher suites</p>
+ <p>
+ Before only some PSK suites would be correctly negotiated
+ and most PSK ciphers suites would fail the connection.</p>
+ <p>
+ Own Id: OTP-15285</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ TLS will now try to order certificate chains if they
+ appear to be unordered. That is prior to TLS 1.3,
+ “certificate_list” ordering was required to be
+ strict, however some implementations already allowed for
+ some flexibility. For maximum compatibility, all
+ implementations SHOULD be prepared to handle potentially
+ extraneous certificates and arbitrary orderings from any
+ TLS version.</p>
+ <p>
+ Own Id: OTP-12983</p>
+ </item>
+ <item>
+ <p>
+ TLS will now try to reconstructed an incomplete
+ certificate chains from its local CA-database and use
+ that data for the certificate path validation. This
+ especially makes sense for partial chains as then the
+ peer might not send an intermediate CA as it is
+ considered the trusted root in that case.</p>
+ <p>
+ Own Id: OTP-15060</p>
+ </item>
+ <item>
+ <p>
+ Option keyfile defaults to certfile and should be trumped
+ with key. This failed for engine keys.</p>
+ <p>
+ Own Id: OTP-15193</p>
+ </item>
+ <item>
+ <p>
+ Error message improvement when own certificate has
+ decoding issues, see also issue ERL-668.</p>
+ <p>
+ Own Id: OTP-15234</p>
+ </item>
+ <item>
+ <p>
+ Correct dialyzer spec for key option</p>
+ <p>
+ Own Id: OTP-15281</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct cipher suite handling for ECDHE_*, the incorrect
+ handling could cause an incorrrect suite to be selected
+ and most likly fail the handshake.</p>
+ <p>
+ Own Id: OTP-15203</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.0</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -170,6 +333,58 @@
</section>
+<section><title>SSL 8.2.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Correct handling of empty server SNI extension</p>
+ <p>
+ Own Id: OTP-15168</p>
+ </item>
+ <item>
+ <p>
+ Correct cipher suite handling for ECDHE_*, the incorrect
+ handling could cause an incorrrect suite to be selected
+ and most likly fail the handshake.</p>
+ <p>
+ Own Id: OTP-15203</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 8.2.6.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improve cipher suite handling correcting ECC and TLS-1.2
+ requierments. Backport of solution for ERL-641</p>
+ <p>
+ Own Id: OTP-15178</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Option keyfile defaults to certfile and should be trumped
+ with key. This failed for engine keys.</p>
+ <p>
+ Own Id: OTP-15193</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 8.2.6</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -339,7 +554,7 @@
<p>
TLS sessions must be registered with SNI if provided, so
that sessions where client hostname verification would
- fail can not connect reusing a session created when the
+ fail cannot connect reusing a session created when the
server name verification succeeded.</p>
<p>
Own Id: OTP-14632</p>
@@ -517,7 +732,7 @@
public_key:pkix_verify_hostname/2 to verify the hostname
of the connection with the server certificates specified
hostname during certificate path validation. The user may
- explicitly disables it. Also if the hostname can not be
+ explicitly disables it. Also if the hostname cannot be
derived from the first argument to connect or is not
supplied by the server name indication option, the check
will not be performed.</p>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 7ce682e28c..ef99ace351 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -200,16 +200,33 @@
| sect163r1 | sect163r2 | secp160k1 | secp160r1 | secp160r2</c></p></item>
<tag><c>hello_extensions() =</c></tag>
- <item><p><c>#{renegotiation_info =>
+ <item><p><c>#{renegotiation_info => binary() | undefined,
signature_algs => [{hash(), ecsda| rsa| dsa}] | undefined
alpn => binary() | undefined,
- next_protocol_negotiation,
+ next_protocol_negotiation => binary() | undefined,
srp => string() | undefined,
- ec_point_formats ,
- elliptic_curves = [oid] | undefined
- sni = string()}
+ ec_point_formats => list() | undefined,
+ elliptic_curves => [oid] | undefined,
+ sni => string() | undefined}
}</c></p></item>
-
+
+ <tag><c>signature_scheme() =</c></tag>
+ <item>
+ <p><c>rsa_pkcs1_sha256</c></p>
+ <p><c>| rsa_pkcs1_sha384</c></p>
+ <p><c>| rsa_pkcs1_sha512</c></p>
+ <p><c>| ecdsa_secp256r1_sha256</c></p>
+ <p><c>| ecdsa_secp384r1_sha384</c></p>
+ <p><c>| ecdsa_secp521r1_sha512</c></p>
+ <p><c>| rsa_pss_rsae_sha256</c></p>
+ <p><c>| rsa_pss_rsae_sha384</c></p>
+ <p><c>| rsa_pss_rsae_sha512</c></p>
+ <p><c>| rsa_pss_pss_sha256</c></p>
+ <p><c>| rsa_pss_pss_sha384</c></p>
+ <p><c>| rsa_pss_pss_sha512</c></p>
+ <p><c>| rsa_pkcs1_sha1</c></p>
+ <p><c>| ecdsa_sha1</c></p>
+ </item>
</taglist>
</section>
@@ -410,7 +427,7 @@ marker="public_key:public_key#pkix_path_validation-3">public_key:pkix_path_valid
<item>check is only performed on the peer certificate.</item>
<tag><c>best_effort</c></tag>
- <item>if certificate revocation status can not be determined
+ <item>if certificate revocation status cannot be determined
it will be accepted as valid.</item>
</taglist>
@@ -709,6 +726,26 @@ fun(srp, Username :: string(), UserState :: term()) ->
that may be selected. Default support for {md5, rsa} removed in ssl-8.0
</p>
</item>
+ <tag><marker id="signature_algs_cert"/><c>{signature_algs_cert, [signature_scheme()]}</c></tag>
+ <item>
+ <p>
+ In addition to the signature_algorithms extension from TLS 1.2,
+ <url href="http://www.ietf.org/rfc/rfc8446.txt#section-4.2.3">TLS 1.3
+ (RFC 5246 Section 4.2.3)</url>adds the signature_algorithms_cert extension
+ which enables having special requirements on the signatures used in the
+ certificates that differs from the requirements on digital signatures as a whole.
+ If this is not required this extension is not needed.
+ </p>
+ <p>
+ The client will send a signature_algorithms_cert extension (ClientHello),
+ if TLS version 1.3 or later is used, and the signature_algs_cert option is
+ explicitly specified. By default, only the signature_algs extension is sent.
+ </p>
+ <p>
+ The signature schemes shall be ordered according to the client's preference
+ (favorite choice first).
+ </p>
+ </item>
</taglist>
</section>
@@ -860,7 +897,6 @@ fun(srp, Username :: string(), UserState :: term()) ->
negotiation, introduced in TLS-1.2. The algorithms will also be offered to the client if a
client certificate is requested. For more details see the <seealso marker="#client_signature_algs">corresponding client option</seealso>.
</p> </item>
-
</taglist>
</section>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index e14f3f90dc..1774bd8f77 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -191,7 +191,7 @@ Eshell V5.0 (abort with ^G)
Any available SSL/TLS option can be specified in an options file,
but note that options that take a <c>fun()</c> has to use
the syntax <c>fun Mod:Func/Arity</c> since a function
- body can not be compiled when consulting a file.
+ body cannot be compiled when consulting a file.
</p>
<p>
Do not tamper with the socket options
diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl
index c150f43bff..8d68da12d5 100644
--- a/lib/ssl/examples/src/client_server.erl
+++ b/lib/ssl/examples/src/client_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -39,15 +39,15 @@ start() ->
%% Accept
{ok, ASock} = ssl:transport_accept(LSock),
- ok = ssl:ssl_accept(ASock),
+ {ok, SslSocket} = ssl:handshake(ASock),
io:fwrite("Accept: accepted.~n"),
- {ok, Cert} = ssl:peercert(ASock),
+ {ok, Cert} = ssl:peercert(SslSocket),
io:fwrite("Accept: peer cert:~n~p~n", [public_key:pkix_decode_cert(Cert, otp)]),
io:fwrite("Accept: sending \"hello\".~n"),
- ssl:send(ASock, "hello"),
- {error, closed} = ssl:recv(ASock, 0),
+ ssl:send(SslSocket, "hello"),
+ {error, closed} = ssl:recv(SslSocket, 0),
io:fwrite("Accept: detected closed.~n"),
- ssl:close(ASock),
+ ssl:close(SslSocket),
io:fwrite("Listen: closing and terminating.~n"),
ssl:close(LSock),
@@ -75,7 +75,7 @@ mk_opts(Role) ->
[{active, false},
{verify, 2},
{depth, 2},
+ {server_name_indication, disable},
{cacertfile, filename:join([Dir, Role, "cacerts.pem"])},
{certfile, filename:join([Dir, Role, "cert.pem"])},
{keyfile, filename:join([Dir, Role, "key.pem"])}].
-
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 1db18d4e5a..d4cb5350d1 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -44,8 +44,6 @@ BEHAVIOUR_MODULES= \
MODULES= \
ssl \
- tls \
- dtls \
ssl_alert \
ssl_app \
ssl_sup \
@@ -64,12 +62,15 @@ MODULES= \
ssl_certificate\
ssl_pkix_db\
ssl_cipher \
+ ssl_cipher_format \
ssl_srp_primes \
tls_connection \
dtls_connection \
+ tls_sender\
ssl_config \
ssl_connection \
tls_handshake \
+ tls_handshake_1_3\
dtls_handshake\
ssl_handshake\
ssl_manager \
@@ -82,6 +83,7 @@ MODULES= \
tls_socket \
dtls_socket \
tls_record \
+ tls_record_1_3\
dtls_record \
ssl_record \
ssl_v3 \
@@ -92,8 +94,9 @@ MODULES= \
INTERNAL_HRL_FILES = \
ssl_alert.hrl ssl_cipher.hrl \
tls_connection.hrl dtls_connection.hrl ssl_connection.hrl \
- ssl_handshake.hrl tls_handshake.hrl dtls_handshake.hrl ssl_api.hrl ssl_internal.hrl \
- ssl_record.hrl tls_record.hrl dtls_record.hrl ssl_srp.hrl
+ ssl_handshake.hrl tls_handshake.hrl tls_handshake_1_3.hrl dtls_handshake.hrl \
+ ssl_api.hrl ssl_internal.hrl \
+ ssl_record.hrl tls_record.hrl tls_record_1_3.hrl dtls_record.hrl ssl_srp.hrl
ERL_FILES= \
$(MODULES:%=%.erl) \
@@ -170,6 +173,7 @@ $(EBIN)/tls_connection.$(EMULATOR): ssl_internal.hrl tls_connection.hrl tls_reco
$(EBIN)/dtls_connection.$(EMULATOR): ssl_internal.hrl dtls_connection.hrl dtls_record.hrl ssl_cipher.hrl dtls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl tls_record.hrl ssl_cipher.hrl tls_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
$(EBIN)/tls_handshake.$(EMULATOR): ssl_internal.hrl ssl_connection.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl ../../public_key/include/public_key.hrl
+$(EBIN)/tls_handshake_1_3.$(EMULATOR): tls_handshake_1_3.hrl tls_handshake.hrl ssl_internal.hrl
$(EBIN)/ssl_manager.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl ../../kernel/include/file.hrl
$(EBIN)/ssl_record.$(EMULATOR): ssl_internal.hrl ssl_record.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_alert.hrl
$(EBIN)/ssl_session.$(EMULATOR): ssl_internal.hrl ssl_handshake.hrl
diff --git a/lib/ssl/src/dtls.erl b/lib/ssl/src/dtls.erl
deleted file mode 100644
index cd705152a8..0000000000
--- a/lib/ssl/src/dtls.erl
+++ /dev/null
@@ -1,113 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : Reflect DTLS specific API options (fairly simple wrapper at the moment)
-%% First implementation will support DTLS connections only in a "TLS/TCP like way"
-
--module(dtls).
-
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
-
--export([connect/2, connect/3, listen/2, accept/1, accept/2,
- handshake/1, handshake/2, handshake/3]).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Connect to a DTLS server.
-%%--------------------------------------------------------------------
-
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
-
-connect(Socket, Options) when is_port(Socket) ->
- connect(Socket, Options, infinity).
-
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Socket, SslOptions, Timeout) when is_port(Socket) ->
- DTLSOpts = [{protocol, dtls} | SslOptions],
- ssl:connect(Socket, DTLSOpts, Timeout);
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
-
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Host, Port, Options, Timeout) ->
- DTLSOpts = [{protocol, dtls} | Options],
- ssl:connect(Host, Port, DTLSOpts, Timeout).
-
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(Port, Options) ->
- DTLSOpts = [{protocol, dtls} | Options],
- ssl:listen(Port, DTLSOpts).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs transport accept on an ssl listen socket
-%%--------------------------------------------------------------------
--spec accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(ListenSocket) ->
- accept(ListenSocket, infinity).
-
--spec accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(Socket, Timeout) ->
- ssl:transport_accept(Socket, Timeout).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
-
--spec handshake(#sslsocket{}) -> ok | {error, reason()}.
-
-handshake(ListenSocket) ->
- handshake(ListenSocket, infinity).
-
-
--spec handshake(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(#sslsocket{} = Socket, Timeout) ->
- ssl:ssl_accept(Socket, Timeout);
-
-handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- handshake(ListenSocket, SslOptions, infinity).
-
-
--spec handshake(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(Socket, SslOptions, Timeout) when is_port(Socket) ->
- ssl:ssl_accept(Socket, SslOptions, Timeout).
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index c0e81d6a28..8ed4505256 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -37,7 +37,7 @@
%% Internal application API
%% Setup
--export([start_fsm/8, start_link/7, init/1]).
+-export([start_fsm/8, start_link/7, init/1, pids/1]).
%% State transition handling
-export([next_record/1, next_event/3, next_event/4, handle_common_event/4]).
@@ -45,10 +45,10 @@
%% Handshake handling
-export([renegotiate/2, send_handshake/2,
queue_handshake/2, queue_change_cipher/2,
- reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
+ reinit/1, reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
%% Alert and close handling
--export([encode_alert/3,send_alert/2, close/5, protocol_name/0]).
+-export([encode_alert/3, send_alert/2, send_alert_in_connection/2, close/5, protocol_name/0]).
%% Data handling
-export([encode_data/3, passive_receive/2, next_record_if_active/1,
@@ -73,7 +73,7 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker}
try
{ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid], CbModule, Tracker),
ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
@@ -101,6 +101,10 @@ init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
EState = State0#state{protocol_specific = Map#{error => Error}},
gen_statem:enter_loop(?MODULE, [], error, EState)
end.
+
+pids(_) ->
+ [self()].
+
%%====================================================================
%% State transition handling
%%====================================================================
@@ -329,10 +333,14 @@ queue_change_cipher(ChangeCipher, #state{flight_buffer = Flight,
dtls_record:next_epoch(ConnectionStates0, write),
State#state{flight_buffer = Flight#{change_cipher_spec => ChangeCipher},
connection_states = ConnectionStates}.
+
+reinit(State) ->
+ %% To be API compatible with TLS NOOP here
+ reinit_handshake_data(State).
reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
State#state{premaster_secret = undefined,
public_key_info = undefined,
- tls_handshake_history = ssl_handshake:init_handshake_history(),
+ tls_handshake_history = ssl_handshake:init_handshake_history(),
flight_state = {retransmit, ?INITIAL_RETRANSMIT_TIMEOUT},
flight_buffer = new_flight(),
protocol_buffers =
@@ -342,8 +350,8 @@ reinit_handshake_data(#state{protocol_buffers = Buffers} = State) ->
dtls_handshake_later_fragments = []
}}.
-select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
- HelloExtensions#hello_extensions.sni;
+select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
+ SNI;
select_sni_extension(_) ->
undefined.
@@ -366,6 +374,10 @@ send_alert(Alert, #state{negotiated_version = Version,
send(Transport, Socket, BinMsg),
State0#state{connection_states = ConnectionStates}.
+send_alert_in_connection(Alert, State) ->
+ _ = send_alert(Alert, State),
+ ok.
+
close(downgrade, _,_,_,_) ->
ok;
%% Other
@@ -539,12 +551,12 @@ hello(internal, #client_hello{extensions = Extensions} = Hello, #state{ssl_optio
start_or_recv_from = From} = State) ->
{next_state, user_hello, State#state{start_or_recv_from = undefined,
hello = Hello},
- [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]};
+ [{reply, From, {ok, Extensions}}]};
hello(internal, #server_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello},
start_or_recv_from = From} = State) ->
{next_state, user_hello, State#state{start_or_recv_from = undefined,
hello = Hello},
- [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]};
+ [{reply, From, {ok, Extensions}}]};
hello(internal, #client_hello{cookie = Cookie} = Hello, #state{role = server,
transport_cb = Transport,
socket = Socket,
@@ -711,6 +723,12 @@ connection(internal, #client_hello{}, #state{role = server, allow_renegotiate =
State1 = send_alert(Alert, State0),
{Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
next_event(?FUNCTION_NAME, Record, State);
+connection({call, From}, {application_data, Data}, State) ->
+ try
+ send_application_data(Data, From, ?FUNCTION_NAME, State)
+ catch throw:Error ->
+ ssl_connection:hibernate_after(?FUNCTION_NAME, State, [{reply, From, Error}])
+ end;
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -1132,3 +1150,42 @@ log_ignore_alert(debug, StateName, Alert, Role) ->
[Role, StateName, Txt]);
log_ignore_alert(_, _, _, _) ->
ok.
+
+send_application_data(Data, From, _StateName,
+ #state{socket = Socket,
+ negotiated_version = Version,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State0) ->
+
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ renegotiate(State0#state{renegotiation = {true, internal}},
+ [{next_event, {call, From}, {application_data, Data}}]);
+ false ->
+ {Msgs, ConnectionStates} =
+ Connection:encode_data(Data, Version, ConnectionStates0),
+ State = State0#state{connection_states = ConnectionStates},
+ case Connection:send(Transport, Socket, Msgs) of
+ ok ->
+ ssl_connection:hibernate_after(connection, State, [{reply, From, ok}]);
+ Result ->
+ ssl_connection:hibernate_after(connection, State, [{reply, From, Result}])
+ end
+ end.
+
+time_to_renegotiate(_Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div
+ %% ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt), but we chose to
+ %% have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 35c213a182..55aa8174a3 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -169,10 +169,7 @@ handle_client_hello(Version,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions =
- #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns}
- = HelloExt},
+ extensions = HelloExt},
#ssl_options{versions = Versions,
signature_algs = SupportedHashSigns,
eccs = SupportedECCs,
@@ -181,6 +178,8 @@ handle_client_hello(Version,
Renegotiation) ->
case dtls_record:is_acceptable_version(Version, Versions) of
true ->
+ Curves = maps:get(elliptic_curves, HelloExt, undefined),
+ ClientHashSigns = maps:get(signature_algs, HelloExt, undefined),
TLSVersion = dtls_v1:corresponding_tls_version(Version),
AvailableHashSigns = ssl_handshake:available_signature_algs(
ClientHashSigns, SupportedHashSigns, Cert,TLSVersion),
@@ -194,8 +193,8 @@ handle_client_hello(Version,
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY);
_ ->
- #{key_exchange := KeyExAlg} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
+ #{key_exchange := KeyExAlg} = ssl_cipher_format:suite_definition(CipherSuite),
+ case ssl_handshake:select_hashsign({ClientHashSigns, undefined}, Cert, KeyExAlg,
SupportedHashSigns, TLSVersion) of
#alert{} = Alert ->
Alert;
@@ -335,7 +334,7 @@ decode_handshake(Version, <<?BYTE(Type), Bin/binary>>) ->
decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
#hello_request{};
-decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
+decode_handshake(Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
?UINT24(_), ?UINT24(_),
?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
@@ -343,8 +342,9 @@ decode_handshake(_Version, ?CLIENT_HELLO, <<?UINT24(_), ?UINT16(_),
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
Extensions/binary>>) ->
-
- DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
+ TLSVersion = dtls_v1:corresponding_tls_version(Version),
+ Exts = ssl_handshake:decode_vector(Extensions),
+ DecodedExtensions = ssl_handshake:decode_hello_extensions(Exts, TLSVersion, client),
#client_hello{
client_version = {Major,Minor},
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 50e92027d2..a16489bbd1 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -56,4 +56,11 @@
fragment
}).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7764 Datagram Transport Layer Security (DTLS) Extension to Establish Keys
+%% for the Secure Real-time Transport Protocol (SRTP)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(USE_SRTP, 14).
+
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index 9eb0d8e2d7..b7346d3ec8 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -499,23 +499,22 @@ encode_dtls_cipher_text(Type, {MajVer, MinVer}, Fragment,
WriteState#{sequence_number => Seq + 1}}.
encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
+ cipher_state := CipherS0,
epoch := Epoch,
sequence_number := Seq,
- cipher_state := CipherS0,
security_parameters :=
#security_parameters{
cipher_type = ?AEAD,
- bulk_cipher_algorithm =
- BulkCipherAlgo,
+ bulk_cipher_algorithm = BCAlg,
compression_algorithm = CompAlg}
} = WriteState0) ->
{Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- AAD = calc_aad(Type, Version, Epoch, Seq),
+ AAD = start_additional_data(Type, Version, Epoch, Seq),
+ CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
+ WriteState = WriteState0#{compression_state => CompS1,
+ cipher_state => CipherS},
TLSVersion = dtls_v1:corresponding_tls_version(Version),
- {CipherFragment, CipherS1} =
- ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, Comp, TLSVersion),
- {CipherFragment, WriteState0#{compression_state => CompS1,
- cipher_state => CipherS1}};
+ ssl_record:cipher_aead(TLSVersion, Comp, WriteState, AAD);
encode_plain_text(Type, Version, Fragment, #{compression_state := CompS0,
epoch := Epoch,
sequence_number := Seq,
@@ -547,9 +546,10 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
BulkCipherAlgo,
compression_algorithm = CompAlg}} = ReadState0,
ConnnectionStates0) ->
- AAD = calc_aad(Type, Version, Epoch, Seq),
+ AAD = start_additional_data(Type, Version, Epoch, Seq),
+ CipherS1 = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT16(Epoch), ?UINT48(Seq)>>, CipherS0),
TLSVersion = dtls_v1:corresponding_tls_version(Version),
- case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, CipherFragment, TLSVersion) of
+ case ssl_record:decipher_aead(BulkCipherAlgo, CipherS1, AAD, CipherFragment, TLSVersion) of
{PlainFragment, CipherState} ->
{Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
PlainFragment, CompressionS0),
@@ -600,7 +600,7 @@ mac_hash({Major, Minor}, MacAlg, MacSecret, Epoch, SeqNo, Type, Length, Fragment
Fragment],
dtls_v1:hmac_hash(MacAlg, MacSecret, Value).
-calc_aad(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
+start_additional_data(Type, {MajVer, MinVer}, Epoch, SeqNo) ->
<<?UINT16(Epoch), ?UINT48(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index b26d3ae41a..2001afd02f 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -48,7 +48,7 @@ accept(dtls, #config{transport_info = {Transport,_,_,_},
dtls_handler = {Listner, _}}, _Timeout) ->
case dtls_packet_demux:accept(Listner, self()) of
{ok, Pid, Socket} ->
- {ok, socket(Pid, Transport, {Listner, Socket}, ConnectionCb)};
+ {ok, socket([Pid], Transport, {Listner, Socket}, ConnectionCb)};
{error, Reason} ->
{error, Reason}
end.
@@ -73,12 +73,12 @@ close(gen_udp, {_Client, _Socket}) ->
close(Transport, {_Client, Socket}) ->
Transport:close(Socket).
-socket(Pid, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
- #sslsocket{pid = Pid,
+socket(Pids, gen_udp = Transport, {{_, _}, Socket}, ConnectionCb) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}};
-socket(Pid, Transport, Socket, ConnectionCb) ->
- #sslsocket{pid = Pid,
+socket(Pids, Transport, Socket, ConnectionCb) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb}}.
setopts(_, #sslsocket{pid = {dtls, #config{dtls_handler = {ListenPid, _}}}}, Options) ->
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index df687f579b..b365961a6a 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -27,22 +27,22 @@
-define(COOKIE_BASE_TIMEOUT, 30000).
--spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
+-spec suites(Minor:: 253|255) -> [ssl_cipher_format:cipher_suite()].
suites(Minor) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_definition(Cipher))
end,
tls_v1:suites(corresponding_minor_tls_version(Minor))).
all_suites(Version) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_definition(Cipher))
end,
ssl_cipher:all_suites(corresponding_tls_version(Version))).
anonymous_suites(Version) ->
lists:filter(fun(Cipher) ->
- is_acceptable_cipher(ssl_cipher:suite_definition(Cipher))
+ is_acceptable_cipher(ssl_cipher_format:suite_definition(Cipher))
end,
ssl_cipher:anonymous_suites(corresponding_tls_version(Version))).
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 1194f4fc72..ce771343fe 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -70,14 +70,14 @@ is_node_name(Node) ->
%% -------------------------------------------------------------------------
-hs_data_common(#sslsocket{pid = DistCtrl} = SslSocket) ->
+hs_data_common(#sslsocket{pid = [_, DistCtrl|_]} = SslSocket) ->
#hs_data{
f_send =
- fun (Ctrl, Packet) when Ctrl == DistCtrl ->
+ fun (_Ctrl, Packet) ->
f_send(SslSocket, Packet)
end,
f_recv =
- fun (Ctrl, Length, Timeout) when Ctrl == DistCtrl ->
+ fun (_, Length, Timeout) ->
f_recv(SslSocket, Length, Timeout)
end,
f_setopts_pre_nodeup =
@@ -176,8 +176,7 @@ mf_getopts(SslSocket, Opts) ->
ssl:getopts(SslSocket, Opts).
f_handshake_complete(DistCtrl, Node, DHandle) ->
- ssl_connection:handshake_complete(DistCtrl, Node, DHandle).
-
+ tls_sender:dist_handshake_complete(DistCtrl, Node, DHandle).
setopts_filter(Opts) ->
[Opt || {K,_} = Opt <- Opts,
@@ -245,7 +244,7 @@ accept_loop(Driver, Listen, Kernel, Socket) ->
trace([{active, false},{packet, 4}|Opts]),
net_kernel:connecttime())
of
- {ok, #sslsocket{pid = DistCtrl} = SslSocket} ->
+ {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} ->
trace(
Kernel !
{accept, self(), DistCtrl,
@@ -405,7 +404,7 @@ gen_accept_connection(
do_accept(
_Driver, AcceptPid, DistCtrl, MyNode, Allowed, SetupTime, Kernel) ->
- SslSocket = ssl_connection:get_sslsocket(DistCtrl),
+ {ok, SslSocket} = tls_sender:dist_tls_socket(DistCtrl),
receive
{AcceptPid, controller} ->
Timer = dist_util:start_timer(SetupTime),
@@ -530,7 +529,7 @@ do_setup_connect(Driver, Kernel, Node, Address, Ip, TcpPort, Version, Type, MyNo
[binary, {active, false}, {packet, 4},
Driver:family(), nodelay()] ++ Opts,
net_kernel:connecttime()) of
- {ok, #sslsocket{pid = DistCtrl} = SslSocket} ->
+ {ok, #sslsocket{pid = [_, DistCtrl| _]} = SslSocket} ->
_ = monitor_pid(DistCtrl),
ok = ssl:controlling_process(SslSocket, self()),
HSData0 = hs_data_common(SslSocket),
@@ -569,7 +568,7 @@ gen_close(Driver, Socket) ->
get_address_resolver(EpmdModule, Driver) ->
case erlang:function_exported(EpmdModule, address_please, 3) of
true -> {EpmdModule, address_please};
- _ -> {Driver, getaddr}
+ _ -> {erl_epmd, address_please}
end.
%% ------------------------------------------------------------
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 9679ea4687..0d92c7b447 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -5,11 +5,14 @@
%% TLS/SSL
tls_connection,
tls_handshake,
+ tls_handshake_1_3,
tls_record,
+ tls_record_1_3,
tls_socket,
tls_v1,
ssl_v3,
tls_connection_sup,
+ tls_sender,
%% DTLS
dtls_connection,
dtls_handshake,
@@ -21,8 +24,6 @@
dtls_listener_sup,
%% API
ssl, %% Main API
- tls, %% TLS specific
- dtls, %% DTLS specific
ssl_session_cache_api,
%% Both TLS/SSL and DTLS
ssl_config,
@@ -30,6 +31,7 @@
ssl_handshake,
ssl_record,
ssl_cipher,
+ ssl_cipher_format,
ssl_srp_primes,
ssl_alert,
ssl_listen_tracker_sup, %% may be used by DTLS over SCTP
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index bfdd0c205b..ae4d60b6ed 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
- [
+[
+ {<<"9\\..*">>, [{restart_application, ssl}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
@@ -9,6 +10,7 @@
{<<"3\\..*">>, [{restart_application, ssl}]}
],
[
+ {<<"9\\..*">>, [{restart_application, ssl}]},
{<<"8\\..*">>, [{restart_application, ssl}]},
{<<"7\\..*">>, [{restart_application, ssl}]},
{<<"6\\..*">>, [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index c7f1f36d5d..3319aadd68 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -241,7 +241,7 @@ handshake(#sslsocket{fd = {_, _, _, Tracker}} = Socket, SslOpts, Timeout) when
catch
Error = {error, _Reason} -> Error
end;
-handshake(#sslsocket{pid = Pid, fd = {_, _, _}} = Socket, SslOpts, Timeout) when
+handshake(#sslsocket{pid = [Pid|_], fd = {_, _, _}} = Socket, SslOpts, Timeout) when
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
try
{ok, EmOpts, _} = dtls_packet_demux:get_all_opts(Pid),
@@ -301,7 +301,7 @@ handshake_cancel(Socket) ->
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+close(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
dtls_packet_demux:close(Pid);
@@ -313,12 +313,12 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = TLSPid},
+close(#sslsocket{pid = [TLSPid|_]},
{Pid, Timeout} = DownGrade) when is_pid(TLSPid),
is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, DownGrade});
-close(#sslsocket{pid = TLSPid}, Timeout) when is_pid(TLSPid),
+close(#sslsocket{pid = [TLSPid|_]}, Timeout) when is_pid(TLSPid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity) ->
ssl_connection:close(TLSPid, {close, Timeout});
close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}}}}, _) ->
@@ -329,8 +329,10 @@ close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_, _, _}
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid}, Data) when is_pid(Pid) ->
+send(#sslsocket{pid = [Pid]}, Data) when is_pid(Pid) ->
ssl_connection:send(Pid, Data);
+send(#sslsocket{pid = [_, Pid]}, Data) when is_pid(Pid) ->
+ tls_sender:send_data(Pid, erlang:iolist_to_binary(Data));
send(#sslsocket{pid = {_, #config{transport_info={_, udp, _, _}}}}, _) ->
{error,enotconn}; %% Emulate connection behaviour
send(#sslsocket{pid = {dtls,_}}, _) ->
@@ -346,7 +348,7 @@ send(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport, _, _, _}
%%--------------------------------------------------------------------
recv(Socket, Length) ->
recv(Socket, Length, infinity).
-recv(#sslsocket{pid = Pid}, Length, Timeout) when is_pid(Pid),
+recv(#sslsocket{pid = [Pid|_]}, Length, Timeout) when is_pid(Pid),
(is_integer(Timeout) andalso Timeout >= 0) or (Timeout == infinity)->
ssl_connection:recv(Pid, Length, Timeout);
recv(#sslsocket{pid = {dtls,_}}, _, _) ->
@@ -361,7 +363,7 @@ recv(#sslsocket{pid = {Listen,
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
+controlling_process(#sslsocket{pid = [Pid|_]}, NewOwner) when is_pid(Pid), is_pid(NewOwner) ->
ssl_connection:new_user(Pid, NewOwner);
controlling_process(#sslsocket{pid = {dtls, _}},
NewOwner) when is_pid(NewOwner) ->
@@ -379,7 +381,7 @@ controlling_process(#sslsocket{pid = {Listen,
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, false) of
{ok, Info} ->
{ok, [Item || Item = {_Key, Value} <- Info, Value =/= undefined]};
@@ -396,7 +398,7 @@ connection_information(#sslsocket{pid = {dtls,_}}) ->
%%
%% Description: Return SSL information for the connection
%%--------------------------------------------------------------------
-connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
+connection_information(#sslsocket{pid = [Pid|_]}, Items) when is_pid(Pid) ->
case ssl_connection:connection_information(Pid, include_security_info(Items)) of
{ok, Info} ->
{ok, [Item || Item = {Key, Value} <- Info, lists:member(Key, Items),
@@ -410,9 +412,9 @@ connection_information(#sslsocket{pid = Pid}, Items) when is_pid(Pid) ->
%%
%% Description: same as inet:peername/1.
%%--------------------------------------------------------------------
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _}}) when is_pid(Pid)->
dtls_socket:peername(Transport, Socket);
-peername(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
+peername(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}) when is_pid(Pid)->
tls_socket:peername(Transport, Socket);
peername(#sslsocket{pid = {dtls, #config{dtls_handler = {_Pid, _}}}}) ->
dtls_socket:peername(dtls, undefined);
@@ -426,7 +428,7 @@ peername(#sslsocket{pid = {dtls,_}}) ->
%%
%% Description: Returns the peercert.
%%--------------------------------------------------------------------
-peercert(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+peercert(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
case ssl_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
@@ -444,33 +446,33 @@ peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
%% Description: Returns the protocol that has been negotiated. If no
%% protocol has been negotiated will return {error, protocol_not_negotiated}
%%--------------------------------------------------------------------
-negotiated_protocol(#sslsocket{pid = Pid}) ->
+negotiated_protocol(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:negotiated_protocol(Pid).
%%--------------------------------------------------------------------
--spec cipher_suites() -> [ssl_cipher:old_erl_cipher_suite()] | [string()].
+-spec cipher_suites() -> [ssl_cipher_format:old_erl_cipher_suite()] | [string()].
%%--------------------------------------------------------------------
cipher_suites() ->
cipher_suites(erlang).
%%--------------------------------------------------------------------
-spec cipher_suites(erlang | openssl | all) ->
- [ssl_cipher:old_erl_cipher_suite() | string()].
+ [ssl_cipher_format:old_erl_cipher_suite() | string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
cipher_suites(erlang) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(default)];
+ [ssl_cipher_format:erl_suite_definition(Suite) || Suite <- available_suites(default)];
cipher_suites(openssl) ->
- [ssl_cipher:openssl_suite_name(Suite) ||
+ [ssl_cipher_format:openssl_suite_name(Suite) ||
Suite <- available_suites(default)];
cipher_suites(all) ->
- [ssl_cipher:erl_suite_definition(Suite) || Suite <- available_suites(all)].
+ [ssl_cipher_format:erl_suite_definition(Suite) || Suite <- available_suites(all)].
%%--------------------------------------------------------------------
-spec cipher_suites(default | all | anonymous, tls_record:tls_version() | dtls_record:dtls_version() |
tls_record:tls_atom_version() | dtls_record:dtls_atom_version()) ->
- [ssl_cipher:erl_cipher_suite()].
+ [ssl_cipher_format:erl_cipher_suite()].
%% Description: Returns all default and all supported cipher suites for a
%% TLS/DTLS version
%%--------------------------------------------------------------------
@@ -483,12 +485,12 @@ cipher_suites(Base, Version) when Version == 'dtlsv1.2';
Version == 'dtlsv1'->
cipher_suites(Base, dtls_record:protocol_version(Version));
cipher_suites(Base, Version) ->
- [ssl_cipher:suite_definition(Suite) || Suite <- supported_suites(Base, Version)].
+ [ssl_cipher_format:suite_definition(Suite) || Suite <- supported_suites(Base, Version)].
%%--------------------------------------------------------------------
--spec filter_cipher_suites([ssl_cipher:erl_cipher_suite()],
+-spec filter_cipher_suites([ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()],
[{key_exchange | cipher | mac | prf, fun()}] | []) ->
- [ssl_cipher:erl_cipher_suite()].
+ [ssl_cipher_format:erl_cipher_suite() ] | [ssl_cipher_format:cipher_suite()].
%% Description: Removes cipher suites if any of the filter functions returns false
%% for any part of the cipher suite. This function also calls default filter functions
%% to make sure the cipher suite are supported by crypto.
@@ -505,10 +507,10 @@ filter_cipher_suites(Suites, Filters0) ->
prf_filters => add_filter(proplists:get_value(prf, Filters0), PrfF)},
ssl_cipher:filter_suites(Suites, Filters).
%%--------------------------------------------------------------------
--spec prepend_cipher_suites([ssl_cipher:erl_cipher_suite()] |
+-spec prepend_cipher_suites([ssl_cipher_format:erl_cipher_suite()] |
[{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+ [ssl_cipher_format:erl_cipher_suite()]) ->
+ [ssl_cipher_format:erl_cipher_suite()].
%% Description: Make <Preferred> suites become the most prefered
%% suites that is put them at the head of the cipher suite list
%% and remove them from <Suites> if present. <Preferred> may be a
@@ -523,10 +525,10 @@ prepend_cipher_suites(Filters, Suites) ->
Preferred = filter_cipher_suites(Suites, Filters),
Preferred ++ (Suites -- Preferred).
%%--------------------------------------------------------------------
--spec append_cipher_suites(Deferred :: [ssl_cipher:erl_cipher_suite()] |
+-spec append_cipher_suites(Deferred :: [ssl_cipher_format:erl_cipher_suite()] |
[{key_exchange | cipher | mac | prf, fun()}],
- [ssl_cipher:erl_cipher_suite()]) ->
- [ssl_cipher:erl_cipher_suite()].
+ [ssl_cipher_format:erl_cipher_suite()]) ->
+ [ssl_cipher_format:erl_cipher_suite()].
%% Description: Make <Deferred> suites suites become the
%% least prefered suites that is put them at the end of the cipher suite list
%% and removed them from <Suites> if present.
@@ -581,7 +583,7 @@ eccs_filter_supported(Curves) ->
%%
%% Description: Gets options
%%--------------------------------------------------------------------
-getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+getopts(#sslsocket{pid = [Pid|_]}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
getopts(#sslsocket{pid = {dtls, #config{transport_info = {Transport,_,_,_}}}} = ListenSocket, OptionTags) when is_list(OptionTags) ->
try dtls_socket:getopts(Transport, ListenSocket, OptionTags) of
@@ -612,7 +614,26 @@ getopts(#sslsocket{}, OptionTags) ->
%%
%% Description: Sets options
%%--------------------------------------------------------------------
-setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+setopts(#sslsocket{pid = [Pid, Sender]}, Options0) when is_pid(Pid), is_list(Options0) ->
+ try proplists:expand([{binary, [{mode, binary}]},
+ {list, [{mode, list}]}], Options0) of
+ Options ->
+ case proplists:get_value(packet, Options, undefined) of
+ undefined ->
+ ssl_connection:set_opts(Pid, Options);
+ PacketOpt ->
+ case tls_sender:setopts(Sender, [{packet, PacketOpt}]) of
+ ok ->
+ ssl_connection:set_opts(Pid, Options);
+ Error ->
+ Error
+ end
+ end
+ catch
+ _:_ ->
+ {error, {options, {not_a_proplist, Options0}}}
+ end;
+setopts(#sslsocket{pid = [Pid|_]}, Options0) when is_pid(Pid), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
Options ->
@@ -667,7 +688,7 @@ getstat(Socket) ->
getstat(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _}}}}, Options) when is_port(Listen), is_list(Options) ->
tls_socket:getstat(Transport, Listen, Options);
-getstat(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
+getstat(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _, _}}, Options) when is_pid(Pid), is_list(Options) ->
tls_socket:getstat(Transport, Socket, Options).
%%---------------------------------------------------------------
@@ -680,7 +701,7 @@ shutdown(#sslsocket{pid = {Listen, #config{transport_info = {Transport,_, _, _}}
Transport:shutdown(Listen, How);
shutdown(#sslsocket{pid = {dtls,_}},_) ->
{error, enotconn};
-shutdown(#sslsocket{pid = Pid}, How) ->
+shutdown(#sslsocket{pid = [Pid|_]}, How) when is_pid(Pid) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
@@ -692,9 +713,9 @@ sockname(#sslsocket{pid = {Listen, #config{transport_info = {Transport, _, _, _
tls_socket:sockname(Transport, Listen);
sockname(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
dtls_packet_demux:sockname(Pid);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid|_], fd = {Transport, Socket, _}}) when is_pid(Pid) ->
dtls_socket:sockname(Transport, Socket);
-sockname(#sslsocket{pid = Pid, fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
+sockname(#sslsocket{pid = [Pid| _], fd = {Transport, Socket, _, _}}) when is_pid(Pid) ->
tls_socket:sockname(Transport, Socket).
%%---------------------------------------------------------------
@@ -723,7 +744,15 @@ versions() ->
%%
%% Description: Initiates a renegotiation.
%%--------------------------------------------------------------------
-renegotiate(#sslsocket{pid = Pid}) when is_pid(Pid) ->
+renegotiate(#sslsocket{pid = [Pid, Sender |_]}) when is_pid(Pid),
+ is_pid(Sender) ->
+ case tls_sender:renegotiate(Sender) of
+ {ok, Write} ->
+ tls_connection:renegotiation(Pid, Write);
+ Error ->
+ Error
+ end;
+renegotiate(#sslsocket{pid = [Pid |_]}) when is_pid(Pid) ->
ssl_connection:renegotiation(Pid);
renegotiate(#sslsocket{pid = {dtls,_}}) ->
{error, enotconn};
@@ -737,7 +766,7 @@ renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
%%
%% Description: use a ssl sessions TLS PRF to generate key material
%%--------------------------------------------------------------------
-prf(#sslsocket{pid = Pid},
+prf(#sslsocket{pid = [Pid|_]},
Secret, Label, Seed, WantedLength) when is_pid(Pid) ->
ssl_connection:prf(Pid, Secret, Label, Seed, WantedLength);
prf(#sslsocket{pid = {dtls,_}}, _,_,_,_) ->
@@ -794,12 +823,12 @@ tls_version({254, _} = Version) ->
%%--------------------------------------------------------------------
--spec suite_to_str(ssl_cipher:erl_cipher_suite()) -> string().
+-spec suite_to_str(ssl_cipher_format:erl_cipher_suite()) -> string().
%%
%% Description: Return the string representation of a cipher suite.
%%--------------------------------------------------------------------
suite_to_str(Cipher) ->
- ssl_cipher:suite_to_str(Cipher).
+ ssl_cipher_format:suite_to_str(Cipher).
%%--------------------------------------------------------------------
@@ -887,9 +916,10 @@ handle_options(Opts0, #ssl_options{protocol = Protocol, cacerts = CaCerts0,
[] ->
new_ssl_options(SslOpts1, NewVerifyOpts, RecordCB);
Value ->
- Versions = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions0 = [RecordCB:protocol_version(Vsn) || Vsn <- Value],
+ Versions1 = lists:sort(fun RecordCB:is_higher/2, Versions0),
new_ssl_options(proplists:delete(versions, SslOpts1),
- NewVerifyOpts#ssl_options{versions = Versions}, record_cb(Protocol))
+ NewVerifyOpts#ssl_options{versions = Versions1}, record_cb(Protocol))
end;
%% Handle all options in listen and connect
@@ -908,12 +938,14 @@ handle_options(Opts0, Role, Host) ->
CertFile = handle_option(certfile, Opts, <<>>),
RecordCb = record_cb(Opts),
- Versions = case handle_option(versions, Opts, []) of
- [] ->
- RecordCb:supported_protocol_versions();
- Vsns ->
- [RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
- end,
+ [HighestVersion|_] = Versions =
+ case handle_option(versions, Opts, []) of
+ [] ->
+ RecordCb:supported_protocol_versions();
+ Vsns ->
+ Versions0 = [RecordCb:protocol_version(Vsn) || Vsn <- Vsns],
+ lists:sort(fun RecordCb:is_higher/2, Versions0)
+ end,
Protocol = handle_option(protocol, Opts, tls),
@@ -945,13 +977,25 @@ handle_options(Opts0, Role, Host) ->
psk_identity = handle_option(psk_identity, Opts, undefined),
srp_identity = handle_option(srp_identity, Opts, undefined),
ciphers = handle_cipher_option(proplists:get_value(ciphers, Opts, []),
- RecordCb:highest_protocol_version(Versions)),
+ HighestVersion),
eccs = handle_eccs_option(proplists:get_value(eccs, Opts, eccs()),
- RecordCb:highest_protocol_version(Versions)),
- signature_algs = handle_hashsigns_option(proplists:get_value(signature_algs, Opts,
- default_option_role(server,
- tls_v1:default_signature_algs(Versions), Role)),
- tls_version(RecordCb:highest_protocol_version(Versions))),
+ HighestVersion),
+ signature_algs =
+ handle_hashsigns_option(
+ proplists:get_value(
+ signature_algs,
+ Opts,
+ default_option_role(server,
+ tls_v1:default_signature_algs(HighestVersion),
+ Role)),
+ tls_version(HighestVersion)),
+ signature_algs_cert =
+ handle_signature_algorithms_option(
+ proplists:get_value(
+ signature_algs_cert,
+ Opts,
+ undefined), %% Do not send by default
+ tls_version(HighestVersion)),
%% Server side option
reuse_session = handle_option(reuse_session, Opts, ReuseSessionFun),
reuse_sessions = handle_option(reuse_sessions, Opts, true),
@@ -1013,8 +1057,8 @@ handle_options(Opts0, Role, Host) ->
alpn_preferred_protocols, next_protocols_advertised,
client_preferred_next_protocols, log_alert, log_level,
server_name_indication, honor_cipher_order, padding_check, crl_check, crl_cache,
- fallback, signature_algs, eccs, honor_ecc_order, beast_mitigation,
- max_handshake_size, handshake, customize_hostname_check],
+ fallback, signature_algs, signature_algs_cert, eccs, honor_ecc_order,
+ beast_mitigation, max_handshake_size, handshake, customize_hostname_check],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
end, Opts, SslOptions),
@@ -1288,6 +1332,19 @@ handle_hashsigns_option(_, Version) when Version >= {3, 3} ->
handle_hashsigns_option(_, _Version) ->
undefined.
+handle_signature_algorithms_option(Value, Version) when is_list(Value)
+ andalso Version >= {3, 4} ->
+ case tls_v1:signature_schemes(Version, Value) of
+ [] ->
+ throw({error, {options,
+ no_supported_signature_schemes,
+ {signature_algs_cert, Value}}});
+ _ ->
+ Value
+ end;
+handle_signature_algorithms_option(_, _Version) ->
+ undefined.
+
validate_options([]) ->
[];
validate_options([{Opt, Value} | Tail]) ->
@@ -1311,7 +1368,8 @@ validate_binary_list(Opt, List) ->
end, List).
validate_versions([], Versions) ->
Versions;
-validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
+validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
Version == 'tlsv1.1';
Version == tlsv1;
Version == sslv3 ->
@@ -1324,10 +1382,11 @@ validate_versions([Ver| _], Versions) ->
tls_validate_versions([], Versions) ->
Versions;
-tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.2';
- Version == 'tlsv1.1';
- Version == tlsv1;
- Version == sslv3 ->
+tls_validate_versions([Version | Rest], Versions) when Version == 'tlsv1.3';
+ Version == 'tlsv1.2';
+ Version == 'tlsv1.1';
+ Version == tlsv1;
+ Version == sslv3 ->
tls_validate_versions(Rest, Versions);
tls_validate_versions([Ver| _], Versions) ->
throw({error, {options, {Ver, {versions, Versions}}}}).
@@ -1375,10 +1434,10 @@ binary_cipher_suites(Version, []) ->
%% not require explicit configuration
default_binary_suites(Version);
binary_cipher_suites(Version, [Map|_] = Ciphers0) when is_map(Map) ->
- Ciphers = [ssl_cipher:suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Tuple|_] = Ciphers0) when is_tuple(Tuple) ->
- Ciphers = [ssl_cipher:suite(tuple_to_map(C)) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:suite(tuple_to_map(C)) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0) ->
All = ssl_cipher:all_suites(Version) ++
@@ -1393,11 +1452,11 @@ binary_cipher_suites(Version, [Cipher0 | _] = Ciphers0) when is_binary(Cipher0)
end;
binary_cipher_suites(Version, [Head | _] = Ciphers0) when is_list(Head) ->
%% Format: ["RC4-SHA","RC4-MD5"]
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- Ciphers0],
+ Ciphers = [ssl_cipher_format:openssl_suite(C) || C <- Ciphers0],
binary_cipher_suites(Version, Ciphers);
binary_cipher_suites(Version, Ciphers0) ->
%% Format: "RC4-SHA:RC4-MD5"
- Ciphers = [ssl_cipher:openssl_suite(C) || C <- string:lexemes(Ciphers0, ":")],
+ Ciphers = [ssl_cipher_format:openssl_suite(C) || C <- string:lexemes(Ciphers0, ":")],
binary_cipher_suites(Version, Ciphers).
default_binary_suites(Version) ->
@@ -1600,6 +1659,14 @@ new_ssl_options([{signature_algs, Value} | Rest], #ssl_options{} = Opts, RecordC
handle_hashsigns_option(Value,
tls_version(RecordCB:highest_protocol_version()))},
RecordCB);
+new_ssl_options([{signature_algs_cert, Value} | Rest], #ssl_options{} = Opts, RecordCB) ->
+ new_ssl_options(
+ Rest,
+ Opts#ssl_options{signature_algs_cert =
+ handle_signature_algorithms_option(
+ Value,
+ tls_version(RecordCB:highest_protocol_version()))},
+ RecordCB);
new_ssl_options([{protocol, dtls = Value} | Rest], #ssl_options{} = Opts, dtls_record = RecordCB) ->
new_ssl_options(Rest, Opts#ssl_options{protocol = Value}, RecordCB);
new_ssl_options([{protocol, tls = Value} | Rest], #ssl_options{} = Opts, tls_record = RecordCB) ->
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 34e9797f1f..ed8156e0be 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -163,6 +163,8 @@ description_txt(?USER_CANCELED) ->
"User Canceled";
description_txt(?NO_RENEGOTIATION) ->
"No Renegotiation";
+description_txt(?MISSING_EXTENSION) ->
+ "Missing extension";
description_txt(?UNSUPPORTED_EXTENSION) ->
"Unsupported Extension";
description_txt(?CERTIFICATE_UNOBTAINABLE) ->
@@ -177,6 +179,8 @@ description_txt(?UNKNOWN_PSK_IDENTITY) ->
"Unknown Psk Identity";
description_txt(?INAPPROPRIATE_FALLBACK) ->
"Inappropriate Fallback";
+description_txt(?CERTIFICATE_REQUIRED) ->
+ "Certificate required";
description_txt(?NO_APPLICATION_PROTOCOL) ->
"No application protocol";
description_txt(Enum) ->
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index b23123905e..9b2322da17 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -29,6 +29,9 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Alert protocol - RFC 2246 section 7.2
+%%% updated by RFC 8486 with
+%%% missing_extension(109),
+%%% certificate_required(116),
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% AlertLevel
@@ -100,12 +103,14 @@
-define(INAPPROPRIATE_FALLBACK, 86).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(MISSING_EXTENSION, 109).
-define(UNSUPPORTED_EXTENSION, 110).
-define(CERTIFICATE_UNOBTAINABLE, 111).
-define(UNRECOGNISED_NAME, 112).
-define(BAD_CERTIFICATE_STATUS_RESPONSE, 113).
-define(BAD_CERTIFICATE_HASH_VALUE, 114).
-define(UNKNOWN_PSK_IDENTITY, 115).
+-define(CERTIFICATE_REQUIRED, 116).
-define(NO_APPLICATION_PROTOCOL, 120).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_api.hrl b/lib/ssl/src/ssl_api.hrl
index 2bd51cf91e..7b7b1cbcd9 100644
--- a/lib/ssl/src/ssl_api.hrl
+++ b/lib/ssl/src/ssl_api.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -42,7 +42,8 @@
{verify, verify_type()} |
{verify_fun, {fun(), InitialUserState::term()}} |
{fail_if_no_peer_cert, boolean()} | {depth, integer()} |
- {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {cert, Der::binary()} | {certfile, path()} |
+ {key, {private_key_type(), Der::binary()}} |
{keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
{cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
{user_lookup_fun, {fun(), InitialUserState::term()}} |
@@ -57,7 +58,7 @@
-type verify_type() :: verify_none | verify_peer.
-type path() :: string().
--type ciphers() :: [ssl_cipher:erl_cipher_suite()] |
+-type ciphers() :: [ssl_cipher_format:erl_cipher_suite()] |
string(). % (according to old API)
-type ssl_imp() :: new | old.
@@ -65,4 +66,11 @@
ClosedTag::atom(), ErrTag::atom()}}.
-type prf_random() :: client_random | server_random.
+-type private_key_type() :: rsa | %% Backwards compatibility
+ dsa | %% Backwards compatibility
+ 'RSAPrivateKey' |
+ 'DSAPrivateKey' |
+ 'ECPrivateKey' |
+ 'PrivateKeyInfo'.
+
-endif. % -ifdef(ssl_api).
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index c15e8a2138..9997f5e0c8 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -33,6 +33,7 @@
-export([trusted_cert_and_path/4,
certificate_chain/3,
+ certificate_chain/4,
file_to_certificats/2,
file_to_crls/2,
validate/3,
@@ -40,7 +41,8 @@
is_valid_key_usage/2,
select_extension/2,
extensions_list/1,
- public_key_type/1
+ public_key_type/1,
+ foldl_db/3
]).
%%====================================================================
@@ -69,7 +71,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
case SignedAndIssuerID of
{error, issuer_not_found} ->
- %% The root CA was not sent and can not be found.
+ %% The root CA was not sent and cannot be found.
handle_incomplete_chain(Path, PartialChainHandler);
{self, _} when length(Path) == 1 ->
{selfsigned_peer, Path};
@@ -79,7 +81,8 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef, PartialChainHandler) -
%% Trusted must be selfsigned or it is an incomplete chain
handle_path(Trusted, Path, PartialChainHandler);
_ ->
- %% Root CA could not be verified
+ %% Root CA could not be verified, but partial
+ %% chain handler may trusted a cert that we got
handle_incomplete_chain(Path, PartialChainHandler)
end
end.
@@ -94,10 +97,23 @@ certificate_chain(undefined, _, _) ->
{error, no_cert};
certificate_chain(OwnCert, CertDbHandle, CertsDbRef) when is_binary(OwnCert) ->
ErlCert = public_key:pkix_decode_cert(OwnCert, otp),
- certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert]);
+ certificate_chain(ErlCert, OwnCert, CertDbHandle, CertsDbRef, [OwnCert], []);
certificate_chain(OwnCert, CertDbHandle, CertsDbRef) ->
DerCert = public_key:pkix_encode('OTPCertificate', OwnCert, otp),
- certificate_chain(OwnCert, DerCert, CertDbHandle, CertsDbRef, [DerCert]).
+ certificate_chain(OwnCert, DerCert, CertDbHandle, CertsDbRef, [DerCert], []).
+
+%%--------------------------------------------------------------------
+-spec certificate_chain(undefined | binary() | #'OTPCertificate'{} , db_handle(), certdb_ref(), [der_cert()]) ->
+ {error, no_cert} | {ok, #'OTPCertificate'{} | undefined, [der_cert()]}.
+%%
+%% Description: Create certificate chain with certs from
+%%--------------------------------------------------------------------
+certificate_chain(Cert, CertDbHandle, CertsDbRef, Candidates) when is_binary(Cert) ->
+ ErlCert = public_key:pkix_decode_cert(Cert, otp),
+ certificate_chain(ErlCert, Cert, CertDbHandle, CertsDbRef, [Cert], Candidates);
+certificate_chain(Cert, CertDbHandle, CertsDbRef, Candidates) ->
+ DerCert = public_key:pkix_encode('OTPCertificate', Cert, otp),
+ certificate_chain(Cert, DerCert, CertDbHandle, CertsDbRef, [DerCert], Candidates).
%%--------------------------------------------------------------------
-spec file_to_certificats(binary(), term()) -> [der_cert()].
%%
@@ -187,9 +203,20 @@ public_key_type(?'id-ecPublicKey') ->
ec.
%%--------------------------------------------------------------------
+-spec foldl_db(fun(), db_handle() | {extracted, list()}, list()) ->
+ {ok, term()} | issuer_not_found.
+%%
+%% Description:
+%%--------------------------------------------------------------------
+foldl_db(IsIssuerFun, CertDbHandle, []) ->
+ ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle);
+foldl_db(IsIssuerFun, _, [_|_] = ListDb) ->
+ lists:foldl(IsIssuerFun, issuer_not_found, ListDb).
+
+%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
+certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain, ListDb) ->
IssuerAndSelfSigned =
case public_key:pkix_is_self_signed(OtpCert) of
true ->
@@ -200,12 +227,12 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
case IssuerAndSelfSigned of
{_, true = SelfSigned} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned, ListDb);
{{error, issuer_not_found}, SelfSigned} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef, ListDb) of
{ok, {SerialNr, Issuer}} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain,
- SerialNr, Issuer, SelfSigned);
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain,
+ SerialNr, Issuer, SelfSigned, ListDb);
_ ->
%% Guess the the issuer must be the root
%% certificate. The verification of the
@@ -214,19 +241,19 @@ certificate_chain(OtpCert, BinCert, CertDbHandle, CertsDbRef, Chain) ->
{ok, undefined, lists:reverse(Chain)}
end;
{{ok, {SerialNr, Issuer}}, SelfSigned} ->
- certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned)
+ do_certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, SelfSigned, ListDb)
end.
-certificate_chain(_, _, [RootCert | _] = Chain, _, _, true) ->
+do_certificate_chain(_, _, [RootCert | _] = Chain, _, _, true, _) ->
{ok, RootCert, lists:reverse(Chain)};
-certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned) ->
+do_certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _, ListDb) ->
case ssl_manager:lookup_trusted_cert(CertDbHandle, CertsDbRef,
SerialNr, Issuer) of
{ok, {IssuerCert, ErlCert}} ->
ErlCert = public_key:pkix_decode_cert(IssuerCert, otp),
certificate_chain(ErlCert, IssuerCert,
- CertDbHandle, CertsDbRef, [IssuerCert | Chain]);
+ CertDbHandle, CertsDbRef, [IssuerCert | Chain], ListDb);
_ ->
%% The trusted cert may be obmitted from the chain as the
%% counter part needs to have it anyway to be able to
@@ -234,7 +261,8 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
{ok, undefined, lists:reverse(Chain)}
end.
-find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
+
+find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef, ListDb) ->
IsIssuerFun =
fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
@@ -252,26 +280,29 @@ find_issuer(OtpCert, BinCert, CertDbHandle, CertsDbRef) ->
Acc
end,
- if is_reference(CertsDbRef) -> % actual DB exists
- try ssl_pkix_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
- end;
- is_tuple(CertsDbRef), element(1,CertsDbRef) =:= extracted -> % cache bypass byproduct
- {extracted, CertsData} = CertsDbRef,
- DB = [Entry || {decoded, Entry} <- CertsData],
- try lists:foldl(IsIssuerFun, issuer_not_found, DB) of
- issuer_not_found ->
- {error, issuer_not_found}
- catch
- {ok, _IssuerId} = Return ->
- Return
- end
+ Result = case is_reference(CertsDbRef) of
+ true ->
+ do_find_issuer(IsIssuerFun, CertDbHandle, ListDb);
+ false ->
+ {extracted, CertsData} = CertsDbRef,
+ DB = [Entry || {decoded, Entry} <- CertsData],
+ do_find_issuer(IsIssuerFun, CertDbHandle, DB)
+ end,
+ case Result of
+ issuer_not_found ->
+ {error, issuer_not_found};
+ Result ->
+ Result
end.
+do_find_issuer(IssuerFun, CertDbHandle, CertDb) ->
+ try
+ foldl_db(IssuerFun, CertDbHandle, CertDb)
+ catch
+ throw:{ok, _} = Return ->
+ Return
+ end.
+
is_valid_extkey_usage(KeyUse, client) ->
%% Client wants to verify server
is_valid_key_usage(KeyUse,?'id-kp-serverAuth');
@@ -300,7 +331,7 @@ other_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) ->
{ok, IssuerId} ->
{other, IssuerId};
{error, issuer_not_found} ->
- case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef) of
+ case find_issuer(OtpCert, BinCert, CertDbHandle, CertDbRef, []) of
{ok, IssuerId} ->
{other, IssuerId};
Other ->
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 50dadd0903..cfcdcb8ac5 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -31,45 +31,29 @@
-include("ssl_cipher.hrl").
-include("ssl_handshake.hrl").
-include("ssl_alert.hrl").
+-include("tls_handshake_1_3.hrl").
-include_lib("public_key/include/public_key.hrl").
--export([security_parameters/2, security_parameters/3, suite_definition/1,
- erl_suite_definition/1,
- cipher_init/3, decipher/6, cipher/5, decipher_aead/6, cipher_aead/6,
- suite/1, suites/1, all_suites/1, crypto_support_filters/0,
+-export([security_parameters/2, security_parameters/3,
+ cipher_init/3, nonce_seed/2, decipher/6, cipher/5, aead_encrypt/5, aead_decrypt/6,
+ suites/1, all_suites/1, crypto_support_filters/0,
chacha_suites/1, anonymous_suites/1, psk_suites/1, psk_suites_anon/1,
srp_suites/0, srp_suites_anon/0,
- rc4_suites/1, des_suites/1, rsa_suites/1, openssl_suite/1, openssl_suite_name/1,
+ rc4_suites/1, des_suites/1, rsa_suites/1,
filter/3, filter_suites/1, filter_suites/2,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2, is_fallback/1,
random_bytes/1, calc_mac_hash/4,
- is_stream_ciphersuite/1, suite_to_str/1]).
-
--export_type([cipher_suite/0,
- erl_cipher_suite/0, old_erl_cipher_suite/0, openssl_cipher_suite/0,
- hash/0, key_algo/0, sign_algo/0]).
-
--type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305.
--type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512.
--type sign_algo() :: rsa | dsa | ecdsa.
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
--type erl_cipher_suite() :: #{key_exchange := key_algo(),
- cipher := cipher(),
- mac := hash() | aead,
- prf := hash() | default_prf %% Old cipher suites, version dependent
- }.
--type old_erl_cipher_suite() :: {key_algo(), cipher(), hash()} % Pre TLS 1.2
- %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
- | {key_algo(), cipher(), hash(), hash() | default_prf}.
--type cipher_suite() :: binary().
--type cipher_enum() :: integer().
--type openssl_cipher_suite() :: string().
-
+ is_stream_ciphersuite/1, signature_scheme/1,
+ scheme_to_components/1]).
-compile(inline).
+-type cipher_enum() :: integer().
+
+-export_type([cipher_enum/0]).
+
%%--------------------------------------------------------------------
--spec security_parameters(cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_cipher_format:cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%% Only security_parameters/2 should call security_parameters/3 with undefined as
%% first argument.
@@ -79,7 +63,8 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
security_parameters(undefined, CipherSuite, SecParams).
%%--------------------------------------------------------------------
--spec security_parameters(ssl_record:ssl_version() | undefined, cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_record:ssl_version() | undefined,
+ ssl_cipher_format:cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%%
%% Description: Returns a security parameters record where the
@@ -87,7 +72,7 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
%%-------------------------------------------------------------------
security_parameters(Version, CipherSuite, SecParams) ->
#{cipher := Cipher, mac := Hash,
- prf := PrfHashAlg} = suite_definition(CipherSuite),
+ prf := PrfHashAlg} = ssl_cipher_format:suite_definition(CipherSuite),
SecParams#security_parameters{
cipher_suite = CipherSuite,
bulk_cipher_algorithm = bulk_cipher_algorithm(Cipher),
@@ -110,10 +95,15 @@ cipher_init(?RC4, IV, Key) ->
#cipher_state{iv = IV, key = Key, state = State};
cipher_init(?AES_GCM, IV, Key) ->
<<Nonce:64>> = random_bytes(8),
- #cipher_state{iv = IV, key = Key, nonce = Nonce};
+ #cipher_state{iv = IV, key = Key, nonce = Nonce, tag_len = 16};
+cipher_init(?CHACHA20_POLY1305, IV, Key) ->
+ #cipher_state{iv = IV, key = Key, tag_len = 16};
cipher_init(_BCA, IV, Key) ->
#cipher_state{iv = IV, key = Key}.
+nonce_seed(Seed, CipherState) ->
+ CipherState#cipher_state{nonce = Seed}.
+
%%--------------------------------------------------------------------
-spec cipher(cipher_enum(), #cipher_state{}, binary(), iodata(), ssl_record:ssl_version()) ->
{binary(), #cipher_state{}}.
@@ -145,32 +135,16 @@ cipher(?AES_CBC, CipherState, Mac, Fragment, Version) ->
crypto:block_encrypt(aes_cbc256, Key, IV, T)
end, block_size(aes_128_cbc), CipherState, Mac, Fragment, Version).
-%%--------------------------------------------------------------------
--spec cipher_aead(cipher_enum(), #cipher_state{}, integer(), binary(), iodata(), ssl_record:ssl_version()) ->
- {binary(), #cipher_state{}}.
-%%
-%% Description: Encrypts the data and protects associated data (AAD) using chipher
-%% described by cipher_enum() and updating the cipher state
-%% Use for suites that use authenticated encryption with associated data (AEAD)
-%%-------------------------------------------------------------------
-cipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_cipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version);
-cipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_cipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version).
-
-aead_cipher(chacha20_poly1305, #cipher_state{key=Key} = CipherState, SeqNo, AAD0, Fragment, _Version) ->
- CipherLen = erlang:iolist_size(Fragment),
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = ?uint64(SeqNo),
- {Content, CipherTag} = crypto:block_encrypt(chacha20_poly1305, Key, Nonce, {AAD, Fragment}),
- {<<Content/binary, CipherTag/binary>>, CipherState};
-aead_cipher(Type, #cipher_state{key=Key, iv = IV0, nonce = Nonce} = CipherState, _SeqNo, AAD0, Fragment, _Version) ->
- CipherLen = erlang:iolist_size(Fragment),
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- <<Salt:4/bytes, _/binary>> = IV0,
- IV = <<Salt/binary, Nonce:64/integer>>,
- {Content, CipherTag} = crypto:block_encrypt(Type, Key, IV, {AAD, Fragment}),
- {<<Nonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = Nonce + 1}}.
+aead_encrypt(Type, Key, Nonce, Fragment, AdditionalData) ->
+ crypto:block_encrypt(aead_type(Type), Key, Nonce, {AdditionalData, Fragment}).
+
+aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AdditionalData) ->
+ crypto:block_decrypt(aead_type(Type), Key, Nonce, {AdditionalData, CipherText, CipherTag}).
+
+aead_type(?AES_GCM) ->
+ aes_gcm;
+aead_type(?CHACHA20_POLY1305) ->
+ chacha20_poly1305.
build_cipher_block(BlockSz, Mac, Fragment) ->
TotSz = byte_size(Mac) + erlang:iolist_size(Fragment) + 1,
@@ -187,7 +161,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
Mac, Fragment, {3, N})
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
NextIV = random_iv(IV),
L0 = build_cipher_block(BlockSz, Mac, Fragment),
L = [NextIV|L0],
@@ -237,19 +211,6 @@ decipher(?AES_CBC, HashSz, CipherState, Fragment, Version, PaddingCheck) ->
crypto:block_decrypt(aes_cbc256, Key, IV, T)
end, CipherState, HashSz, Fragment, Version, PaddingCheck).
-%%--------------------------------------------------------------------
--spec decipher_aead(cipher_enum(), #cipher_state{}, integer(), binary(), binary(), ssl_record:ssl_version()) ->
- {binary(), #cipher_state{}} | #alert{}.
-%%
-%% Description: Decrypts the data and checks the associated data (AAD) MAC using
-%% cipher described by cipher_enum() and updating the cipher state.
-%% Use for suites that use authenticated encryption with associated data (AEAD)
-%%-------------------------------------------------------------------
-decipher_aead(?AES_GCM, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_decipher(aes_gcm, CipherState, SeqNo, AAD, Fragment, Version);
-decipher_aead(?CHACHA20_POLY1305, CipherState, SeqNo, AAD, Fragment, Version) ->
- aead_decipher(chacha20_poly1305, CipherState, SeqNo, AAD, Fragment, Version).
-
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
HashSz, Fragment, Version, PaddingCheck) ->
try
@@ -280,36 +241,8 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
end.
-aead_ciphertext_to_state(chacha20_poly1305, SeqNo, _IV, AAD0, Fragment, _Version) ->
- CipherLen = size(Fragment) - 16,
- <<CipherText:CipherLen/bytes, CipherTag:16/bytes>> = Fragment,
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = ?uint64(SeqNo),
- {Nonce, AAD, CipherText, CipherTag};
-aead_ciphertext_to_state(_, _SeqNo, <<Salt:4/bytes, _/binary>>, AAD0, Fragment, _Version) ->
- CipherLen = size(Fragment) - 24,
- <<ExplicitNonce:8/bytes, CipherText:CipherLen/bytes, CipherTag:16/bytes>> = Fragment,
- AAD = <<AAD0/binary, ?UINT16(CipherLen)>>,
- Nonce = <<Salt/binary, ExplicitNonce/binary>>,
- {Nonce, AAD, CipherText, CipherTag}.
-
-aead_decipher(Type, #cipher_state{key = Key, iv = IV} = CipherState,
- SeqNo, AAD0, Fragment, Version) ->
- try
- {Nonce, AAD, CipherText, CipherTag} = aead_ciphertext_to_state(Type, SeqNo, IV, AAD0, Fragment, Version),
- case crypto:block_decrypt(Type, Key, Nonce, {AAD, CipherText, CipherTag}) of
- Content when is_binary(Content) ->
- {Content, CipherState};
- _ ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
- end
- catch
- _:_ ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
- end.
-
%%--------------------------------------------------------------------
--spec suites(ssl_record:ssl_version()) -> [cipher_suite()].
+-spec suites(ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -332,7 +265,8 @@ all_suites({3, _} = Version) ->
all_suites(Version) ->
dtls_v1:all_suites(Version).
%%--------------------------------------------------------------------
--spec chacha_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec chacha_suites(ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns list of the chacha cipher suites, only supported
%% if explicitly set by user for now due to interop problems, proably need
@@ -346,7 +280,8 @@ chacha_suites(_) ->
[].
%%--------------------------------------------------------------------
--spec anonymous_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec anonymous_suites(ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the anonymous cipher suites, only supported
%% if explicitly set by user. Intended only for testing.
@@ -355,6 +290,8 @@ anonymous_suites({3, N}) ->
srp_suites_anon() ++ anonymous_suites(N);
anonymous_suites({254, _} = Version) ->
dtls_v1:anonymous_suites(Version);
+anonymous_suites(4) ->
+ []; %% Raw public key negotiation may be used instead
anonymous_suites(N)
when N >= 3 ->
psk_suites_anon(N) ++
@@ -382,13 +319,15 @@ anonymous_suites(N) when N == 0;
].
%%--------------------------------------------------------------------
--spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec psk_suites(ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
%%--------------------------------------------------------------------
psk_suites({3, N}) ->
psk_suites(N);
+psk_suites(4) ->
+ []; %% TODO Add new PSK, PSK_(EC)DHE suites
psk_suites(N)
when N >= 3 ->
[
@@ -404,7 +343,7 @@ psk_suites(_) ->
?TLS_RSA_PSK_WITH_RC4_128_SHA].
%%--------------------------------------------------------------------
--spec psk_suites_anon(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec psk_suites_anon(ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the anonymous PSK cipher suites, only supported
%% if explicitly set by user.
@@ -439,7 +378,7 @@ psk_suites_anon(_) ->
?TLS_DHE_PSK_WITH_RC4_128_SHA,
?TLS_PSK_WITH_RC4_128_SHA].
%%--------------------------------------------------------------------
--spec srp_suites() -> [cipher_suite()].
+-spec srp_suites() -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP cipher suites, only supported
%% if explicitly set by user.
@@ -453,7 +392,7 @@ srp_suites() ->
?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec srp_suites_anon() -> [cipher_suite()].
+-spec srp_suites_anon() -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the SRP anonymous cipher suites, only supported
%% if explicitly set by user.
@@ -464,7 +403,8 @@ srp_suites_anon() ->
?TLS_SRP_SHA_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec rc4_suites(Version::ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec rc4_suites(Version::ssl_record:ssl_version() | integer()) ->
+ [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the RSA|(ECDH/RSA)| (ECDH/ECDSA)
%% with RC4 cipher suites, only supported if explicitly set by user.
@@ -478,13 +418,14 @@ rc4_suites({3, Minor}) ->
rc4_suites(0) ->
[?TLS_RSA_WITH_RC4_128_SHA,
?TLS_RSA_WITH_RC4_128_MD5];
-rc4_suites(N) when N =< 3 ->
+rc4_suites(N) when N =< 4 ->
[?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDHE_RSA_WITH_RC4_128_SHA,
?TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
?TLS_ECDH_RSA_WITH_RC4_128_SHA].
+
%%--------------------------------------------------------------------
--spec des_suites(Version::ssl_record:ssl_version()) -> [cipher_suite()].
+-spec des_suites(Version::ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the cipher suites
%% with DES cipher, only supported if explicitly set by user.
@@ -502,7 +443,7 @@ des_suites(_)->
].
%%--------------------------------------------------------------------
--spec rsa_suites(Version::ssl_record:ssl_version() | integer()) -> [cipher_suite()].
+-spec rsa_suites(Version::ssl_record:ssl_version() | integer()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Returns a list of the RSA key exchange
%% cipher suites, only supported if explicitly set by user.
@@ -517,1728 +458,17 @@ rsa_suites(0) ->
?TLS_RSA_WITH_AES_128_CBC_SHA,
?TLS_RSA_WITH_3DES_EDE_CBC_SHA
];
-rsa_suites(N) when N =< 3 ->
+rsa_suites(N) when N =< 4 ->
[
?TLS_RSA_WITH_AES_256_GCM_SHA384,
?TLS_RSA_WITH_AES_256_CBC_SHA256,
?TLS_RSA_WITH_AES_128_GCM_SHA256,
?TLS_RSA_WITH_AES_128_CBC_SHA256
].
-%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition.
-%% Note: Currently not supported suites are commented away.
-%% They should be supported or removed in the future.
-%%-------------------------------------------------------------------
-%% TLS v1.1 suites
-suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
- #{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null};
-%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
-%% to avoid handshake failure from old servers that do not ignore
-%% hello extension data as they should.
-suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
- #{key_exchange => null,
- cipher => null,
- mac => null,
- prf => null};
-suite_definition(?TLS_RSA_WITH_RC4_128_MD5) ->
- #{key_exchange => rsa,
- cipher => rc4_128,
- mac => md5,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-%%% TSL V1.1 AES suites
-suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% TLS v1.2 suites
-%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
-%% {rsa, null, sha, default_prf};
-suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-%% not defined YET:
-%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256
-%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256
-%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256
-%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256
-%%% DH-ANON deprecated by TLS spec and not available
-%%% by default, but good for testing purposes.
-suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) ->
- #{key_exchange => dh_anon,
- cipher => rc4_128,
- mac => md5,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => des_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_cbc,
- mac => sha256,
- prf => default_prf};
-%%% PSK Cipher Suites RFC 4279
-suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%%% PSK NULL Cipher Suites RFC 4785
-suite_definition(?TLS_PSK_WITH_NULL_SHA) ->
- #{key_exchange => psk,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA) ->
- #{key_exchange => dhe_psk,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA) ->
- #{key_exchange => rsa_psk,
- cipher => null,
- mac => sha,
- prf => default_prf};
-%%% TLS 1.2 PSK Cipher Suites RFC 5487
-suite_definition(?TLS_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => dhe_psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => dhe_psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => rsa_psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => rsa_psk,
- cipher => null,
- mac => sha384,
- prf => default_prf};
-%%% ECDHE PSK Cipher Suites RFC 5489
-suite_definition(?TLS_ECDHE_PSK_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdhe_psk,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdhe_psk,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_NULL_SHA256) ->
- #{key_exchange => ecdhe_psk,
- cipher => null,
- mac => sha256,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_PSK_WITH_NULL_SHA384) ->
- #{key_exchange => ecdhe_psk,
- cipher => null, mac => sha384,
- prf => default_prf};
-%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_128_gcm,
- mac => null,
- prf => sha256};
-suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdhe_psk,
- cipher => aes_256_gcm,
- mac => null,
- prf => sha384};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_128_ccm,
-%% mac => null,
-%% prf =>sha256};
-%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
-%% #{key_exchange => ecdhe_psk,
-%% cipher => aes_256_ccm,
-%% mac => null,
-%% prf => sha256};
-%%% SRP Cipher Suites RFC 5054
-suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => srp_dss,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% RFC 4492 EC TLS suites
-suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => null,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => rc4_128,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => '3des_ede_cbc',
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => aes_128_cbc,
- mac => sha,
- prf => default_prf};
-suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
- #{key_exchange => ecdh_anon,
- cipher => aes_256_cbc,
- mac => sha,
- prf => default_prf};
-%% RFC 5289 EC TLS suites
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_cbc,
- mac => sha256,
- prf => sha256};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_cbc,
- mac => sha384,
- prf => sha384};
-%% RFC 5288 AES-GCM Cipher Suites
-suite_definition(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dhe_dss,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dhe_dss,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_dss,
- cipher => aes_128_gcm,
- mac => null,
- prf => sha256};
-suite_definition(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_dss,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_DH_anon_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => dh_anon,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DH_anon_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => dh_anon,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-%% RFC 5289 ECC AES-GCM Cipher Suites
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdh_ecdsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdhe_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_128_gcm,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
- #{key_exchange => ecdh_rsa,
- cipher => aes_256_gcm,
- mac => aead,
- prf => sha384};
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
-suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => ecdhe_rsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => ecdhe_ecdsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256};
-suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
- #{key_exchange => dhe_rsa,
- cipher => chacha20_poly1305,
- mac => aead,
- prf => sha256}.
-
-%%--------------------------------------------------------------------
--spec erl_suite_definition(cipher_suite() | erl_cipher_suite()) -> old_erl_cipher_suite().
-%%
-%% Description: Return erlang cipher suite definition. Filters last value
-%% for now (compatibility reasons).
-%%--------------------------------------------------------------------
-erl_suite_definition(Bin) when is_binary(Bin) ->
- erl_suite_definition(suite_definition(Bin));
-erl_suite_definition(#{key_exchange := KeyExchange, cipher := Cipher,
- mac := Hash, prf := Prf}) ->
- case Prf of
- default_prf ->
- {KeyExchange, Cipher, Hash};
- _ ->
- {KeyExchange, Cipher, Hash, Prf}
- end.
-
-%%--------------------------------------------------------------------
--spec suite(erl_cipher_suite()) -> cipher_suite().
-%%
-%% Description: Return TLS cipher suite definition.
-%%--------------------------------------------------------------------
-%% TLS v1.1 suites
-suite(#{key_exchange := rsa,
- cipher := rc4_128,
- mac := md5}) ->
- ?TLS_RSA_WITH_RC4_128_MD5;
-suite(#{key_exchange := rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := rsa,
- cipher := des_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_DES_CBC_SHA;
-suite(#{key_exchange := rsa,
- cipher :='3des_ede_cbc',
- mac := sha}) ->
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher:= rc4_128,
- mac := md5}) ->
- ?TLS_DH_anon_WITH_RC4_128_MD5;
-suite(#{key_exchange := dh_anon,
- cipher:= des_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_DES_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher:= '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
-%%% TSL V1.1 AES suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA;
-%% TLS v1.2 suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := rsa,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_cbc,
- mac := sha256}) ->
- ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
-%%% PSK Cipher Suites RFC 4279
-suite(#{key_exchange := psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_PSK_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
-%%% PSK NULL Cipher Suites RFC 4785
-suite(#{key_exchange := psk,
- cipher := null,
- mac := sha}) ->
- ?TLS_PSK_WITH_NULL_SHA;
-suite(#{key_exchange := dhe_psk,
- cipher := null,
- mac := sha}) ->
- ?TLS_DHE_PSK_WITH_NULL_SHA;
-suite(#{key_exchange := rsa_psk,
- cipher := null,
- mac := sha}) ->
- ?TLS_RSA_PSK_WITH_NULL_SHA;
-%%% TLS 1.2 PSK Cipher Suites RFC 5487
-suite(#{key_exchange := psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_PSK_WITH_NULL_SHA384;
-suite(#{key_exchange := dhe_psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_DHE_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := dhe_psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_DHE_PSK_WITH_NULL_SHA384;
-suite(#{key_exchange := rsa_psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_RSA_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := rsa_psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_RSA_PSK_WITH_NULL_SHA384;
-%%% ECDHE PSK Cipher Suites RFC 5489
-suite(#{key_exchange := ecdhe_psk,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDHE_PSK_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdhe_psk,
- cipher :='3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_128_cbc,
- mac := sha256}) ->
- ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_256_cbc,
- mac := sha384}) ->
- ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdhe_psk,
- cipher := null,
- mac := sha256}) ->
- ?TLS_ECDHE_PSK_WITH_NULL_SHA256;
-suite(#{key_exchange := ecdhe_psk,
- cipher := null,
- mac := sha384}) ->
- ?TLS_ECDHE_PSK_WITH_NULL_SHA384;
-%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_128_gcm,
- mac := null,
- prf := sha256}) ->
- ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdhe_psk,
- cipher := aes_256_gcm,
- mac := null,
- prf := sha384}) ->
- ?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_128_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
- %% suite(#{key_exchange := ecdhe_psk,
- %% cipher := aes_256_ccm,
- %% mac := null,
- %% prf := sha256}) ->
- %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
-%%% SRP Cipher Suites RFC 5054
-suite(#{key_exchange := srp_anon,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := srp_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := srp_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := srp_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := srp_dss,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
-%%% RFC 4492 EC TLS suites
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := '3des_ede_cbc', mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_NULL_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := null,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_NULL_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := rc4_128,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_RC4_128_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := '3des_ede_cbc',
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := aes_128_cbc,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
-suite(#{key_exchange := ecdh_anon,
- cipher := aes_256_cbc,
- mac := sha}) ->
- ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
-%%% RFC 5289 EC TLS suites
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_cbc,
- mac:= sha256,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_cbc,
- mac := sha256,
- prf := sha256}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_cbc,
- mac := sha384,
- prf := sha384}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
-%% RFC 5288 AES-GCM Cipher Suites
-suite(#{key_exchange := rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dhe_dss,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_dss,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_dss,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := dh_anon,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DH_anon_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := dh_anon,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_DH_anon_WITH_AES_256_GCM_SHA384;
-%% RFC 5289 ECC AES-GCM Cipher Suites
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdh_ecdsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdhe_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_128_gcm,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
-suite(#{key_exchange := ecdh_rsa,
- cipher := aes_256_gcm,
- mac := aead,
- prf := sha384}) ->
- ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
-%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
-suite(#{key_exchange := ecdhe_rsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
-suite(#{key_exchange := ecdhe_ecdsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
-suite(#{key_exchange := dhe_rsa,
- cipher := chacha20_poly1305,
- mac := aead,
- prf := sha256}) ->
- ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256.
-
%%--------------------------------------------------------------------
--spec suite_to_str(erl_cipher_suite()) -> string().
-%%
-%% Description: Return the string representation of a cipher suite.
-%%--------------------------------------------------------------------
-suite_to_str(#{key_exchange := null,
- cipher := null,
- mac := null,
- prf := null}) ->
- "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
-suite_to_str(#{key_exchange := Kex,
- cipher := Cipher,
- mac := aead,
- prf := PRF}) ->
- "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
- "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
- "_" ++ string:to_upper(atom_to_list(PRF));
-suite_to_str(#{key_exchange := Kex,
- cipher := Cipher,
- mac := Mac}) ->
- "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
- "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
- "_" ++ string:to_upper(atom_to_list(Mac)).
-
-
-%%--------------------------------------------------------------------
--spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
-%%
-%% Description: Return TLS cipher suite definition.
-%%--------------------------------------------------------------------
-%% translate constants <-> openssl-strings
-openssl_suite("DHE-RSA-AES256-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
-openssl_suite("DHE-DSS-AES256-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
-openssl_suite("AES256-SHA256") ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA256;
-openssl_suite("DHE-RSA-AES128-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("DHE-DSS-AES128-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
-openssl_suite("AES128-SHA256") ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("DHE-RSA-AES256-SHA") ->
- ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("DHE-DSS-AES256-SHA") ->
- ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
-openssl_suite("AES256-SHA") ->
- ?TLS_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("EDH-RSA-DES-CBC3-SHA") ->
- ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("EDH-DSS-DES-CBC3-SHA") ->
- ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("DES-CBC3-SHA") ->
- ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("DHE-RSA-AES128-SHA") ->
- ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("DHE-DSS-AES128-SHA") ->
- ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
-openssl_suite("AES128-SHA") ->
- ?TLS_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("RC4-SHA") ->
- ?TLS_RSA_WITH_RC4_128_SHA;
-openssl_suite("RC4-MD5") ->
- ?TLS_RSA_WITH_RC4_128_MD5;
-openssl_suite("EDH-RSA-DES-CBC-SHA") ->
- ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
-openssl_suite("DES-CBC-SHA") ->
- ?TLS_RSA_WITH_DES_CBC_SHA;
-
-%%% SRP Cipher Suites RFC 5054
-
-openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
-openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
-openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
-openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
- ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
-
-%% RFC 4492 EC TLS suites
-openssl_suite("ECDH-ECDSA-RC4-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
-openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDH-ECDSA-AES128-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDH-ECDSA-AES256-SHA") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
-openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDHE-RSA-RC4-SHA") ->
- ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
-openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
- ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDHE-RSA-AES128-SHA") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDHE-RSA-AES256-SHA") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
-
-openssl_suite("ECDH-RSA-RC4-SHA") ->
- ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
-openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
- ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
-openssl_suite("ECDH-RSA-AES128-SHA") ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
-openssl_suite("ECDH-RSA-AES256-SHA") ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
-
-%% RFC 5289 EC TLS suites
-openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDHE-RSA-AES128-SHA256") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDHE-RSA-AES256-SHA384") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
-openssl_suite("ECDH-RSA-AES128-SHA256") ->
- ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
-openssl_suite("ECDH-RSA-AES256-SHA384") ->
- ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
-
-%% RFC 5288 AES-GCM Cipher Suites
-openssl_suite("AES128-GCM-SHA256") ->
- ?TLS_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("AES256-GCM-SHA384") ->
- ?TLS_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DHE-RSA-AES128-GCM-SHA256") ->
- ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("DHE-RSA-AES256-GCM-SHA384") ->
- ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DH-RSA-AES128-GCM-SHA256") ->
- ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("DH-RSA-AES256-GCM-SHA384") ->
- ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("DHE-DSS-AES128-GCM-SHA256") ->
- ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
-openssl_suite("DHE-DSS-AES256-GCM-SHA384") ->
- ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
-openssl_suite("DH-DSS-AES128-GCM-SHA256") ->
- ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
-openssl_suite("DH-DSS-AES256-GCM-SHA384") ->
- ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
-
-%% RFC 5289 ECC AES-GCM Cipher Suites
-openssl_suite("ECDHE-ECDSA-AES128-GCM-SHA256") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDHE-ECDSA-AES256-GCM-SHA384") ->
- ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDH-ECDSA-AES128-GCM-SHA256") ->
- ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDH-ECDSA-AES256-GCM-SHA384") ->
- ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDHE-RSA-AES128-GCM-SHA256") ->
- ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDHE-RSA-AES256-GCM-SHA384") ->
- ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
-openssl_suite("ECDH-RSA-AES128-GCM-SHA256") ->
- ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
-openssl_suite("ECDH-RSA-AES256-GCM-SHA384") ->
- ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384.
-
-%%--------------------------------------------------------------------
--spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite() | erl_cipher_suite().
-%%
-%% Description: Return openssl cipher suite name if possible
-%%-------------------------------------------------------------------
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
- "DHE-RSA-AES256-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
- "DHE-DSS-AES256-SHA";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
- "AES256-SHA";
-openssl_suite_name(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "EDH-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
- "EDH-DSS-DES-CBC3-SHA";
-openssl_suite_name(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "DES-CBC3-SHA";
-openssl_suite_name( ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
- "DHE-RSA-AES128-SHA";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
- "DHE-DSS-AES128-SHA";
-openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
- "AES128-SHA";
-openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) ->
- "RC4-SHA";
-openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) ->
- "RC4-MD5";
-openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
- "EDH-RSA-DES-CBC-SHA";
-openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) ->
- "DES-CBC-SHA";
-openssl_suite_name(?TLS_RSA_WITH_NULL_SHA256) ->
- "NULL-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
- "AES128-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
- "AES256-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_CBC_SHA256) ->
- "DH-DSS-AES128-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_CBC_SHA256) ->
- "DH-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
- "DHE-DSS-AES128-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
- "DHE-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_CBC_SHA256) ->
- "DH-DSS-AES256-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_CBC_SHA256) ->
- "DH-RSA-AES256-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
- "DHE-DSS-AES256-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
- "DHE-RSA-AES256-SHA256";
-
-%%% PSK Cipher Suites RFC 4279
-
-openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
- "PSK-AES256-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
- "PSK-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
- "PSK-AES128-CBC-SHA";
-openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
- "PSK-RC4-SHA";
-
-%%% SRP Cipher Suites RFC 5054
-
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "SRP-RSA-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
- "SRP-DSS-3DES-EDE-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
- "SRP-RSA-AES-128-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
- "SRP-DSS-AES-128-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
- "SRP-RSA-AES-256-CBC-SHA";
-openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
- "SRP-DSS-AES-256-CBC-SHA";
-
-%% RFC 4492 EC TLS suites
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
- "ECDH-ECDSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDH-ECDSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
- "ECDH-ECDSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
- "ECDH-ECDSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
- "ECDHE-ECDSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDHE-ECDSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
- "ECDHE-ECDSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
- "ECDHE-ECDSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
- "ECDH-RSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDH-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
- "ECDH-RSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
- "ECDH-RSA-AES256-SHA";
-
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
- "ECDHE-RSA-RC4-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
- "ECDHE-RSA-DES-CBC3-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
- "ECDHE-RSA-AES128-SHA";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
- "ECDHE-RSA-AES256-SHA";
-
-%% RFC 5289 EC TLS suites
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
- "ECDHE-ECDSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
- "ECDHE-ECDSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
- "ECDH-ECDSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
- "ECDH-ECDSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
- "ECDHE-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
- "ECDHE-RSA-AES256-SHA384";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
- "ECDH-RSA-AES128-SHA256";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
- "ECDH-RSA-AES256-SHA384";
-
-%% RFC 5288 AES-GCM Cipher Suites
-openssl_suite_name(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
- "AES128-GCM-SHA256";
-openssl_suite_name(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
- "AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
- "DHE-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
- "DHE-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
- "DH-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
- "DH-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
- "DHE-DSS-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
- "DHE-DSS-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
- "DH-DSS-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
- "DH-DSS-AES256-GCM-SHA384";
-
-%% RFC 5289 ECC AES-GCM Cipher Suites
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
- "ECDHE-ECDSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
- "ECDHE-ECDSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
- "ECDH-ECDSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
- "ECDH-ECDSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
- "ECDHE-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
- "ECDHE-RSA-AES256-GCM-SHA384";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
- "ECDH-RSA-AES128-GCM-SHA256";
-openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
- "ECDH-RSA-AES256-GCM-SHA384";
-
-%% No oppenssl name
-openssl_suite_name(Cipher) ->
- suite_definition(Cipher).
-
-%%--------------------------------------------------------------------
--spec filter(undefined | binary(), [cipher_suite()], ssl_record:ssl_version()) -> [cipher_suite()].
+-spec filter(undefined | binary(), [ssl_cipher_format:cipher_suite()],
+ ssl_record:ssl_version()) -> [ssl_cipher_format:cipher_suite()].
%%
%% Description: Select the cipher suites that can be used together with the
%% supplied certificate. (Server side functionality)
@@ -2258,8 +488,8 @@ filter(DerCert, Ciphers0, Version) ->
filter_suites_signature(Sign, Ciphers, Version).
%%--------------------------------------------------------------------
--spec filter_suites([erl_cipher_suite()] | [cipher_suite()], map()) ->
- [erl_cipher_suite()] | [cipher_suite()].
+-spec filter_suites([ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()], map()) ->
+ [ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()].
%%
%% Description: Filter suites using supplied filter funs
%%-------------------------------------------------------------------
@@ -2282,11 +512,11 @@ filter_suite(#{key_exchange := KeyExchange,
all_filters(Hash, HashFilters) andalso
all_filters(Prf, PrfFilters);
filter_suite(Suite, Filters) ->
- filter_suite(suite_definition(Suite), Filters).
+ filter_suite(ssl_cipher_format:suite_definition(Suite), Filters).
%%--------------------------------------------------------------------
--spec filter_suites([erl_cipher_suite()] | [cipher_suite()]) ->
- [erl_cipher_suite()] | [cipher_suite()].
+-spec filter_suites([ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()]) ->
+ [ssl_cipher_format:erl_cipher_suite()] | [ssl_cipher_format:cipher_suite()].
%%
%% Description: Filter suites for algorithms supported by crypto.
%%-------------------------------------------------------------------
@@ -2430,7 +660,7 @@ mac_hash({_,_}, ?NULL, _MacSecret, _SeqNo, _Type,
mac_hash({3, 0}, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
ssl_v3:mac_hash(MacAlg, MacSecret, SeqNo, Type, Length, Fragment);
mac_hash({3, N} = Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment)
- when N =:= 1; N =:= 2; N =:= 3 ->
+ when N =:= 1; N =:= 2; N =:= 3; N =:= 4 ->
tls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
Length, Fragment).
@@ -2578,6 +808,61 @@ sign_algorithm(?ECDSA) -> ecdsa;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 4) and (Other =< 223)) -> unassigned;
sign_algorithm(Other) when is_integer(Other) andalso ((Other >= 224) and (Other =< 255)) -> Other.
+
+signature_scheme(rsa_pkcs1_sha256) -> ?RSA_PKCS1_SHA256;
+signature_scheme(rsa_pkcs1_sha384) -> ?RSA_PKCS1_SHA384;
+signature_scheme(rsa_pkcs1_sha512) -> ?RSA_PKCS1_SHA512;
+signature_scheme(ecdsa_secp256r1_sha256) -> ?ECDSA_SECP256R1_SHA256;
+signature_scheme(ecdsa_secp384r1_sha384) -> ?ECDSA_SECP384R1_SHA384;
+signature_scheme(ecdsa_secp521r1_sha512) -> ?ECDSA_SECP521R1_SHA512;
+signature_scheme(rsa_pss_rsae_sha256) -> ?RSA_PSS_RSAE_SHA256;
+signature_scheme(rsa_pss_rsae_sha384) -> ?RSA_PSS_RSAE_SHA384;
+signature_scheme(rsa_pss_rsae_sha512) -> ?RSA_PSS_RSAE_SHA512;
+signature_scheme(ed25519) -> ?ED25519;
+signature_scheme(ed448) -> ?ED448;
+signature_scheme(rsa_pss_pss_sha256) -> ?RSA_PSS_PSS_SHA256;
+signature_scheme(rsa_pss_pss_sha384) -> ?RSA_PSS_PSS_SHA384;
+signature_scheme(rsa_pss_pss_sha512) -> ?RSA_PSS_PSS_SHA512;
+signature_scheme(rsa_pkcs1_sha1) -> ?RSA_PKCS1_SHA1;
+signature_scheme(ecdsa_sha1) -> ?ECDSA_SHA1;
+signature_scheme(?RSA_PKCS1_SHA256) -> rsa_pkcs1_sha256;
+signature_scheme(?RSA_PKCS1_SHA384) -> rsa_pkcs1_sha384;
+signature_scheme(?RSA_PKCS1_SHA512) -> rsa_pkcs1_sha512;
+signature_scheme(?ECDSA_SECP256R1_SHA256) -> ecdsa_secp256r1_sha256;
+signature_scheme(?ECDSA_SECP384R1_SHA384) -> ecdsa_secp384r1_sha384;
+signature_scheme(?ECDSA_SECP521R1_SHA512) -> ecdsa_secp521r1_sha512;
+signature_scheme(?RSA_PSS_RSAE_SHA256) -> rsa_pss_rsae_sha256;
+signature_scheme(?RSA_PSS_RSAE_SHA384) -> rsa_pss_rsae_sha384;
+signature_scheme(?RSA_PSS_RSAE_SHA512) -> rsa_pss_rsae_sha512;
+signature_scheme(?ED25519) -> ed25519;
+signature_scheme(?ED448) -> ed448;
+signature_scheme(?RSA_PSS_PSS_SHA256) -> rsa_pss_pss_sha256;
+signature_scheme(?RSA_PSS_PSS_SHA384) -> rsa_pss_pss_sha384;
+signature_scheme(?RSA_PSS_PSS_SHA512) -> rsa_pss_pss_sha512;
+signature_scheme(?RSA_PKCS1_SHA1) -> rsa_pkcs1_sha1;
+signature_scheme(?ECDSA_SHA1) -> ecdsa_sha1;
+signature_scheme(_) -> unassigned.
+%% TODO: reserved code points?
+
+scheme_to_components(rsa_pkcs1_sha256) -> {sha256, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha384) -> {sha384, rsa_pkcs1, undefined};
+scheme_to_components(rsa_pkcs1_sha512) -> {sha512, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_secp256r1_sha256) -> {sha256, ecdsa, secp256r1};
+scheme_to_components(ecdsa_secp384r1_sha384) -> {sha384, ecdsa, secp384r1};
+scheme_to_components(ecdsa_secp521r1_sha512) -> {sha512, ecdsa, secp521r1};
+scheme_to_components(rsa_pss_rsae_sha256) -> {sha256, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha384) -> {sha384, rsa_pss_rsae, undefined};
+scheme_to_components(rsa_pss_rsae_sha512) -> {sha512, rsa_pss_rsae, undefined};
+%% scheme_to_components(ed25519) -> {undefined, undefined, undefined};
+%% scheme_to_components(ed448) -> {undefined, undefined, undefined};
+scheme_to_components(rsa_pss_pss_sha256) -> {sha256, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha384) -> {sha384, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pss_pss_sha512) -> {sha512, rsa_pss_pss, undefined};
+scheme_to_components(rsa_pkcs1_sha1) -> {sha1, rsa_pkcs1, undefined};
+scheme_to_components(ecdsa_sha1) -> {sha1, ecdsa, undefined}.
+
+
+
hash_size(null) ->
0;
%% The AEAD MAC hash size is not used in the context
@@ -2635,7 +920,7 @@ generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
next_iv = IV};
generic_block_cipher_from_bin({3, N}, T, IV, HashSize)
- when N == 2; N == 3 ->
+ when N == 2; N == 3; N == 4 ->
Sz1 = byte_size(T) - 1,
<<_:Sz1/binary, ?BYTE(PadLength)>> = T,
IVLength = byte_size(IV),
@@ -2777,6 +1062,8 @@ ecdsa_signed_suites(Ciphers, Version) ->
rsa_keyed(dhe_rsa) ->
true;
+rsa_keyed(ecdhe_rsa) ->
+ true;
rsa_keyed(rsa) ->
true;
rsa_keyed(rsa_psk) ->
@@ -2840,6 +1127,8 @@ ec_keyed(ecdh_ecdsa) ->
true;
ec_keyed(ecdh_rsa) ->
true;
+ec_keyed(ecdhe_ecdsa) ->
+ true;
ec_keyed(_) ->
false.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index ba6a98b92a..5891f3a7cc 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -48,7 +48,8 @@
iv,
key,
state,
- nonce
+ nonce,
+ tag_len
}).
%%% TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a
@@ -610,4 +611,21 @@
%% TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = {0xcc, 0x15}
-define(TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, <<?BYTE(16#CC), ?BYTE(16#15)>>).
+%%% TLS 1.3 cipher suites RFC8446
+
+%% TLS_AES_128_GCM_SHA256 = {0x13,0x01}
+-define(TLS_AES_128_GCM_SHA256, <<?BYTE(16#13), ?BYTE(16#01)>>).
+
+%% TLS_AES_256_GCM_SHA384 = {0x13,0x02}
+-define(TLS_AES_256_GCM_SHA384, <<?BYTE(16#13),?BYTE(16#02)>>).
+
+%% TLS_CHACHA20_POLY1305_SHA256 = {0x13,0x03}
+-define(TLS_CHACHA20_POLY1305_SHA256, <<?BYTE(16#13),?BYTE(16#03)>>).
+
+%% %% TLS_AES_128_CCM_SHA256 = {0x13,0x04}
+%% -define(TLS_AES_128_CCM_SHA256, <<?BYTE(16#13), ?BYTE(16#04)>>).
+
+%% %% TLS_AES_128_CCM_8_SHA256 = {0x13,0x05}
+%% -define(TLS_AES_128_CCM_8_SHA256, <<?BYTE(16#13),?BYTE(16#05)>>).
+
-endif. % -ifdef(ssl_cipher).
diff --git a/lib/ssl/src/ssl_cipher_format.erl b/lib/ssl/src/ssl_cipher_format.erl
new file mode 100644
index 0000000000..6e480eef45
--- /dev/null
+++ b/lib/ssl/src/ssl_cipher_format.erl
@@ -0,0 +1,1854 @@
+%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Convert between diffrent cipher suite representations
+%%
+%%----------------------------------------------------------------------
+-module(ssl_cipher_format).
+
+-include("ssl_cipher.hrl").
+-include("ssl_internal.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-export_type([cipher_suite/0,
+ erl_cipher_suite/0, old_erl_cipher_suite/0, openssl_cipher_suite/0,
+ hash/0, key_algo/0, sign_algo/0]).
+
+-type cipher() :: null |rc4_128 | des_cbc | '3des_ede_cbc' | aes_128_cbc | aes_256_cbc | aes_128_gcm | aes_256_gcm | chacha20_poly1305.
+-type hash() :: null | md5 | sha | sha224 | sha256 | sha384 | sha512.
+-type sign_algo() :: rsa | dsa | ecdsa.
+-type key_algo() :: null |
+ rsa |
+ dhe_rsa | dhe_dss |
+ ecdhe_ecdsa | ecdh_ecdsa | ecdh_rsa |
+ srp_rsa| srp_dss |
+ psk | dhe_psk | rsa_psk |
+ dh_anon | ecdh_anon | srp_anon |
+ any. %% TLS 1.3
+-type erl_cipher_suite() :: #{key_exchange := key_algo(),
+ cipher := cipher(),
+ mac := hash() | aead,
+ prf := hash() | default_prf %% Old cipher suites, version dependent
+ }.
+-type old_erl_cipher_suite() :: {key_algo(), cipher(), hash()} % Pre TLS 1.2
+ %% TLS 1.2, internally PRE TLS 1.2 will use default_prf
+ | {key_algo(), cipher(), hash(), hash() | default_prf}.
+-type cipher_suite() :: binary().
+-type openssl_cipher_suite() :: string().
+
+
+-export([suite_to_str/1, suite_definition/1, suite/1, erl_suite_definition/1,
+ openssl_suite/1, openssl_suite_name/1]).
+
+%%--------------------------------------------------------------------
+-spec suite_to_str(erl_cipher_suite()) -> string().
+%%
+%% Description: Return the string representation of a cipher suite.
+%%--------------------------------------------------------------------
+suite_to_str(#{key_exchange := null,
+ cipher := null,
+ mac := null,
+ prf := null}) ->
+ "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+suite_to_str(#{key_exchange := any,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(PRF));
+suite_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := aead,
+ prf := PRF}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(PRF));
+suite_to_str(#{key_exchange := Kex,
+ cipher := Cipher,
+ mac := Mac}) ->
+ "TLS_" ++ string:to_upper(atom_to_list(Kex)) ++
+ "_WITH_" ++ string:to_upper(atom_to_list(Cipher)) ++
+ "_" ++ string:to_upper(atom_to_list(Mac)).
+
+%%--------------------------------------------------------------------
+-spec suite_definition(cipher_suite()) -> erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition.
+%% Note: Currently not supported suites are commented away.
+%% They should be supported or removed in the future.
+%%-------------------------------------------------------------------
+%% TLS v1.1 suites
+suite_definition(?TLS_NULL_WITH_NULL_NULL) ->
+ #{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null};
+%% RFC 5746 - Not a real cipher suite used to signal empty "renegotiation_info" extension
+%% to avoid handshake failure from old servers that do not ignore
+%% hello extension data as they should.
+suite_definition(?TLS_EMPTY_RENEGOTIATION_INFO_SCSV) ->
+ #{key_exchange => null,
+ cipher => null,
+ mac => null,
+ prf => null};
+suite_definition(?TLS_RSA_WITH_RC4_128_MD5) ->
+ #{key_exchange => rsa,
+ cipher => rc4_128,
+ mac => md5,
+ prf => default_prf};
+suite_definition(?TLS_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_WITH_DES_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+%%% TSL V1.1 AES suites
+suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% TLS v1.2 suites
+%% suite_definition(?TLS_RSA_WITH_NULL_SHA) ->
+%% {rsa, null, sha, default_prf};
+suite_definition(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+%% not defined YET:
+%% TLS_DH_DSS_WITH_AES_128_CBC_SHA256 DH_DSS AES_128_CBC SHA256
+%% TLS_DH_RSA_WITH_AES_128_CBC_SHA256 DH_RSA AES_128_CBC SHA256
+%% TLS_DH_DSS_WITH_AES_256_CBC_SHA256 DH_DSS AES_256_CBC SHA256
+%% TLS_DH_RSA_WITH_AES_256_CBC_SHA256 DH_RSA AES_256_CBC SHA256
+%%% DH-ANON deprecated by TLS spec and not available
+%%% by default, but good for testing purposes.
+suite_definition(?TLS_DH_anon_WITH_RC4_128_MD5) ->
+ #{key_exchange => dh_anon,
+ cipher => rc4_128,
+ mac => md5,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_DES_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => des_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DH_anon_WITH_AES_256_CBC_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_cbc,
+ mac => sha256,
+ prf => default_prf};
+%%% PSK Cipher Suites RFC 4279
+suite_definition(?TLS_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%%% PSK NULL Cipher Suites RFC 4785
+suite_definition(?TLS_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+suite_definition(?TLS_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => psk,
+ cipher => null,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_DHE_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => dhe_psk,
+ cipher => null,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_RSA_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => rsa_psk,
+ cipher => null,
+ mac => sha384,
+ prf => default_prf};
+%%% ECDHE PSK Cipher Suites RFC 5489
+suite_definition(?TLS_ECDHE_PSK_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_NULL_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => null,
+ mac => sha256,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_PSK_WITH_NULL_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => null, mac => sha384,
+ prf => default_prf};
+%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_128_gcm,
+ mac => null,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_psk,
+ cipher => aes_256_gcm,
+ mac => null,
+ prf => sha384};
+%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256) ->
+%% #{key_exchange => ecdhe_psk,
+%% cipher => aes_128_ccm,
+%% mac => null,
+%% prf =>sha256};
+%% suite_definition(?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256) ->
+%% #{key_exchange => ecdhe_psk,
+%% cipher => aes_256_ccm,
+%% mac => null,
+%% prf => sha256};
+%%% SRP Cipher Suites RFC 5054
+suite_definition(?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => srp_dss,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% RFC 4492 EC TLS suites
+suite_definition(?TLS_ECDH_ECDSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_NULL_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_NULL_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => null,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_RC4_128_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => rc4_128,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => '3des_ede_cbc',
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_128_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => aes_128_cbc,
+ mac => sha,
+ prf => default_prf};
+suite_definition(?TLS_ECDH_anon_WITH_AES_256_CBC_SHA) ->
+ #{key_exchange => ecdh_anon,
+ cipher => aes_256_cbc,
+ mac => sha,
+ prf => default_prf};
+%% RFC 5289 EC TLS suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_cbc,
+ mac => sha256,
+ prf => sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_cbc,
+ mac => sha384,
+ prf => sha384};
+%% RFC 5288 AES-GCM Cipher Suites
+suite_definition(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dhe_dss,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_dss,
+ cipher => aes_128_gcm,
+ mac => null,
+ prf => sha256};
+suite_definition(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_dss,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_DH_anon_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DH_anon_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => dh_anon,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+%% RFC 5289 ECC AES-GCM Cipher Suites
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdh_ecdsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
+ #{key_exchange => ecdh_rsa,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite_definition(?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => ecdhe_rsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => ecdhe_ecdsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => dhe_rsa,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256};
+%% TLS 1.3 Cipher Suites RFC8446
+suite_definition(?TLS_AES_128_GCM_SHA256) ->
+ #{key_exchange => any,
+ cipher => aes_128_gcm,
+ mac => aead,
+ prf => sha256};
+suite_definition(?TLS_AES_256_GCM_SHA384) ->
+ #{key_exchange => any,
+ cipher => aes_256_gcm,
+ mac => aead,
+ prf => sha384};
+suite_definition(?TLS_CHACHA20_POLY1305_SHA256) ->
+ #{key_exchange => any,
+ cipher => chacha20_poly1305,
+ mac => aead,
+ prf => sha256}.
+%% suite_definition(?TLS_AES_128_CCM_SHA256) ->
+%% #{key_exchange => any,
+%% cipher => aes_128_ccm,
+%% mac => aead,
+%% prf => sha256};
+%% suite_definition(?TLS_AES_128_CCM_8_SHA256) ->
+%% #{key_exchange => any,
+%% cipher => aes_128_ccm_8,
+%% mac => aead,
+%% prf => sha256}.
+
+
+%%--------------------------------------------------------------------
+-spec erl_suite_definition(cipher_suite() | erl_cipher_suite()) -> old_erl_cipher_suite().
+%%
+%% Description: Return erlang cipher suite definition. Filters last value
+%% for now (compatibility reasons).
+%%--------------------------------------------------------------------
+erl_suite_definition(Bin) when is_binary(Bin) ->
+ erl_suite_definition(suite_definition(Bin));
+erl_suite_definition(#{key_exchange := KeyExchange, cipher := Cipher,
+ mac := Hash, prf := Prf}) ->
+ case Prf of
+ default_prf ->
+ {KeyExchange, Cipher, Hash};
+ _ ->
+ {KeyExchange, Cipher, Hash, Prf}
+ end.
+
+%%--------------------------------------------------------------------
+-spec suite(erl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
+%% TLS v1.1 suites
+suite(#{key_exchange := rsa,
+ cipher := rc4_128,
+ mac := md5}) ->
+ ?TLS_RSA_WITH_RC4_128_MD5;
+suite(#{key_exchange := rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_RC4_128_SHA;
+suite(#{key_exchange := rsa,
+ cipher := des_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+suite(#{key_exchange := rsa,
+ cipher :='3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := dhe_dss,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_DES_CBC_SHA;
+suite(#{key_exchange := dhe_dss,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := dhe_rsa,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
+suite(#{key_exchange := dhe_rsa,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := dh_anon,
+ cipher:= rc4_128,
+ mac := md5}) ->
+ ?TLS_DH_anon_WITH_RC4_128_MD5;
+suite(#{key_exchange := dh_anon,
+ cipher:= des_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_DES_CBC_SHA;
+suite(#{key_exchange := dh_anon,
+ cipher:= '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+%%% TSL V1.1 AES suites
+suite(#{key_exchange := rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA;
+%% TLS v1.2 suites
+suite(#{key_exchange := rsa,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_256_cbc,
+ mac := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_256_CBC_SHA256;
+%%% PSK Cipher Suites RFC 4279
+suite(#{key_exchange := psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_RC4_128_SHA;
+suite(#{key_exchange := psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := dhe_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_RC4_128_SHA;
+suite(#{key_exchange := dhe_psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := rsa_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_RC4_128_SHA;
+suite(#{key_exchange := rsa_psk,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+%%% PSK NULL Cipher Suites RFC 4785
+suite(#{key_exchange := psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_PSK_WITH_NULL_SHA;
+suite(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA;
+suite(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA;
+%%% TLS 1.2 PSK Cipher Suites RFC 5487
+suite(#{key_exchange := psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_PSK_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_PSK_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_PSK_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_DHE_PSK_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := dhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_DHE_PSK_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_RSA_PSK_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := rsa_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_RSA_PSK_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_PSK_WITH_NULL_SHA256;
+suite(#{key_exchange := psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_PSK_WITH_NULL_SHA384;
+suite(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA256;
+suite(#{key_exchange := dhe_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_DHE_PSK_WITH_NULL_SHA384;
+suite(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA256;
+suite(#{key_exchange := rsa_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_RSA_PSK_WITH_NULL_SHA384;
+%%% ECDHE PSK Cipher Suites RFC 5489
+suite(#{key_exchange := ecdhe_psk,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdhe_psk,
+ cipher :='3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_cbc,
+ mac := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_cbc,
+ mac := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := null,
+ mac := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_NULL_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := null,
+ mac := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_NULL_SHA384;
+%%% ECDHE_PSK with AES-GCM and AES-CCM Cipher Suites, draft-ietf-tls-ecdhe-psk-aead-05
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_128_gcm,
+ mac := null,
+ prf := sha256}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := ecdhe_psk,
+ cipher := aes_256_gcm,
+ mac := null,
+ prf := sha384}) ->
+ ?TLS_ECDHE_PSK_WITH_AES_256_GCM_SHA384;
+ %% suite(#{key_exchange := ecdhe_psk,
+ %% cipher := aes_128_ccm,
+ %% mac := null,
+ %% prf := sha256}) ->
+ %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_8_SHA256;
+ %% suite(#{key_exchange := ecdhe_psk,
+ %% cipher := aes_256_ccm,
+ %% mac := null,
+ %% prf := sha256}) ->
+ %% ?TLS_ECDHE_PSK_WITH_AES_128_CCM_SHA256;
+%%% SRP Cipher Suites RFC 5054
+suite(#{key_exchange := srp_anon,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := srp_rsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := srp_dss,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := srp_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := srp_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := srp_dss,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := srp_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := srp_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := srp_dss,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+%%% RFC 4492 EC TLS suites
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_NULL_SHA;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_NULL_SHA;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_NULL_SHA;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := '3des_ede_cbc', mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_NULL_SHA;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+suite(#{key_exchange := ecdh_anon,
+ cipher := null,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_NULL_SHA;
+suite(#{key_exchange := ecdh_anon,
+ cipher := rc4_128,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_RC4_128_SHA;
+suite(#{key_exchange := ecdh_anon,
+ cipher := '3des_ede_cbc',
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA;
+suite(#{key_exchange := ecdh_anon,
+ cipher := aes_128_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_128_CBC_SHA;
+suite(#{key_exchange := ecdh_anon,
+ cipher := aes_256_cbc,
+ mac := sha}) ->
+ ?TLS_ECDH_anon_WITH_AES_256_CBC_SHA;
+%%% RFC 5289 EC TLS suites
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_cbc,
+ mac:= sha256,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_cbc,
+ mac := sha256,
+ prf := sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_cbc,
+ mac := sha384,
+ prf := sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
+%% RFC 5288 AES-GCM Cipher Suites
+suite(#{key_exchange := rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_RSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_RSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dhe_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dh_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dh_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dhe_dss,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dh_dss,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dh_dss,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DH_anon_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := dh_anon,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_DH_anon_WITH_AES_256_GCM_SHA384;
+%% RFC 5289 ECC AES-GCM Cipher Suites
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := ecdh_ecdsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+suite(#{key_exchange := ecdh_rsa,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+%% draft-agl-tls-chacha20poly1305-04 Chacha20/Poly1305 Suites
+suite(#{key_exchange := ecdhe_rsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+suite(#{key_exchange := ecdhe_ecdsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256;
+suite(#{key_exchange := dhe_rsa,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256;
+%% TLS 1.3 Cipher Suites RFC8446
+suite(#{key_exchange := any,
+ cipher := aes_128_gcm,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_AES_128_GCM_SHA256;
+suite(#{key_exchange := any,
+ cipher := aes_256_gcm,
+ mac := aead,
+ prf := sha384}) ->
+ ?TLS_AES_256_GCM_SHA384;
+suite(#{key_exchange := any,
+ cipher := chacha20_poly1305,
+ mac := aead,
+ prf := sha256}) ->
+ ?TLS_CHACHA20_POLY1305_SHA256.
+%% suite(#{key_exchange := any,
+%% cipher := aes_128_ccm,
+%% mac := aead,
+%% prf := sha256}) ->
+%% ?TLS_AES_128_CCM_SHA256;
+%% suite(#{key_exchange := any,
+%% cipher := aes_128_ccm_8,
+%% mac := aead,
+%% prf := sha256}) ->
+%% ?TLS_AES_128_CCM_8_SHA256.
+%%--------------------------------------------------------------------
+-spec openssl_suite(openssl_cipher_suite()) -> cipher_suite().
+%%
+%% Description: Return TLS cipher suite definition.
+%%--------------------------------------------------------------------
+%% translate constants <-> openssl-strings
+openssl_suite("DHE-RSA-AES256-SHA256") ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256;
+openssl_suite("DHE-DSS-AES256-SHA256") ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256;
+openssl_suite("AES256-SHA256") ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA256;
+openssl_suite("DHE-RSA-AES128-SHA256") ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("DHE-DSS-AES128-SHA256") ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256;
+openssl_suite("AES128-SHA256") ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("DHE-RSA-AES256-SHA") ->
+ ?TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("DHE-DSS-AES256-SHA") ->
+ ?TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("AES256-SHA") ->
+ ?TLS_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("EDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("EDH-DSS-DES-CBC3-SHA") ->
+ ?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("DES-CBC3-SHA") ->
+ ?TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("DHE-RSA-AES128-SHA") ->
+ ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("DHE-DSS-AES128-SHA") ->
+ ?TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+openssl_suite("AES128-SHA") ->
+ ?TLS_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("RC4-SHA") ->
+ ?TLS_RSA_WITH_RC4_128_SHA;
+openssl_suite("RC4-MD5") ->
+ ?TLS_RSA_WITH_RC4_128_MD5;
+openssl_suite("EDH-RSA-DES-CBC-SHA") ->
+ ?TLS_DHE_RSA_WITH_DES_CBC_SHA;
+openssl_suite("DES-CBC-SHA") ->
+ ?TLS_RSA_WITH_DES_CBC_SHA;
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite("SRP-DSS-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-RSA-AES-256-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+openssl_suite("SRP-DSS-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-RSA-3DES-EDE-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("SRP-DSS-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+openssl_suite("SRP-RSA-AES-128-CBC-SHA") ->
+ ?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+
+%% RFC 4492 EC TLS suites
+openssl_suite("ECDH-ECDSA-RC4-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES128-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-ECDSA-AES256-SHA") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-ECDSA-RC4-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-ECDSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES128-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-ECDSA-AES256-SHA") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDHE-RSA-RC4-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDHE-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES128-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDHE-RSA-AES256-SHA") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA;
+
+openssl_suite("ECDH-RSA-RC4-SHA") ->
+ ?TLS_ECDH_RSA_WITH_RC4_128_SHA;
+openssl_suite("ECDH-RSA-DES-CBC3-SHA") ->
+ ?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA;
+openssl_suite("ECDH-RSA-AES128-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA;
+openssl_suite("ECDH-RSA-AES256-SHA") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA;
+
+%% RFC 5289 EC TLS suites
+openssl_suite("ECDHE-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDHE-RSA-AES128-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDHE-RSA-AES256-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384;
+openssl_suite("ECDH-RSA-AES128-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256;
+openssl_suite("ECDH-RSA-AES256-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384;
+
+%% RFC 5288 AES-GCM Cipher Suites
+openssl_suite("AES128-GCM-SHA256") ->
+ ?TLS_RSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("AES256-GCM-SHA384") ->
+ ?TLS_RSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("DHE-RSA-AES128-GCM-SHA256") ->
+ ?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("DHE-RSA-AES256-GCM-SHA384") ->
+ ?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("DH-RSA-AES128-GCM-SHA256") ->
+ ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("DH-RSA-AES256-GCM-SHA384") ->
+ ?TLS_DH_RSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("DHE-DSS-AES128-GCM-SHA256") ->
+ ?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256;
+openssl_suite("DHE-DSS-AES256-GCM-SHA384") ->
+ ?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384;
+openssl_suite("DH-DSS-AES128-GCM-SHA256") ->
+ ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256;
+openssl_suite("DH-DSS-AES256-GCM-SHA384") ->
+ ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384;
+
+%% RFC 5289 ECC AES-GCM Cipher Suites
+openssl_suite("ECDHE-ECDSA-AES128-GCM-SHA256") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("ECDHE-ECDSA-AES256-GCM-SHA384") ->
+ ?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("ECDH-ECDSA-AES128-GCM-SHA256") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("ECDH-ECDSA-AES256-GCM-SHA384") ->
+ ?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("ECDHE-RSA-AES128-GCM-SHA256") ->
+ ?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("ECDHE-RSA-AES256-GCM-SHA384") ->
+ ?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384;
+openssl_suite("ECDH-RSA-AES128-GCM-SHA256") ->
+ ?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256;
+openssl_suite("ECDH-RSA-AES256-GCM-SHA384") ->
+ ?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384;
+
+%% TLS 1.3 Cipher Suites RFC8446
+openssl_suite("TLS_AES_128_GCM_SHA256") ->
+ ?TLS_AES_128_GCM_SHA256;
+openssl_suite("TLS_AES_256_GCM_SHA384") ->
+ ?TLS_AES_256_GCM_SHA384;
+openssl_suite("TLS_CHACHA20_POLY1305_SHA256") ->
+ ?TLS_CHACHA20_POLY1305_SHA256.
+%% openssl_suite("TLS_AES_128_CCM_SHA256") ->
+%% ?TLS_AES_128_CCM_SHA256;
+%% openssl_suite("TLS_AES_128_CCM_8_SHA256") ->
+%% ?TLS_AES_128_CCM_8_SHA256.
+
+
+%%--------------------------------------------------------------------
+-spec openssl_suite_name(cipher_suite()) -> openssl_cipher_suite() | erl_cipher_suite().
+%%
+%% Description: Return openssl cipher suite name if possible
+%%-------------------------------------------------------------------
+openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "DHE-RSA-AES256-SHA";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA) ->
+ "DHE-DSS-AES256-SHA";
+openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA) ->
+ "AES256-SHA";
+openssl_suite_name(?TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "EDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "EDH-DSS-DES-CBC3-SHA";
+openssl_suite_name(?TLS_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "DES-CBC3-SHA";
+openssl_suite_name( ?TLS_DHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "DHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA) ->
+ "DHE-DSS-AES128-SHA";
+openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA) ->
+ "AES128-SHA";
+openssl_suite_name(?TLS_RSA_WITH_RC4_128_SHA) ->
+ "RC4-SHA";
+openssl_suite_name(?TLS_RSA_WITH_RC4_128_MD5) ->
+ "RC4-MD5";
+openssl_suite_name(?TLS_DHE_RSA_WITH_DES_CBC_SHA) ->
+ "EDH-RSA-DES-CBC-SHA";
+openssl_suite_name(?TLS_RSA_WITH_DES_CBC_SHA) ->
+ "DES-CBC-SHA";
+openssl_suite_name(?TLS_RSA_WITH_NULL_SHA256) ->
+ "NULL-SHA256";
+openssl_suite_name(?TLS_RSA_WITH_AES_128_CBC_SHA256) ->
+ "AES128-SHA256";
+openssl_suite_name(?TLS_RSA_WITH_AES_256_CBC_SHA256) ->
+ "AES256-SHA256";
+openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_CBC_SHA256) ->
+ "DH-DSS-AES128-SHA256";
+openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "DH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_CBC_SHA256) ->
+ "DHE-DSS-AES128-SHA256";
+openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "DHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_CBC_SHA256) ->
+ "DH-DSS-AES256-SHA256";
+openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_CBC_SHA256) ->
+ "DH-RSA-AES256-SHA256";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_CBC_SHA256) ->
+ "DHE-DSS-AES256-SHA256";
+openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_CBC_SHA256) ->
+ "DHE-RSA-AES256-SHA256";
+
+%%% PSK Cipher Suites RFC 4279
+
+openssl_suite_name(?TLS_PSK_WITH_AES_256_CBC_SHA) ->
+ "PSK-AES256-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_3DES_EDE_CBC_SHA) ->
+ "PSK-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_AES_128_CBC_SHA) ->
+ "PSK-AES128-CBC-SHA";
+openssl_suite_name(?TLS_PSK_WITH_RC4_128_SHA) ->
+ "PSK-RC4-SHA";
+
+%%% SRP Cipher Suites RFC 5054
+
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-RSA-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) ->
+ "SRP-DSS-3DES-EDE-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA) ->
+ "SRP-RSA-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) ->
+ "SRP-DSS-AES-128-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA) ->
+ "SRP-RSA-AES-256-CBC-SHA";
+openssl_suite_name(?TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) ->
+ "SRP-DSS-AES-256-CBC-SHA";
+
+%% RFC 4492 EC TLS suites
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDH-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_RC4_128_SHA) ->
+ "ECDHE-ECDSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-ECDSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-ECDSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-ECDSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDH_RSA_WITH_RC4_128_SHA) ->
+ "ECDH-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDH-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDH-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDH-RSA-AES256-SHA";
+
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_RC4_128_SHA) ->
+ "ECDHE-RSA-RC4-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA) ->
+ "ECDHE-RSA-DES-CBC3-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA) ->
+ "ECDHE-RSA-AES128-SHA";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA) ->
+ "ECDHE-RSA-AES256-SHA";
+
+%% RFC 5289 EC TLS suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-ECDSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-ECDSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDHE-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDHE-RSA-AES256-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256) ->
+ "ECDH-RSA-AES128-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384) ->
+ "ECDH-RSA-AES256-SHA384";
+
+%% RFC 5288 AES-GCM Cipher Suites
+openssl_suite_name(?TLS_RSA_WITH_AES_128_GCM_SHA256) ->
+ "AES128-GCM-SHA256";
+openssl_suite_name(?TLS_RSA_WITH_AES_256_GCM_SHA384) ->
+ "AES256-GCM-SHA384";
+openssl_suite_name(?TLS_DHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ "DHE-RSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_DHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ "DHE-RSA-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_DH_RSA_WITH_AES_128_GCM_SHA256) ->
+ "DH-RSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_DH_RSA_WITH_AES_256_GCM_SHA384) ->
+ "DH-RSA-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_128_GCM_SHA256) ->
+ "DHE-DSS-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_DHE_DSS_WITH_AES_256_GCM_SHA384) ->
+ "DHE-DSS-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_DH_DSS_WITH_AES_128_GCM_SHA256) ->
+ "DH-DSS-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_DH_DSS_WITH_AES_256_GCM_SHA384) ->
+ "DH-DSS-AES256-GCM-SHA384";
+
+%% RFC 5289 ECC AES-GCM Cipher Suites
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ "ECDHE-ECDSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ "ECDHE-ECDSA-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256) ->
+ "ECDH-ECDSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384) ->
+ "ECDH-ECDSA-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) ->
+ "ECDHE-RSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) ->
+ "ECDHE-RSA-AES256-GCM-SHA384";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256) ->
+ "ECDH-RSA-AES128-GCM-SHA256";
+openssl_suite_name(?TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384) ->
+ "ECDH-RSA-AES256-GCM-SHA384";
+
+%% TLS 1.3 Cipher Suites RFC8446
+openssl_suite_name(?TLS_AES_128_GCM_SHA256) ->
+ "TLS_AES_128_GCM_SHA256";
+openssl_suite_name(?TLS_AES_256_GCM_SHA384) ->
+ "TLS_AES_256_GCM_SHA384";
+openssl_suite_name(?TLS_CHACHA20_POLY1305_SHA256) ->
+ "TLS_CHACHA20_POLY1305_SHA256";
+%% openssl_suite(?TLS_AES_128_CCM_SHA256) ->
+%% "TLS_AES_128_CCM_SHA256";
+%% openssl_suite(?TLS_AES_128_CCM_8_SHA256) ->
+%% "TLS_AES_128_CCM_8_SHA256";
+
+%% No oppenssl name
+openssl_suite_name(Cipher) ->
+ suite_definition(Cipher).
diff --git a/lib/ssl/src/ssl_config.erl b/lib/ssl/src/ssl_config.erl
index 63c0a416ef..1e6dab9276 100644
--- a/lib/ssl/src/ssl_config.erl
+++ b/lib/ssl/src/ssl_config.erl
@@ -91,9 +91,9 @@ init_certificates(undefined, #{pem_cache := PemCache} = Config, CertFile, server
end;
init_certificates(Cert, Config, _, _) ->
{ok, Config#{own_certificate => Cert}}.
-init_private_key(_, #{algorithm := Alg} = Key, <<>>, _Password, _Client) when Alg == ecdsa;
- Alg == rsa;
- Alg == dss ->
+init_private_key(_, #{algorithm := Alg} = Key, _, _Password, _Client) when Alg == ecdsa;
+ Alg == rsa;
+ Alg == dss ->
case maps:is_key(engine, Key) andalso maps:is_key(key_id, Key) of
true ->
Key;
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index bd17f19d10..6e602eac23 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -56,22 +56,22 @@
]).
%% Data handling
--export([write_application_data/3, read_application_data/2]).
+-export([read_application_data/2, internal_renegotiation/2]).
%% Help functions for tls|dtls_connection.erl
-export([handle_session/7, ssl_config/3,
- prepare_connection/2, hibernate_after/3, map_extensions/1]).
+ prepare_connection/2, hibernate_after/3]).
%% General gen_statem state functions with extra callback argument
%% to determine if it is an SSL/TLS or DTLS gen_statem machine
-export([init/4, error/4, hello/4, user_hello/4, abbreviated/4, certify/4, cipher/4,
- connection/4, death_row/4, downgrade/4]).
+ connection/4, downgrade/4]).
%% gen_statem callbacks
-export([terminate/3, format_status/2]).
%% Erlang Distribution export
--export([get_sslsocket/1, handshake_complete/3]).
+-export([get_sslsocket/1, dist_handshake_complete/2]).
%%====================================================================
%% Setup
@@ -119,7 +119,7 @@ handshake(Connection, Port, Socket, Opts, User, CbInfo, Timeout) ->
%%
%% Description: Starts ssl handshake.
%%--------------------------------------------------------------------
-handshake(#sslsocket{pid = Pid} = Socket, Timeout) ->
+handshake(#sslsocket{pid = [Pid|_]} = Socket, Timeout) ->
case call(Pid, {start, Timeout}) of
connected ->
{ok, Socket};
@@ -135,7 +135,7 @@ handshake(#sslsocket{pid = Pid} = Socket, Timeout) ->
%%
%% Description: Starts ssl handshake with some new options
%%--------------------------------------------------------------------
-handshake(#sslsocket{pid = Pid} = Socket, SslOptions, Timeout) ->
+handshake(#sslsocket{pid = [Pid|_]} = Socket, SslOptions, Timeout) ->
case call(Pid, {start, SslOptions, Timeout}) of
connected ->
{ok, Socket};
@@ -149,7 +149,7 @@ handshake(#sslsocket{pid = Pid} = Socket, SslOptions, Timeout) ->
%%
%% Description: Continues handshake with new options
%%--------------------------------------------------------------------
-handshake_continue(#sslsocket{pid = Pid} = Socket, SslOptions, Timeout) ->
+handshake_continue(#sslsocket{pid = [Pid|_]} = Socket, SslOptions, Timeout) ->
case call(Pid, {handshake_continue, SslOptions, Timeout}) of
connected ->
{ok, Socket};
@@ -161,7 +161,7 @@ handshake_continue(#sslsocket{pid = Pid} = Socket, SslOptions, Timeout) ->
%%
%% Description: Cancels connection
%%--------------------------------------------------------------------
-handshake_cancel(#sslsocket{pid = Pid}) ->
+handshake_cancel(#sslsocket{pid = [Pid|_]}) ->
case call(Pid, cancel) of
closed ->
ok;
@@ -169,7 +169,7 @@ handshake_cancel(#sslsocket{pid = Pid}) ->
Error
end.
%--------------------------------------------------------------------
--spec socket_control(tls_connection | dtls_connection, port(), pid(), atom()) ->
+-spec socket_control(tls_connection | dtls_connection, port(), [pid()], atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Set the ssl process to own the accept socket
@@ -178,24 +178,24 @@ socket_control(Connection, Socket, Pid, Transport) ->
socket_control(Connection, Socket, Pid, Transport, undefined).
%--------------------------------------------------------------------
--spec socket_control(tls_connection | dtls_connection, port(), pid(), atom(), pid()| undefined) ->
+-spec socket_control(tls_connection | dtls_connection, port(), [pid()], atom(), pid()| atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%--------------------------------------------------------------------
-socket_control(Connection, Socket, Pid, Transport, udp_listener) ->
+socket_control(Connection, Socket, Pids, Transport, udp_listener) ->
%% dtls listener process must have the socket control
- {ok, Connection:socket(Pid, Transport, Socket, Connection, undefined)};
+ {ok, Connection:socket(Pids, Transport, Socket, Connection, undefined)};
-socket_control(tls_connection = Connection, Socket, Pid, Transport, ListenTracker) ->
+socket_control(tls_connection = Connection, Socket, [Pid|_] = Pids, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, Connection:socket(Pids, Transport, Socket, Connection, ListenTracker)};
{error, Reason} ->
{error, Reason}
end;
-socket_control(dtls_connection = Connection, {_, Socket}, Pid, Transport, ListenTracker) ->
+socket_control(dtls_connection = Connection, {_, Socket}, [Pid|_] = Pids, Transport, ListenTracker) ->
case Transport:controlling_process(Socket, Pid) of
ok ->
- {ok, Connection:socket(Pid, Transport, Socket, Connection, ListenTracker)};
+ {ok, Connection:socket(Pids, Transport, Socket, Connection, ListenTracker)};
{error, Reason} ->
{error, Reason}
end.
@@ -307,12 +307,20 @@ peer_certificate(ConnectionPid) ->
renegotiation(ConnectionPid) ->
call(ConnectionPid, renegotiate).
+%%--------------------------------------------------------------------
+-spec internal_renegotiation(pid(), ssl_record:connection_states()) ->
+ ok.
+%%
+%% Description: Starts a renegotiation of the ssl session.
+%%--------------------------------------------------------------------
+internal_renegotiation(ConnectionPid, #{current_write := WriteState}) ->
+ gen_statem:cast(ConnectionPid, {internal_renegotiate, WriteState}).
get_sslsocket(ConnectionPid) ->
call(ConnectionPid, get_sslsocket).
-handshake_complete(ConnectionPid, Node, DHandle) ->
- call(ConnectionPid, {handshake_complete, Node, DHandle}).
+dist_handshake_complete(ConnectionPid, DHandle) ->
+ gen_statem:cast(ConnectionPid, {dist_handshake_complete, DHandle}).
%%--------------------------------------------------------------------
-spec prf(pid(), binary() | 'master_secret', binary(),
@@ -327,21 +335,12 @@ prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-handle_own_alert(Alert, Version, StateName,
+handle_own_alert(Alert, _, StateName,
#state{role = Role,
- transport_cb = Transport,
- socket = Socket,
protocol_cb = Connection,
- connection_states = ConnectionStates,
ssl_options = SslOpts} = State) ->
try %% Try to tell the other side
- {BinMsg, _} =
- Connection:encode_alert(Alert, Version, ConnectionStates),
- Connection:send(Transport, Socket, BinMsg),
- Report = #{direction => outbound,
- protocol => 'tls_record',
- message => BinMsg},
- ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]})
+ send_alert(Alert, StateName, State)
catch _:_ -> %% Can crash if we are in a uninitialized state
ignore
end,
@@ -360,8 +359,9 @@ handle_normal_shutdown(Alert, _, #state{socket = Socket,
protocol_cb = Connection,
start_or_recv_from = StartFrom,
tracker = Tracker,
- role = Role, renegotiation = {false, first}}) ->
- alert_user(Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
+ role = Role, renegotiation = {false, first}} = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker,Socket, StartFrom, Alert, Role, Connection);
handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
socket_options = Opts,
@@ -369,20 +369,22 @@ handle_normal_shutdown(Alert, StateName, #state{socket = Socket,
protocol_cb = Connection,
user_application = {_Mon, Pid},
tracker = Tracker,
- start_or_recv_from = RecvFrom, role = Role}) ->
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
+ start_or_recv_from = RecvFrom, role = Role} = State) ->
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, RecvFrom, Alert, Role, Connection).
handle_alert(#alert{level = ?FATAL} = Alert, StateName,
#state{socket = Socket, transport_cb = Transport,
protocol_cb = Connection,
ssl_options = SslOpts, start_or_recv_from = From, host = Host,
port = Port, session = Session, user_application = {_Mon, Pid},
- role = Role, socket_options = Opts, tracker = Tracker} = State) ->
+ role = Role, socket_options = Opts,
+ tracker = Tracker} = State) ->
invalidate_session(Role, Host, Port, Session),
- log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName,
- Alert#alert{role = opposite_role(Role)}),
- alert_user(Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection),
+ log_alert(SslOpts#ssl_options.log_level, Role, Connection:protocol_name(),
+ StateName, Alert#alert{role = opposite_role(Role)}),
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker, Socket, StateName, Opts, Pid, From, Alert, Role, Connection),
stop(normal, State);
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
@@ -391,13 +393,24 @@ handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
stop({shutdown, peer_close}, State);
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{role = Role, ssl_options = SslOpts, protocol_cb = Connection, renegotiation = {true, internal}} = State) ->
- log_alert(SslOpts#ssl_options.log_level, Role,
- Connection:protocol_name(), StateName,
- Alert#alert{role = opposite_role(Role)}),
+ #state{role = Role, ssl_options = SslOpts, protocol_cb = Connection,
+ renegotiation = {true, internal}} = State) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
handle_normal_shutdown(Alert, StateName, State),
stop({shutdown, peer_close}, State);
+handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, connection = StateName,
+ #state{role = Role,
+ ssl_options = SslOpts, renegotiation = {true, From},
+ protocol_cb = Connection} = State0) ->
+ log_alert(SslOpts#ssl_options.log_level, Role,
+ Connection:protocol_name(), StateName, Alert#alert{role = opposite_role(Role)}),
+ gen_statem:reply(From, {error, renegotiation_rejected}),
+ State1 = Connection:reinit_handshake_data(State0),
+ {Record, State} = Connection:next_record(State1#state{renegotiation = undefined}),
+ Connection:next_event(connection, Record, State);
+
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
#state{role = Role,
ssl_options = SslOpts, renegotiation = {true, From},
@@ -408,7 +421,7 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
gen_statem:reply(From, {error, renegotiation_rejected}),
{Record, State1} = Connection:next_record(State0),
%% Go back to connection!
- State = Connection:reinit_handshake_data(State1#state{renegotiation = undefined}),
+ State = Connection:reinit(State1#state{renegotiation = undefined}),
Connection:next_event(connection, Record, State);
%% Gracefully log and ignore all other warning alerts
@@ -423,41 +436,6 @@ handle_alert(#alert{level = ?WARNING} = Alert, StateName,
%%====================================================================
%% Data handling
%%====================================================================
-write_application_data(Data0, {FromPid, _} = From,
- #state{socket = Socket,
- negotiated_version = Version,
- protocol_cb = Connection,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt} = SslOpts} = State) ->
- Data = encode_packet(Data0, SockOpts),
-
- case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
- true ->
- Connection:renegotiate(State#state{renegotiation = {true, internal}},
- [{next_event, {call, From}, {application_data, Data0}}]);
- false ->
- {Msgs, ConnectionStates} =
- Connection:encode_data(Data, Version, ConnectionStates0),
- NewState = State#state{connection_states = ConnectionStates},
- RetVal = case Connection:send(Transport, Socket, Msgs) of
- ok when FromPid =:= self() ->
- hibernate_after(connection, NewState, []);
- Error when FromPid =:= self() ->
- stop({shutdown, Error}, NewState);
- ok ->
- hibernate_after(connection, NewState, [{reply, From, ok}]);
- Result ->
- hibernate_after(connection, NewState, [{reply, From, Result}])
- end,
- Report = #{direction => outbound,
- protocol => 'tls_record',
- message => Msgs},
- ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
- RetVal
- end.
-
read_application_data(Data, #state{user_application = {_Mon, Pid},
socket = Socket,
protocol_cb = Connection,
@@ -475,58 +453,74 @@ read_application_data(Data, #state{user_application = {_Mon, Pid},
end,
case get_data(SOpts, BytesToRead, Buffer1) of
{ok, ClientData, Buffer} -> % Send data
- case State0 of
- #state{
- ssl_options = #ssl_options{erl_dist = true},
- protocol_specific = #{d_handle := DHandle}} ->
- State =
- State0#state{
- user_data_buffer = Buffer,
- bytes_to_read = undefined},
- try erlang:dist_ctrl_put_data(DHandle, ClientData) of
- _
- when SOpts#socket_options.active =:= false;
- Buffer =:= <<>> ->
- %% Passive mode, wait for active once or recv
- %% Active and empty, get more data
- Connection:next_record_if_active(State);
- _ -> %% We have more data
- read_application_data(<<>>, State)
- catch error:_ ->
- death_row(State, disconnect)
- end;
- _ ->
- SocketOpt =
- deliver_app_data(
- Transport, Socket, SOpts,
- ClientData, Pid, RecvFrom, Tracker, Connection),
- cancel_timer(Timer),
- State =
- State0#state{
- user_data_buffer = Buffer,
+ #state{ssl_options = #ssl_options{erl_dist = Dist},
+ erl_dist_data = DistData} = State0,
+ case Dist andalso is_dist_up(DistData) of
+ true ->
+ dist_app_data(ClientData, State0#state{user_data_buffer = Buffer,
+ bytes_to_read = undefined});
+ _ ->
+ SocketOpt =
+ deliver_app_data(Connection:pids(State0),
+ Transport, Socket, SOpts,
+ ClientData, Pid, RecvFrom, Tracker, Connection),
+ cancel_timer(Timer),
+ State =
+ State0#state{
+ user_data_buffer = Buffer,
start_or_recv_from = undefined,
timer = undefined,
bytes_to_read = undefined,
socket_options = SocketOpt
- },
- if
- SocketOpt#socket_options.active =:= false;
- Buffer =:= <<>> ->
- %% Passive mode, wait for active once or recv
+ },
+ if
+ SocketOpt#socket_options.active =:= false;
+ Buffer =:= <<>> ->
+ %% Passive mode, wait for active once or recv
%% Active and empty, get more data
- Connection:next_record_if_active(State);
- true -> %% We have more data
- read_application_data(<<>>, State)
- end
- end;
+ Connection:next_record_if_active(State);
+ true -> %% We have more data
+ read_application_data(<<>>, State)
+ end
+ end;
{more, Buffer} -> % no reply, we need more data
Connection:next_record(State0#state{user_data_buffer = Buffer});
{passive, Buffer} ->
Connection:next_record_if_active(State0#state{user_data_buffer = Buffer});
{error,_Reason} -> %% Invalid packet in packet mode
- deliver_packet_error(Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker, Connection),
+ deliver_packet_error(Connection:pids(State0),
+ Transport, Socket, SOpts, Buffer1, Pid, RecvFrom, Tracker, Connection),
stop(normal, State0)
end.
+
+dist_app_data(ClientData, #state{protocol_cb = Connection,
+ erl_dist_data = #{dist_handle := undefined,
+ dist_buffer := DistBuff} = DistData} = State) ->
+ Connection:next_record_if_active(State#state{erl_dist_data = DistData#{dist_buffer => [ClientData, DistBuff]}});
+dist_app_data(ClientData, #state{erl_dist_data = #{dist_handle := DHandle,
+ dist_buffer := DistBuff} = ErlDistData,
+ protocol_cb = Connection,
+ user_data_buffer = Buffer,
+ socket_options = SOpts} = State) ->
+ Data = merge_dist_data(DistBuff, ClientData),
+ try erlang:dist_ctrl_put_data(DHandle, Data) of
+ _ when SOpts#socket_options.active =:= false;
+ Buffer =:= <<>> ->
+ %% Passive mode, wait for active once or recv
+ %% Active and empty, get more data
+ Connection:next_record_if_active(State#state{erl_dist_data = ErlDistData#{dist_buffer => <<>>}});
+ _ -> %% We have more data
+ read_application_data(<<>>, State)
+ catch error:_ ->
+ stop(State, disconnect)
+ end.
+
+merge_dist_data(<<>>, ClientData) ->
+ ClientData;
+merge_dist_data(DistBuff, <<>>) ->
+ DistBuff;
+merge_dist_data(DistBuff, ClientData) ->
+ [DistBuff, ClientData].
%%====================================================================
%% Help functions for tls|dtls_connection.erl
%%====================================================================
@@ -542,7 +536,7 @@ handle_session(#server_hello{cipher_suite = CipherSuite,
negotiated_version = ReqVersion,
negotiated_protocol = CurrentProtocol} = State0) ->
#{key_exchange := KeyAlgorithm} =
- ssl_cipher:suite_definition(CipherSuite),
+ ssl_cipher_format:suite_definition(CipherSuite),
PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
@@ -626,12 +620,6 @@ init({call, From}, {start, {Opts, EmOpts}, Timeout},
socket_options = SockOpts} = State0, Connection) ->
try
SslOpts = ssl:handle_options(Opts, OrigSSLOptions),
- case SslOpts of
- #ssl_options{erl_dist = true} ->
- process_flag(priority, max);
- _ ->
- ok
- end,
State = ssl_config(SslOpts, Role, State0),
init({call, From}, {start, Timeout},
State#state{ssl_options = SslOpts,
@@ -650,6 +638,8 @@ init(_Type, _Event, _State, _Connection) ->
tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
+error({call, From}, {close, _}, State, _Connection) ->
+ stop_and_reply(normal, {reply, From, ok}, State);
error({call, From}, _Msg, State, _Connection) ->
{next_state, ?FUNCTION_NAME, State, [{reply, From, {error, closed}}]}.
@@ -742,8 +732,8 @@ abbreviated(internal, #next_protocol{selected_protocol = SelectedProtocol},
Connection:next_event(?FUNCTION_NAME, Record,
State#state{expecting_next_protocol_negotiation = false});
abbreviated(internal,
- #change_cipher_spec{type = <<1>>}, #state{connection_states = ConnectionStates0} =
- State0, Connection) ->
+ #change_cipher_spec{type = <<1>>},
+ #state{connection_states = ConnectionStates0} = State0, Connection) ->
ConnectionStates1 =
ssl_record:activate_pending_connection_state(ConnectionStates0, read, Connection),
{Record, State} = Connection:next_record(State0#state{connection_states =
@@ -858,7 +848,9 @@ certify(internal, #certificate_request{} = CertRequest,
role = client,
ssl_options = #ssl_options{signature_algs = SupportedHashSigns},
negotiated_version = Version} = State0, Connection) ->
- case ssl_handshake:select_hashsign(CertRequest, Cert, SupportedHashSigns, ssl:tls_version(Version)) of
+ case ssl_handshake:select_hashsign(CertRequest, Cert,
+ SupportedHashSigns,
+ ssl:tls_version(Version)) of
#alert {} = Alert ->
handle_own_alert(Alert, Version, ?FUNCTION_NAME, State0);
NegotiatedHashSign ->
@@ -1039,22 +1031,6 @@ cipher(Type, Msg, State, Connection) ->
#state{}, tls_connection | dtls_connection) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-connection({call, {FromPid, _} = From}, {application_data, Data},
- #state{protocol_cb = Connection} = State, Connection) ->
- %% We should look into having a worker process to do this to
- %% parallize send and receive decoding and not block the receiver
- %% if sending is overloading the socket.
- try
- write_application_data(Data, From, State)
- catch throw:Error ->
- case self() of
- FromPid ->
- stop({shutdown, Error}, State);
- _ ->
- hibernate_after(
- ?FUNCTION_NAME, State, [{reply, From, Error}])
- end
- end;
connection({call, RecvFrom}, {recv, N, Timeout},
#state{protocol_cb = Connection, socket_options =
#socket_options{active = false}} = State0, Connection) ->
@@ -1081,64 +1057,25 @@ connection({call, From}, negotiated_protocol,
#state{negotiated_protocol = SelectedProtocol} = State, _) ->
hibernate_after(?FUNCTION_NAME, State,
[{reply, From, {ok, SelectedProtocol}}]);
-connection(
- {call, From}, {handshake_complete, _Node, DHandle},
- #state{
- ssl_options = #ssl_options{erl_dist = true},
- socket_options = SockOpts,
- protocol_specific = ProtocolSpecific} = State,
- Connection) ->
- %% From now on we execute on normal priority
- process_flag(priority, normal),
- try erlang:dist_ctrl_get_data_notification(DHandle) of
- _ ->
- NewState =
- State#state{
- socket_options =
- SockOpts#socket_options{active = true},
- protocol_specific =
- ProtocolSpecific#{d_handle => DHandle}},
- {Record, NewerState} = Connection:next_record_if_active(NewState),
- Connection:next_event(connection, Record, NewerState, [{reply, From, ok}])
- catch error:_ ->
- death_row(State, disconnect)
- end;
connection({call, From}, Msg, State, Connection) ->
handle_call(Msg, From, ?FUNCTION_NAME, State, Connection);
-connection(
- info, dist_data = Msg,
- #state{
- ssl_options = #ssl_options{erl_dist = true},
- protocol_specific = #{d_handle := DHandle}} = State,
- _) ->
- eat_msgs(Msg),
- try send_dist_data(?FUNCTION_NAME, State, DHandle, [])
- catch error:_ ->
- death_row(State, disconnect)
- end;
-connection(
- info, {send, From, Ref, Data},
- #state{
- ssl_options = #ssl_options{erl_dist = true},
- protocol_specific = #{d_handle := _}},
- _) ->
- %% This is for testing only!
- %%
- %% Needed by some OTP distribution
- %% test suites...
- From ! {Ref, ok},
- {keep_state_and_data,
- [{next_event, {call, {self(), undefined}},
- {application_data, iolist_to_binary(Data)}}]};
-connection(
- info, tick = Msg,
- #state{
- ssl_options = #ssl_options{erl_dist = true},
- protocol_specific = #{d_handle := _}},
- _) ->
- eat_msgs(Msg),
- {keep_state_and_data,
- [{next_event, {call, {self(), undefined}}, {application_data, <<>>}}]};
+connection(cast, {internal_renegotiate, WriteState}, #state{protocol_cb = Connection,
+ connection_states = ConnectionStates}
+ = State, Connection) ->
+ Connection:renegotiate(State#state{renegotiation = {true, internal},
+ connection_states = ConnectionStates#{current_write => WriteState}}, []);
+connection(cast, {dist_handshake_complete, DHandle},
+ #state{ssl_options = #ssl_options{erl_dist = true},
+ erl_dist_data = ErlDistData,
+ socket_options = SockOpts} = State0, Connection) ->
+ process_flag(priority, normal),
+ State1 =
+ State0#state{
+ socket_options =
+ SockOpts#socket_options{active = true},
+ erl_dist_data = ErlDistData#{dist_handle => DHandle}},
+ {Record, State} = dist_app_data(<<>>, State1),
+ Connection:next_event(connection, Record, State);
connection(info, Msg, State, _) ->
handle_info(Msg, ?FUNCTION_NAME, State);
connection(internal, {recv, _}, State, Connection) ->
@@ -1147,32 +1084,6 @@ connection(Type, Msg, State, Connection) ->
handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
%%--------------------------------------------------------------------
--spec death_row(gen_statem:event_type(), term(),
- #state{}, tls_connection | dtls_connection) ->
- gen_statem:state_function_result().
-%%--------------------------------------------------------------------
-%% We just wait for the owner to die which triggers the monitor,
-%% or the socket may die too
-death_row(
- info, {'DOWN', MonitorRef, _, _, Reason},
- #state{user_application={MonitorRef,_Pid}},
- _) ->
- {stop, {shutdown, Reason}};
-death_row(
- info, {'EXIT', Socket, Reason}, #state{socket = Socket}, _) ->
- {stop, {shutdown, Reason}};
-death_row(state_timeout, Reason, _State, _Connection) ->
- {stop, {shutdown,Reason}};
-death_row(_Type, _Msg, _State, _Connection) ->
- %% Waste all other events
- keep_state_and_data.
-
-%% State entry function
-death_row(State, Reason) ->
- {next_state, death_row, State,
- [{state_timeout, 5000, Reason}]}.
-
-%%--------------------------------------------------------------------
-spec downgrade(gen_statem:event_type(), term(),
#state{}, tls_connection | dtls_connection) ->
gen_statem:state_function_result().
@@ -1222,7 +1133,14 @@ handle_common_event(internal, {application_data, Data}, StateName, State0, Conne
{stop, _, _} = Stop->
Stop;
{Record, State} ->
- Connection:next_event(StateName, Record, State)
+ case Connection:next_event(StateName, Record, State) of
+ {next_state, StateName, State} ->
+ hibernate_after(StateName, State, []);
+ {next_state, StateName, State, Actions} ->
+ hibernate_after(StateName, State, Actions);
+ {stop, _, _} = Stop ->
+ Stop
+ end
end;
handle_common_event(internal, #change_cipher_spec{type = <<1>>}, StateName,
#state{negotiated_version = Version} = State, _) ->
@@ -1245,24 +1163,20 @@ handle_call({close, {Pid, Timeout}}, From, StateName, State0, Connection) when i
%% we must recive the close alert from the peer before releasing the
%% transport socket.
{next_state, downgrade, State#state{terminated = true}, [{timeout, Timeout, downgrade}]};
-handle_call({close, _} = Close, From, StateName, State, Connection) ->
+handle_call({close, _} = Close, From, StateName, State, _Connection) ->
%% Run terminate before returning so that the reuseaddr
%% inet-option works properly
- Result = Connection:terminate(Close, StateName, State#state{terminated = true}),
+ Result = terminate(Close, StateName, State),
stop_and_reply(
{shutdown, normal},
- {reply, From, Result}, State);
-handle_call({shutdown, How0}, From, _,
+ {reply, From, Result}, State#state{terminated = true});
+handle_call({shutdown, How0}, From, StateName,
#state{transport_cb = Transport,
- negotiated_version = Version,
- connection_states = ConnectionStates,
- socket = Socket} = State, Connection) ->
+ socket = Socket} = State, _) ->
case How0 of
How when How == write; How == both ->
- Alert = ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- {BinMsg, _} =
- Connection:encode_alert(Alert, Version, ConnectionStates),
- Connection:send(Transport, Socket, BinMsg);
+ send_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
+ StateName, State);
_ ->
ok
end,
@@ -1308,12 +1222,8 @@ handle_call({set_opts, Opts0}, From, StateName,
handle_call(renegotiate, From, StateName, _, _) when StateName =/= connection ->
{keep_state_and_data, [{reply, From, {error, already_renegotiating}}]};
-handle_call(
- get_sslsocket, From, _StateName,
- #state{transport_cb = Transport, socket = Socket, tracker = Tracker},
- Connection) ->
- SslSocket =
- Connection:socket(self(), Transport, Socket, Connection, Tracker),
+handle_call(get_sslsocket, From, _StateName, State, Connection) ->
+ SslSocket = Connection:socket(State),
{keep_state_and_data, [{reply, From, SslSocket}]};
handle_call({prf, Secret, Label, Seed, WantedLength}, From, _,
@@ -1350,7 +1260,8 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
start_or_recv_from = StartFrom, role = Role,
error_tag = ErrorTag,
tracker = Tracker} = State) when StateName =/= connection ->
- alert_user(Transport, Tracker,Socket,
+ Pids = Connection:pids(State),
+ alert_user(Pids, Transport, Tracker,Socket,
StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, Connection),
stop(normal, State);
@@ -1361,23 +1272,18 @@ handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
stop(normal, State);
-handle_info(
- {'DOWN', MonitorRef, _, _, Reason}, _,
- #state{
- user_application = {MonitorRef, _Pid},
- ssl_options = #ssl_options{erl_dist = true}}) ->
+handle_info({'DOWN', MonitorRef, _, _, Reason}, _,
+ #state{user_application = {MonitorRef, _Pid},
+ ssl_options = #ssl_options{erl_dist = true}}) ->
{stop, {shutdown, Reason}};
-handle_info(
- {'DOWN', MonitorRef, _, _, _}, _,
- #state{user_application = {MonitorRef, _Pid}}) ->
+handle_info({'DOWN', MonitorRef, _, _, _}, _,
+ #state{user_application = {MonitorRef, _Pid}}) ->
{stop, normal};
-handle_info(
- {'EXIT', Pid, _Reason}, StateName,
- #state{user_application = {_MonitorRef, Pid}} = State) ->
+handle_info({'EXIT', Pid, _Reason}, StateName,
+ #state{user_application = {_MonitorRef, Pid}} = State) ->
%% It seems the user application has linked to us
%% - ignore that and let the monitor handle this
{next_state, StateName, State};
-
%%% So that terminate will be run when supervisor issues shutdown
handle_info({'EXIT', _Sup, shutdown}, _StateName, State) ->
stop(shutdown, State);
@@ -1425,7 +1331,7 @@ terminate({shutdown, transport_closed} = Reason,
socket = Socket, transport_cb = Transport} = State) ->
handle_trusted_certs_db(State),
Connection:close(Reason, Socket, Transport, undefined, undefined);
-terminate({shutdown, own_alert}, _StateName, #state{%%send_queue = SendQueue,
+terminate({shutdown, own_alert}, _StateName, #state{
protocol_cb = Connection,
socket = Socket,
transport_cb = Transport} = State) ->
@@ -1436,15 +1342,20 @@ terminate({shutdown, own_alert}, _StateName, #state{%%send_queue = SendQueue,
_ ->
Connection:close({timeout, ?DEFAULT_TIMEOUT}, Socket, Transport, undefined, undefined)
end;
-terminate(Reason, connection, #state{negotiated_version = Version,
- protocol_cb = Connection,
- connection_states = ConnectionStates0,
- ssl_options = #ssl_options{padding_check = Check},
- transport_cb = Transport, socket = Socket
- } = State) ->
+terminate(downgrade = Reason, connection, #state{protocol_cb = Connection,
+ transport_cb = Transport, socket = Socket
+ } = State) ->
handle_trusted_certs_db(State),
- {BinAlert, ConnectionStates} = terminate_alert(Reason, Version, ConnectionStates0, Connection),
- Connection:send(Transport, Socket, BinAlert),
+ Connection:close(Reason, Socket, Transport, undefined, undefined);
+terminate(Reason, connection, #state{protocol_cb = Connection,
+ connection_states = ConnectionStates,
+ ssl_options = #ssl_options{padding_check = Check},
+ transport_cb = Transport, socket = Socket
+ } = State) ->
+ handle_trusted_certs_db(State),
+ Alert = terminate_alert(Reason),
+ %% Send the termination ALERT if possible
+ catch (ok = Connection:send_alert_in_connection(Alert, State)),
Connection:close(Reason, Socket, Transport, ConnectionStates, Check);
terminate(Reason, _StateName, #state{transport_cb = Transport, protocol_cb = Connection,
socket = Socket
@@ -1481,6 +1392,11 @@ format_status(terminate, [_, StateName, State]) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+send_alert(Alert, connection, #state{protocol_cb = Connection} = State) ->
+ Connection:send_alert_in_connection(Alert, State);
+send_alert(Alert, _, #state{protocol_cb = Connection} = State) ->
+ Connection:send_alert(Alert, State).
+
connection_info(#state{sni_hostname = SNIHostname,
session = #session{session_id = SessionId,
cipher_suite = CipherSuite, ecc = ECCCurve},
@@ -1488,7 +1404,7 @@ connection_info(#state{sni_hostname = SNIHostname,
negotiated_version = {_,_} = Version,
ssl_options = Opts}) ->
RecordCB = record_cb(Connection),
- CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher:suite_definition(CipherSuite),
+ CipherSuiteDef = #{key_exchange := KexAlg} = ssl_cipher_format:suite_definition(CipherSuite),
IsNamedCurveSuite = lists:member(KexAlg,
[ecdh_ecdsa, ecdhe_ecdsa, ecdh_rsa, ecdhe_rsa, ecdh_anon]),
CurveInfo = case ECCCurve of
@@ -1499,7 +1415,7 @@ connection_info(#state{sni_hostname = SNIHostname,
end,
[{protocol, RecordCB:protocol_version(Version)},
{session_id, SessionId},
- {cipher_suite, ssl_cipher:erl_suite_definition(CipherSuiteDef)},
+ {cipher_suite, ssl_cipher_format:erl_suite_definition(CipherSuiteDef)},
{selected_cipher_suite, CipherSuiteDef},
{sni_hostname, SNIHostname} | CurveInfo] ++ ssl_options_list(Opts).
@@ -1511,17 +1427,22 @@ security_info(#state{connection_states = ConnectionStates}) ->
ssl_record:current_connection_state(ConnectionStates, read),
[{client_random, ClientRand}, {server_random, ServerRand}, {master_secret, MasterSecret}].
-do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocols} =
+do_server_hello(Type, #{next_protocol_negotiation := NextProtocols} =
ServerHelloExt,
#state{negotiated_version = Version,
session = #session{session_id = SessId},
- connection_states = ConnectionStates0}
+ connection_states = ConnectionStates0,
+ ssl_options = #ssl_options{versions = [HighestVersion|_]}}
= State0, Connection) when is_atom(Type) ->
-
+ %% TLS 1.3 - Section 4.1.3
+ %% Override server random values for TLS 1.3 downgrade protection mechanism.
+ ConnectionStates1 = update_server_random(ConnectionStates0, Version, HighestVersion),
+ State1 = State0#state{connection_states = ConnectionStates1},
ServerHello =
- ssl_handshake:server_hello(SessId, ssl:tls_version(Version), ConnectionStates0, ServerHelloExt),
+ ssl_handshake:server_hello(SessId, ssl:tls_version(Version),
+ ConnectionStates1, ServerHelloExt),
State = server_hello(ServerHello,
- State0#state{expecting_next_protocol_negotiation =
+ State1#state{expecting_next_protocol_negotiation =
NextProtocols =/= undefined}, Connection),
case Type of
new ->
@@ -1530,6 +1451,60 @@ do_server_hello(Type, #hello_extensions{next_protocol_negotiation = NextProtocol
resumed_server_hello(State, Connection)
end.
+update_server_random(#{pending_read := #{security_parameters := ReadSecParams0} =
+ ReadState0,
+ pending_write := #{security_parameters := WriteSecParams0} =
+ WriteState0} = ConnectionStates,
+ Version, HighestVersion) ->
+ ReadRandom = override_server_random(
+ ReadSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ WriteRandom = override_server_random(
+ WriteSecParams0#security_parameters.server_random,
+ Version,
+ HighestVersion),
+ ReadSecParams = ReadSecParams0#security_parameters{server_random = ReadRandom},
+ WriteSecParams = WriteSecParams0#security_parameters{server_random = WriteRandom},
+ ReadState = ReadState0#{security_parameters => ReadSecParams},
+ WriteState = WriteState0#{security_parameters => WriteSecParams},
+
+ ConnectionStates#{pending_read => ReadState, pending_write => WriteState}.
+
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major > 3 orelse Major =:= 3 andalso Minor >= 4 -> %% TLS 1.3 or above
+ if M =:= 3 andalso N =:= 3 -> %% Negotating TLS 1.2
+ Down = ?RANDOM_OVERRIDE_TLS12,
+ <<Random0/binary,Down/binary>>;
+ M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(<<Random0:24/binary,_:8/binary>> = Random, {M,N}, {Major,Minor})
+ when Major =:= 3 andalso Minor =:= 3 -> %% TLS 1.2
+ if M =:= 3 andalso N < 3 -> %% Negotating TLS 1.1 or prior
+ Down = ?RANDOM_OVERRIDE_TLS11,
+ <<Random0/binary,Down/binary>>;
+ true ->
+ Random
+ end;
+override_server_random(Random, _, _) ->
+ Random.
+
new_server_hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression,
session_id = SessionId},
@@ -1568,7 +1543,7 @@ resumed_server_hello(#state{session = Session,
server_hello(ServerHello, State0, Connection) ->
CipherSuite = ServerHello#server_hello.cipher_suite,
- #{key_exchange := KeyAlgorithm} = ssl_cipher:suite_definition(CipherSuite),
+ #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite),
State = Connection:queue_handshake(ServerHello, State0),
State#state{key_algorithm = KeyAlgorithm}.
@@ -1582,7 +1557,7 @@ handle_peer_cert(Role, PeerCert, PublicKeyInfo,
State1 = State0#state{session =
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
- #{key_exchange := KeyAlgorithm} = ssl_cipher:suite_definition(CipherSuite),
+ #{key_exchange := KeyAlgorithm} = ssl_cipher_format:suite_definition(CipherSuite),
State2 = handle_peer_cert_key(Role, PeerCert, PublicKeyInfo, KeyAlgorithm, State1),
{Record, State} = Connection:next_record(State2),
@@ -2189,22 +2164,24 @@ generate_srp_server_keys(_SrpParams, 10) ->
generate_srp_server_keys(SrpParams =
#srp_user{generator = Generator, prime = Prime,
verifier = Verifier}, N) ->
- case crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
- error ->
- generate_srp_server_keys(SrpParams, N+1);
+ try crypto:generate_key(srp, {host, [Verifier, Generator, Prime, '6a']}) of
Keys ->
Keys
+ catch
+ error:_ ->
+ generate_srp_server_keys(SrpParams, N+1)
end.
generate_srp_client_keys(_Generator, _Prime, 10) ->
?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
generate_srp_client_keys(Generator, Prime, N) ->
- case crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
- error ->
- generate_srp_client_keys(Generator, Prime, N+1);
+ try crypto:generate_key(srp, {user, [Generator, Prime, '6a']}) of
Keys ->
Keys
+ catch
+ error:_ ->
+ generate_srp_client_keys(Generator, Prime, N+1)
end.
handle_srp_identity(Username, {Fun, UserState}) ->
@@ -2374,35 +2351,14 @@ hibernate_after(connection = StateName,
hibernate_after(StateName, State, Actions) ->
{next_state, StateName, State, Actions}.
-map_extensions(#hello_extensions{renegotiation_info = RenegotiationInfo,
- signature_algs = SigAlg,
- alpn = Alpn,
- next_protocol_negotiation = Next,
- srp = SRP,
- ec_point_formats = ECPointFmt,
- elliptic_curves = ECCCurves,
- sni = SNI}) ->
- #{renegotiation_info => ssl_handshake:extension_value(RenegotiationInfo),
- signature_algs => ssl_handshake:extension_value(SigAlg),
- alpn => ssl_handshake:extension_value(Alpn),
- srp => ssl_handshake:extension_value(SRP),
- next_protocol => ssl_handshake:extension_value(Next),
- ec_point_formats => ssl_handshake:extension_value(ECPointFmt),
- elliptic_curves => ssl_handshake:extension_value(ECCCurves),
- sni => ssl_handshake:extension_value(SNI)}.
-
-terminate_alert(normal, Version, ConnectionStates, Connection) ->
- Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- Version, ConnectionStates);
-terminate_alert({Reason, _}, Version, ConnectionStates, Connection) when Reason == close;
- Reason == shutdown ->
- Connection:encode_alert(?ALERT_REC(?WARNING, ?CLOSE_NOTIFY),
- Version, ConnectionStates);
-
-terminate_alert(_, Version, ConnectionStates, Connection) ->
- {BinAlert, _} = Connection:encode_alert(?ALERT_REC(?FATAL, ?INTERNAL_ERROR),
- Version, ConnectionStates),
- BinAlert.
+
+terminate_alert(normal) ->
+ ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY);
+terminate_alert({Reason, _}) when Reason == close;
+ Reason == shutdown ->
+ ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY);
+terminate_alert(_) ->
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR).
handle_trusted_certs_db(#state{ssl_options =
#ssl_options{cacertfile = <<>>, cacerts = []}}) ->
@@ -2411,7 +2367,7 @@ handle_trusted_certs_db(#state{ssl_options =
handle_trusted_certs_db(#state{cert_db_ref = Ref,
cert_db = CertDb,
ssl_options = #ssl_options{cacertfile = <<>>}}) when CertDb =/= undefined ->
- %% Certs provided as DER directly can not be shared
+ %% Certs provided as DER directly cannot be shared
%% with other connections and it is safe to delete them when the connection ends.
ssl_pkix_db:remove_trusted_certs(Ref, CertDb);
handle_trusted_certs_db(#state{file_ref_db = undefined}) ->
@@ -2432,16 +2388,15 @@ prepare_connection(#state{renegotiation = Renegotiate,
start_or_recv_from = RecvFrom} = State0, Connection)
when Renegotiate =/= {false, first},
RecvFrom =/= undefined ->
- State1 = Connection:reinit_handshake_data(State0),
+ State1 = Connection:reinit(State0),
{Record, State} = Connection:next_record(State1),
{Record, ack_connection(State)};
prepare_connection(State0, Connection) ->
- State = Connection:reinit_handshake_data(State0),
+ State = Connection:reinit(State0),
{no_record, ack_connection(State)}.
-ack_connection(#state{renegotiation = {true, Initiater}} = State)
- when Initiater == internal;
- Initiater == peer ->
+ack_connection(#state{renegotiation = {true, Initiater}} = State) when Initiater == peer;
+ Initiater == internal ->
State#state{renegotiation = undefined};
ack_connection(#state{renegotiation = {true, From}} = State) ->
gen_statem:reply(From, ok),
@@ -2547,7 +2502,7 @@ ssl_options_list([ciphers = Key | Keys], [Value | Values], Acc) ->
ssl_options_list(Keys, Values,
[{Key, lists:map(
fun(Suite) ->
- ssl_cipher:suite_definition(Suite)
+ ssl_cipher_format:suite_definition(Suite)
end, Value)}
| Acc]);
ssl_options_list([Key | Keys], [Value | Values], Acc) ->
@@ -2590,35 +2545,6 @@ handle_active_option(_, StateName0, To, Reply, #state{protocol_cb = Connection}
end
end.
-encode_packet(Data, #socket_options{packet=Packet}) ->
- case Packet of
- 1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
- 2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
- 4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
- _ -> Data
- end.
-
-encode_size_packet(Bin, Size, Max) ->
- Len = erlang:byte_size(Bin),
- case Len > Max of
- true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
- false -> <<Len:Size, Bin/binary>>
- end.
-
-time_to_renegotiate(_Data,
- #{current_write := #{sequence_number := Num}},
- RenegotiateAt) ->
-
- %% We could do test:
- %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
- %% but we chose to have a some what lower renegotiateAt and a much cheaper test
- is_time_to_renegotiate(Num, RenegotiateAt).
-
-is_time_to_renegotiate(N, M) when N < M->
- false;
-is_time_to_renegotiate(_,_) ->
- true.
-
%% Picks ClientData
get_data(_, _, <<>>) ->
@@ -2665,9 +2591,10 @@ decode_packet(Type, Buffer, PacketOpts) ->
%% Note that if the user has explicitly configured the socket to expect
%% HTTP headers using the {packet, httph} option, we don't do any automatic
%% switching of states.
-deliver_app_data(Transport, Socket, SOpts = #socket_options{active=Active, packet=Type},
+deliver_app_data(CPids, Transport, Socket, SOpts = #socket_options{active=Active, packet=Type},
Data, Pid, From, Tracker, Connection) ->
- send_or_reply(Active, Pid, From, format_reply(Transport, Socket, SOpts, Data, Tracker, Connection)),
+ send_or_reply(Active, Pid, From,
+ format_reply(CPids, Transport, Socket, SOpts, Data, Tracker, Connection)),
SO = case Data of
{P, _, _, _} when ((P =:= http_request) or (P =:= http_response)),
((Type =:= http) or (Type =:= http_bin)) ->
@@ -2686,21 +2613,24 @@ deliver_app_data(Transport, Socket, SOpts = #socket_options{active=Active, packe
SO
end.
-format_reply(_, _,#socket_options{active = false, mode = Mode, packet = Packet,
+format_reply(_, _, _,#socket_options{active = false, mode = Mode, packet = Packet,
header = Header}, Data, _, _) ->
{ok, do_format_reply(Mode, Packet, Header, Data)};
-format_reply(Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
+format_reply(CPids, Transport, Socket, #socket_options{active = _, mode = Mode, packet = Packet,
header = Header}, Data, Tracker, Connection) ->
- {ssl, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+ {ssl, Connection:socket(CPids, Transport, Socket, Connection, Tracker),
do_format_reply(Mode, Packet, Header, Data)}.
-deliver_packet_error(Transport, Socket, SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
- send_or_reply(Active, Pid, From, format_packet_error(Transport, Socket, SO, Data, Tracker, Connection)).
+deliver_packet_error(CPids, Transport, Socket,
+ SO= #socket_options{active = Active}, Data, Pid, From, Tracker, Connection) ->
+ send_or_reply(Active, Pid, From, format_packet_error(CPids,
+ Transport, Socket, SO, Data, Tracker, Connection)).
-format_packet_error(_, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
+format_packet_error(_, _, _,#socket_options{active = false, mode = Mode}, Data, _, _) ->
{error, {invalid_packet, do_format_reply(Mode, raw, 0, Data)}};
-format_packet_error(Transport, Socket, #socket_options{active = _, mode = Mode}, Data, Tracker, Connection) ->
- {ssl_error, Connection:socket(self(), Transport, Socket, Connection, Tracker),
+format_packet_error(CPids, Transport, Socket, #socket_options{active = _, mode = Mode},
+ Data, Tracker, Connection) ->
+ {ssl_error, Connection:socket(CPids, Transport, Socket, Connection, Tracker),
{invalid_packet, do_format_reply(Mode, raw, 0, Data)}}.
do_format_reply(binary, _, N, Data) when N > 0 -> % Header mode
@@ -2738,29 +2668,29 @@ send_user(Pid, Msg) ->
Pid ! Msg,
ok.
-alert_user(Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
-alert_user(Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, connection, Opts, Pid, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, Opts#socket_options.active, Pid, From, Alert, Role, Connection);
+alert_user(Pids, Transport, Tracker, Socket,_, _, _, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection).
-alert_user(Transport, Tracker, Socket, From, Alert, Role, Connection) ->
- alert_user(Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
+alert_user(Pids, Transport, Tracker, Socket, From, Alert, Role, Connection) ->
+ alert_user(Pids, Transport, Tracker, Socket, false, no_pid, From, Alert, Role, Connection).
-alert_user(_, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
+alert_user(_, _, _, _, false = Active, Pid, From, Alert, Role, _) when From =/= undefined ->
%% If there is an outstanding ssl_accept | recv
%% From will be defined and send_or_reply will
%% send the appropriate error message.
ReasonCode = ssl_alert:reason_code(Alert, Role),
send_or_reply(Active, Pid, From, {error, ReasonCode});
-alert_user(Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
+alert_user(Pids, Transport, Tracker, Socket, Active, Pid, From, Alert, Role, Connection) ->
case ssl_alert:reason_code(Alert, Role) of
closed ->
send_or_reply(Active, Pid, From,
- {ssl_closed, Connection:socket(self(),
+ {ssl_closed, Connection:socket(Pids,
Transport, Socket, Connection, Tracker)});
ReasonCode ->
send_or_reply(Active, Pid, From,
- {ssl_error, Connection:socket(self(),
+ {ssl_error, Connection:socket(Pids,
Transport, Socket, Connection, Tracker), ReasonCode})
end.
@@ -2829,42 +2759,14 @@ new_emulated([], EmOpts) ->
EmOpts;
new_emulated(NewEmOpts, _) ->
NewEmOpts.
-%%---------------Erlang distribution --------------------------------------
-
-send_dist_data(StateName, State, DHandle, Acc) ->
- case erlang:dist_ctrl_get_data(DHandle) of
- none ->
- erlang:dist_ctrl_get_data_notification(DHandle),
- hibernate_after(StateName, State, lists:reverse(Acc));
- Data ->
- send_dist_data(
- StateName, State, DHandle,
- [{next_event, {call, {self(), undefined}}, {application_data, Data}}
- |Acc])
- end.
-
-%% Overload mitigation
-eat_msgs(Msg) ->
- receive Msg -> eat_msgs(Msg)
- after 0 -> ok
- end.
-%% When acting as distribution controller map the exit reason
-%% to follow the documented nodedown_reason for net_kernel
stop(Reason, State) ->
- {stop, erl_dist_stop_reason(Reason, State), State}.
+ {stop, Reason, State}.
stop_and_reply(Reason, Replies, State) ->
- {stop_and_reply, erl_dist_stop_reason(Reason, State), Replies, State}.
-
-erl_dist_stop_reason(
- Reason, #state{ssl_options = #ssl_options{erl_dist = true}}) ->
- case Reason of
- normal ->
- %% We can not exit with normal since that will not bring
- %% down the rest of the distribution processes
- {shutdown, normal};
- _ -> Reason
- end;
-erl_dist_stop_reason(Reason, _State) ->
- Reason.
+ {stop_and_reply, Reason, Replies, State}.
+
+is_dist_up(#{dist_handle := Handle}) when Handle =/= undefined ->
+ true;
+is_dist_up(_) ->
+ false.
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 811aa779d5..66e3182313 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -44,6 +44,7 @@
host :: string() | inet:ip_address(),
port :: integer(),
socket :: port() | tuple(), %% TODO: dtls socket
+ sender :: pid() | undefined,
ssl_options :: #ssl_options{},
socket_options :: #socket_options{},
connection_states :: ssl_record:connection_states() | secret_printout(),
@@ -59,7 +60,7 @@
negotiated_version :: ssl_record:ssl_version() | 'undefined',
client_hello_version :: ssl_record:ssl_version() | 'undefined',
client_certificate_requested = false :: boolean(),
- key_algorithm :: ssl_cipher:key_algo(),
+ key_algorithm :: ssl_cipher_format:key_algo(),
hashsign_algorithm = {undefined, undefined},
cert_hashsign_algorithm = {undefined, undefined},
public_key_info :: ssl_handshake:public_key_info() | 'undefined',
@@ -74,6 +75,7 @@
cert_db_ref :: certdb_ref() | 'undefined',
bytes_to_read :: undefined | integer(), %% bytes to read in passive mode
user_data_buffer :: undefined | binary() | secret_printout(),
+ erl_dist_data = #{} :: map(),
renegotiation :: undefined | {boolean(), From::term() | internal | peer},
start_or_recv_from :: term(),
timer :: undefined | reference(), % start_or_recive_timer
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 4d0bdd6386..1e57dfd710 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -53,14 +53,14 @@
-export([certify/7, certificate_verify/6, verify_signature/5,
master_secret/4, server_key_exchange_hash/2, verify_connection/6,
init_handshake_history/0, update_handshake_history/2, verify_server_key/5,
- select_version/3, extension_value/1
+ select_version/3, select_supported_version/2, extension_value/1
]).
%% Encode
--export([encode_handshake/2, encode_hello_extensions/1,
+-export([encode_handshake/2, encode_hello_extensions/1, encode_extensions/1, encode_extensions/2,
encode_client_protocol_negotiation/2, encode_protocols_advertised_on_server/1]).
%% Decode
--export([decode_handshake/3, decode_hello_extensions/1,
+-export([decode_handshake/3, decode_vector/1, decode_hello_extensions/3, decode_extensions/1,
decode_server_key/3, decode_client_key/3,
decode_suites/2
]).
@@ -93,7 +93,7 @@ hello_request() ->
%%--------------------------------------------------------------------
-spec server_hello(#session{}, ssl_record:ssl_version(), ssl_record:connection_states(),
- #hello_extensions{}) -> #server_hello{}.
+ Extension::map()) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
%%--------------------------------------------------------------------
@@ -169,14 +169,14 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
end.
%%--------------------------------------------------------------------
--spec certificate_request(ssl_cipher:cipher_suite(), db_handle(),
+-spec certificate_request(ssl_cipher_format:cipher_suite(), db_handle(),
certdb_ref(), #hash_sign_algos{}, ssl_record:ssl_version()) ->
#certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
%%--------------------------------------------------------------------
certificate_request(CipherSuite, CertDbHandle, CertDbRef, HashSigns, Version) ->
- Types = certificate_types(ssl_cipher:suite_definition(CipherSuite), Version),
+ Types = certificate_types(ssl_cipher_format:suite_definition(CipherSuite), Version),
Authorities = certificate_authorities(CertDbHandle, CertDbRef),
#certificate_request{
certificate_types = Types,
@@ -338,7 +338,7 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
Opts, CRLDbHandle, Role, Host) ->
ServerName = server_name(Opts#ssl_options.server_name_indication, Host, Role),
- [PeerCert | _] = ASN1Certs,
+ [PeerCert | ChainCerts ] = ASN1Certs,
try
{TrustedCert, CertPath} =
ssl_certificate:trusted_cert_and_path(ASN1Certs, CertDbHandle, CertDbRef,
@@ -347,14 +347,14 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
CertDbHandle, CertDbRef, ServerName,
Opts#ssl_options.customize_hostname_check,
Opts#ssl_options.crl_check, CRLDbHandle, CertPath),
- case public_key:pkix_path_validation(TrustedCert,
- CertPath,
- [{max_path_length, Opts#ssl_options.depth},
- {verify_fun, ValidationFunAndState}]) of
+ Options = [{max_path_length, Opts#ssl_options.depth},
+ {verify_fun, ValidationFunAndState}],
+ case public_key:pkix_path_validation(TrustedCert, CertPath, Options) of
{ok, {PublicKeyInfo,_}} ->
{PeerCert, PublicKeyInfo};
{error, Reason} ->
- path_validation_alert(Reason)
+ handle_path_validation_error(Reason, PeerCert, ChainCerts, Opts, Options,
+ CertDbHandle, CertDbRef)
end
catch
error:{badmatch,{asn1, Asn1Reason}} ->
@@ -363,7 +363,6 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
error:OtherReason ->
?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {unexpected_error, OtherReason})
end.
-
%%--------------------------------------------------------------------
-spec certificate_verify(binary(), public_key_info(), ssl_record:ssl_version(), term(),
binary(), ssl_handshake_history()) -> valid | #alert{}.
@@ -505,6 +504,21 @@ verify_server_key(#server_key_params{params_bin = EncParams,
select_version(RecordCB, ClientVersion, Versions) ->
do_select_version(RecordCB, ClientVersion, Versions).
+
+%% Called by TLS 1.2/1.3 Server when "supported_versions" is present
+%% in ClientHello.
+%% Input lists are ordered (highest first)
+select_supported_version([], _ServerVersions) ->
+ undefined;
+select_supported_version([ClientVersion|T], ServerVersions) ->
+ case lists:member(ClientVersion, ServerVersions) of
+ true ->
+ ClientVersion;
+ false ->
+ select_supported_version(T, ServerVersions)
+ end.
+
+
%%====================================================================
%% Encode handshake
%%====================================================================
@@ -518,7 +532,7 @@ encode_handshake(#server_hello{server_version = {Major, Minor},
session_id = Session_ID,
cipher_suite = CipherSuite,
compression_method = Comp_method,
- extensions = #hello_extensions{} = Extensions}, _Version) ->
+ extensions = Extensions}, _Version) ->
SID_length = byte_size(Session_ID),
ExtensionsBin = encode_hello_extensions(Extensions),
{?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
@@ -568,71 +582,93 @@ encode_handshake(#certificate_verify{signature = BinSig, hashsign_algorithm = Ha
encode_handshake(#finished{verify_data = VerifyData}, _Version) ->
{?FINISHED, VerifyData}.
-encode_hello_extensions(#hello_extensions{} = Extensions) ->
- encode_hello_extensions(hello_extensions_list(Extensions), <<>>).
-encode_hello_extensions([], <<>>) ->
+encode_hello_extensions(Extensions) ->
+ encode_extensions(hello_extensions_list(Extensions), <<>>).
+
+encode_extensions(Exts) ->
+ encode_extensions(Exts, <<>>).
+
+encode_extensions([], <<>>) ->
<<>>;
-encode_hello_extensions([], Acc) ->
+encode_extensions([], Acc) ->
Size = byte_size(Acc),
<<?UINT16(Size), Acc/binary>>;
-
-encode_hello_extensions([#alpn{extension_data = ExtensionData} | Rest], Acc) ->
- Len = byte_size(ExtensionData),
+encode_extensions([#alpn{extension_data = ExtensionData} | Rest], Acc) ->
+ Len = byte_size(ExtensionData),
ExtLen = Len + 2,
- encode_hello_extensions(Rest, <<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len),
- ExtensionData/binary, Acc/binary>>);
-encode_hello_extensions([#next_protocol_negotiation{extension_data = ExtensionData} | Rest], Acc) ->
+ encode_extensions(Rest, <<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len),
+ ExtensionData/binary, Acc/binary>>);
+encode_extensions([#next_protocol_negotiation{extension_data = ExtensionData} | Rest], Acc) ->
Len = byte_size(ExtensionData),
- encode_hello_extensions(Rest, <<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len),
+ encode_extensions(Rest, <<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len),
ExtensionData/binary, Acc/binary>>);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = undefined} | Rest], Acc) ->
- encode_hello_extensions(Rest, Acc);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) ->
+encode_extensions([#renegotiation_info{renegotiated_connection = undefined} | Rest], Acc) ->
+ encode_extensions(Rest, Acc);
+encode_extensions([#renegotiation_info{renegotiated_connection = ?byte(0) = Info} | Rest], Acc) ->
Len = byte_size(Info),
- encode_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>);
+ encode_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info/binary, Acc/binary>>);
-encode_hello_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) ->
+encode_extensions([#renegotiation_info{renegotiated_connection = Info} | Rest], Acc) ->
InfoLen = byte_size(Info),
Len = InfoLen +1,
- encode_hello_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen),
+ encode_extensions(Rest, <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), ?BYTE(InfoLen),
Info/binary, Acc/binary>>);
-encode_hello_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
+encode_extensions([#elliptic_curves{elliptic_curve_list = EllipticCurves} | Rest], Acc) ->
EllipticCurveList = << <<(tls_v1:oid_to_enum(X)):16>> || X <- EllipticCurves>>,
ListLen = byte_size(EllipticCurveList),
Len = ListLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
+ encode_extensions(Rest, <<?UINT16(?ELLIPTIC_CURVES_EXT),
?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary, Acc/binary>>);
-encode_hello_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
+encode_extensions([#ec_point_formats{ec_point_format_list = ECPointFormats} | Rest], Acc) ->
ECPointFormatList = list_to_binary(ECPointFormats),
ListLen = byte_size(ECPointFormatList),
Len = ListLen + 1,
- encode_hello_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
+ encode_extensions(Rest, <<?UINT16(?EC_POINT_FORMATS_EXT),
?UINT16(Len), ?BYTE(ListLen), ECPointFormatList/binary, Acc/binary>>);
-encode_hello_extensions([#srp{username = UserName} | Rest], Acc) ->
+encode_extensions([#srp{username = UserName} | Rest], Acc) ->
SRPLen = byte_size(UserName),
Len = SRPLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen),
+ encode_extensions(Rest, <<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen),
UserName/binary, Acc/binary>>);
-encode_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
+encode_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Rest], Acc) ->
SignAlgoList = << <<(ssl_cipher:hash_algorithm(Hash)):8, (ssl_cipher:sign_algorithm(Sign)):8>> ||
{Hash, Sign} <- HashSignAlgos >>,
ListLen = byte_size(SignAlgoList),
Len = ListLen + 2,
- encode_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
+ encode_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>);
-encode_hello_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
+encode_extensions([#signature_scheme_list{
+ signature_scheme_list = SignatureSchemes} | Rest], Acc) ->
+ SignSchemeList = << <<(ssl_cipher:signature_scheme(SignatureScheme)):16 >> ||
+ SignatureScheme <- SignatureSchemes >>,
+ ListLen = byte_size(SignSchemeList),
+ Len = ListLen + 2,
+ encode_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT),
+ ?UINT16(Len), ?UINT16(ListLen), SignSchemeList/binary, Acc/binary>>);
+encode_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
HostLen = length(Hostname),
HostnameBin = list_to_binary(Hostname),
% Hostname type (1 byte) + Hostname length (2 bytes) + Hostname (HostLen bytes)
ServerNameLength = 1 + 2 + HostLen,
% ServerNameListSize (2 bytes) + ServerNameLength
ExtLength = 2 + ServerNameLength,
- encode_hello_extensions(Rest, <<?UINT16(?SNI_EXT), ?UINT16(ExtLength),
- ?UINT16(ServerNameLength),
- ?BYTE(?SNI_NAMETYPE_HOST_NAME),
- ?UINT16(HostLen), HostnameBin/binary,
- Acc/binary>>).
+ encode_extensions(Rest, <<?UINT16(?SNI_EXT), ?UINT16(ExtLength),
+ ?UINT16(ServerNameLength),
+ ?BYTE(?SNI_NAMETYPE_HOST_NAME),
+ ?UINT16(HostLen), HostnameBin/binary,
+ Acc/binary>>);
+encode_extensions([#client_hello_versions{versions = Versions0} | Rest], Acc) ->
+ Versions = encode_versions(Versions0),
+ VerLen = byte_size(Versions),
+ Len = VerLen + 2,
+ encode_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), ?UINT16(VerLen), Versions/binary, Acc/binary>>);
+encode_extensions([#server_hello_selected_version{selected_version = Version0} | Rest], Acc) ->
+ Version = encode_versions([Version0]),
+ Len = byte_size(Version), %% 2
+ encode_extensions(Rest, <<?UINT16(?SUPPORTED_VERSIONS_EXT),
+ ?UINT16(Len), Version/binary, Acc/binary>>).
encode_client_protocol_negotiation(undefined, _) ->
undefined;
@@ -658,7 +694,7 @@ decode_handshake(_, ?NEXT_PROTOCOL, <<?BYTE(SelectedProtocolLength),
?BYTE(PaddingLength), _Padding:PaddingLength/binary>>) ->
#next_protocol{selected_protocol = SelectedProtocol};
-decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+decode_handshake(Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
Cipher_suite:2/binary, ?BYTE(Comp_method)>>) ->
#server_hello{
@@ -667,14 +703,14 @@ decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:3
session_id = Session_ID,
cipher_suite = Cipher_suite,
compression_method = Comp_method,
- extensions = #hello_extensions{}};
+ extensions = empty_hello_extensions(Version, server)};
-decode_handshake(_Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
+decode_handshake(Version, ?SERVER_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
Cipher_suite:2/binary, ?BYTE(Comp_method),
?UINT16(ExtLen), Extensions:ExtLen/binary>>) ->
- HelloExtensions = decode_hello_extensions(Extensions),
+ HelloExtensions = decode_hello_extensions(Extensions, Version, server),
#server_hello{
server_version = {Major,Minor},
@@ -717,20 +753,37 @@ decode_handshake(_Version, ?FINISHED, VerifyData) ->
decode_handshake(_, Message, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {unknown_or_malformed_handshake, Message})).
+
+%%--------------------------------------------------------------------
+-spec decode_vector(binary()) -> binary().
+%%
+%% Description: Remove length tag from TLS Vector type. Needed
+%% for client hello when extensions in older versions may be empty.
+%%
+%%--------------------------------------------------------------------
+decode_vector(<<>>) ->
+ <<>>;
+decode_vector(<<?UINT16(Len), Vector:Len/binary>>) ->
+ Vector.
+
+%%--------------------------------------------------------------------
+-spec decode_hello_extensions(binary(), ssl_record:ssl_version(), client | server) -> map().
+%%
+%% Description: Decodes TLS hello extensions
+%%--------------------------------------------------------------------
+decode_hello_extensions(Extensions, Version, Role) ->
+ decode_extensions(Extensions, empty_hello_extensions(Version, Role)).
+
%%--------------------------------------------------------------------
--spec decode_hello_extensions({client, binary()} | binary()) -> #hello_extensions{}.
+-spec decode_extensions(binary()) -> map().
%%
%% Description: Decodes TLS hello extensions
%%--------------------------------------------------------------------
-decode_hello_extensions({client, <<>>}) ->
- #hello_extensions{};
-decode_hello_extensions({client, <<?UINT16(ExtLen), Extensions:ExtLen/binary>>}) ->
- decode_hello_extensions(Extensions);
-decode_hello_extensions(Extensions) ->
- dec_hello_extensions(Extensions, #hello_extensions{}).
+decode_extensions(Extensions) ->
+ decode_extensions(Extensions, empty_extensions()).
%%--------------------------------------------------------------------
--spec decode_server_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
+-spec decode_server_key(binary(), ssl_cipher_format:key_algo(), ssl_record:ssl_version()) ->
#server_key_params{}.
%%
%% Description: Decode server_key data and return appropriate type
@@ -739,7 +792,7 @@ decode_server_key(ServerKey, Type, Version) ->
dec_server_key(ServerKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
--spec decode_client_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
+-spec decode_client_key(binary(), ssl_cipher_format:key_algo(), ssl_record:ssl_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
| #client_ec_diffie_hellman_public{}
@@ -777,7 +830,7 @@ available_suites(ServerCert, UserSuites, Version, undefined, Curve) ->
filter_unavailable_ecc_suites(Curve, Suites);
available_suites(ServerCert, UserSuites, Version, HashSigns, Curve) ->
Suites = available_suites(ServerCert, UserSuites, Version, undefined, Curve),
- filter_hashsigns(Suites, [ssl_cipher:suite_definition(Suite) || Suite <- Suites], HashSigns,
+ filter_hashsigns(Suites, [ssl_cipher_format:suite_definition(Suite) || Suite <- Suites], HashSigns,
Version, []).
available_signature_algs(undefined, _) ->
@@ -859,22 +912,24 @@ premaster_secret(PublicDhKey, PrivateDhKey, #server_dh_params{dh_p = Prime, dh_g
end;
premaster_secret(#client_srp_public{srp_a = ClientPublicKey}, ServerKey, #srp_user{prime = Prime,
verifier = Verifier}) ->
- case crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) of
- error ->
- throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER));
+ try crypto:compute_key(srp, ClientPublicKey, ServerKey, {host, [Verifier, Prime, '6a']}) of
PremasterSecret ->
PremasterSecret
+ catch
+ error:_ ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end;
premaster_secret(#server_srp_params{srp_n = Prime, srp_g = Generator, srp_s = Salt, srp_b = Public},
ClientKeys, {Username, Password}) ->
case ssl_srp_primes:check_srp_params(Generator, Prime) of
ok ->
DerivedKey = crypto:hash(sha, [Salt, crypto:hash(sha, [Username, <<$:>>, Password])]),
- case crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
- error ->
- throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER));
+ try crypto:compute_key(srp, Public, ClientKeys, {user, [DerivedKey, Prime, Generator, '6a']}) of
PremasterSecret ->
PremasterSecret
+ catch
+ error ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
end;
_ ->
throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER))
@@ -930,9 +985,11 @@ premaster_secret(EncSecret, #'RSAPrivateKey'{} = RSAPrivateKey) ->
%%====================================================================
client_hello_extensions(Version, CipherSuites,
#ssl_options{signature_algs = SupportedHashSigns,
- eccs = SupportedECCs} = SslOpts, ConnectionStates, Renegotiation) ->
+ signature_algs_cert = SignatureSchemes,
+ eccs = SupportedECCs,
+ versions = Versions} = SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
- case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
+ case advertises_ec_ciphers(lists:map(fun ssl_cipher_format:suite_definition/1, CipherSuites)) of
true ->
client_ecc_extensions(SupportedECCs);
false ->
@@ -940,44 +997,57 @@ client_hello_extensions(Version, CipherSuites,
end,
SRP = srp_user(SslOpts),
- #hello_extensions{
- renegotiation_info = renegotiation_info(tls_record, client,
- ConnectionStates, Renegotiation),
- srp = SRP,
- signature_algs = available_signature_algs(SupportedHashSigns, Version),
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
- alpn = encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
- next_protocol_negotiation =
- encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
- Renegotiation),
- sni = sni(SslOpts#ssl_options.server_name_indication)}.
+ HelloExtensions = #{renegotiation_info => renegotiation_info(tls_record, client,
+ ConnectionStates, Renegotiation),
+ srp => SRP,
+ signature_algs => available_signature_algs(SupportedHashSigns, Version),
+ ec_point_formats => EcPointFormats,
+ elliptic_curves => EllipticCurves,
+ alpn => encode_alpn(SslOpts#ssl_options.alpn_advertised_protocols, Renegotiation),
+ next_protocol_negotiation =>
+ encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
+ Renegotiation),
+ sni => sni(SslOpts#ssl_options.server_name_indication)
+ },
+
+ %% Add "supported_versions" extension if TLS 1.3
+ case Version of
+ {3,4} ->
+ HelloExtensions#{client_hello_versions =>
+ #client_hello_versions{versions = Versions},
+ signature_algs_cert =>
+ signature_scheme_list(SignatureSchemes)};
+ _Else ->
+ HelloExtensions
+ end.
+
+signature_scheme_list(undefined) ->
+ undefined;
+signature_scheme_list(SignatureSchemes) ->
+ #signature_scheme_list{signature_scheme_list = SignatureSchemes}.
handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
- #hello_extensions{renegotiation_info = Info,
- srp = SRP,
- ec_point_formats = ECCFormat,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation}, Version,
+ Exts, Version,
#ssl_options{secure_renegotiate = SecureRenegotation,
alpn_preferred_protocols = ALPNPreferredProtocols} = Opts,
#session{cipher_suite = NegotiatedCipherSuite,
compression_method = Compression} = Session0,
ConnectionStates0, Renegotiation) ->
- Session = handle_srp_extension(SRP, Session0),
- ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, Info,
+ Session = handle_srp_extension(maps:get(srp, Exts, undefined), Session0),
+ ConnectionStates = handle_renegotiation_extension(server, RecordCB, Version, maps:get(renegotiation_info, Exts, undefined),
Random, NegotiatedCipherSuite,
ClientCipherSuites, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation),
- ServerHelloExtensions = #hello_extensions{
- renegotiation_info = renegotiation_info(RecordCB, server,
- ConnectionStates, Renegotiation),
- ec_point_formats = server_ecc_extension(Version, ECCFormat)
- },
-
+ Empty = empty_hello_extensions(Version, client),
+ ServerHelloExtensions = Empty#{renegotiation_info => renegotiation_info(RecordCB, server,
+ ConnectionStates, Renegotiation),
+ ec_point_formats => server_ecc_extension(Version, maps:get(ec_point_formats, Exts, undefined))
+ },
+
%% If we receive an ALPN extension and have ALPN configured for this connection,
%% we handle it. Otherwise we check for the NPN extension.
+ ALPN = maps:get(alpn, Exts, undefined),
if
ALPN =/= undefined, ALPNPreferredProtocols =/= undefined ->
case handle_alpn_extension(ALPNPreferredProtocols, decode_alpn(ALPN)) of
@@ -985,35 +1055,36 @@ handle_client_hello_extensions(RecordCB, Random, ClientCipherSuites,
Alert;
Protocol ->
{Session, ConnectionStates, Protocol,
- ServerHelloExtensions#hello_extensions{alpn=encode_alpn([Protocol], Renegotiation)}}
+ ServerHelloExtensions#{alpn => encode_alpn([Protocol], Renegotiation)}}
end;
true ->
+ NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined),
ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts),
{Session, ConnectionStates, undefined,
- ServerHelloExtensions#hello_extensions{next_protocol_negotiation=
- encode_protocols_advertised_on_server(ProtocolsToAdvertise)}}
+ ServerHelloExtensions#{next_protocol_negotiation =>
+ encode_protocols_advertised_on_server(ProtocolsToAdvertise)}}
end.
handle_server_hello_extensions(RecordCB, Random, CipherSuite, Compression,
- #hello_extensions{renegotiation_info = Info,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation}, Version,
+ Exts, Version,
#ssl_options{secure_renegotiate = SecureRenegotation,
next_protocol_selector = NextProtoSelector},
ConnectionStates0, Renegotiation) ->
- ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, Info, Random,
+ ConnectionStates = handle_renegotiation_extension(client, RecordCB, Version, maps:get(renegotiation_info, Exts, undefined), Random,
CipherSuite, undefined,
Compression, ConnectionStates0,
Renegotiation, SecureRenegotation),
%% If we receive an ALPN extension then this is the protocol selected,
%% otherwise handle the NPN extension.
+ ALPN = maps:get(alpn, Exts, undefined),
case decode_alpn(ALPN) of
%% ServerHello contains exactly one protocol: the one selected.
%% We also ignore the ALPN extension during renegotiation (see encode_alpn/2).
[Protocol] when not Renegotiation ->
{ConnectionStates, alpn, Protocol};
undefined ->
+ NextProtocolNegotiation = maps:get(next_protocol_negotiation, Exts, undefined),
case handle_next_protocol(NextProtocolNegotiation, NextProtoSelector, Renegotiation) of
#alert{} = Alert ->
Alert;
@@ -1056,30 +1127,56 @@ select_curve(undefined, _, _) ->
select_hashsign(_, _, KeyExAlgo, _, _Version) when KeyExAlgo == dh_anon;
KeyExAlgo == ecdh_anon;
KeyExAlgo == srp_anon;
- KeyExAlgo == psk ->
+ KeyExAlgo == psk;
+ KeyExAlgo == dhe_psk;
+ KeyExAlgo == ecdhe_psk ->
{null, anon};
%% The signature_algorithms extension was introduced with TLS 1.2. Ignore it if we have
%% negotiated a lower version.
-select_hashsign(HashSigns, Cert, KeyExAlgo,
- undefined, {Major, Minor} = Version) when Major >= 3 andalso Minor >= 3->
- select_hashsign(HashSigns, Cert, KeyExAlgo, tls_v1:default_signature_algs(Version), Version);
-select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert, KeyExAlgo, SupportedHashSigns,
- {Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
- #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
- TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
-
- SubSign = sign_algo(SubjAlgo),
-
- case lists:filter(fun({_, S} = Algos) when S == SubSign ->
- is_acceptable_hash_sign(Algos, KeyExAlgo, SupportedHashSigns);
- (_) ->
- false
- end, HashSigns) of
- [] ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
- [HashSign | _] ->
- HashSign
+select_hashsign({ClientHashSigns, ClientSignatureSchemes},
+ Cert, KeyExAlgo, undefined, {Major, Minor} = Version)
+ when Major >= 3 andalso Minor >= 3->
+ select_hashsign({ClientHashSigns, ClientSignatureSchemes}, Cert, KeyExAlgo,
+ tls_v1:default_signature_algs(Version), Version);
+select_hashsign({#hash_sign_algos{hash_sign_algos = ClientHashSigns},
+ ClientSignatureSchemes0},
+ Cert, KeyExAlgo, SupportedHashSigns, {Major, Minor})
+ when Major >= 3 andalso Minor >= 3 ->
+ ClientSignatureSchemes = get_signature_scheme(ClientSignatureSchemes0),
+ {SignAlgo0, Param, PublicKeyAlgo0} = get_cert_params(Cert),
+ SignAlgo = sign_algo(SignAlgo0),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ %% RFC 5246 (TLS 1.2)
+ %% If the client provided a "signature_algorithms" extension, then all
+ %% certificates provided by the server MUST be signed by a
+ %% hash/signature algorithm pair that appears in that extension.
+ %%
+ %% RFC 8446 (TLS 1.3)
+ %% TLS 1.3 provides two extensions for indicating which signature
+ %% algorithms may be used in digital signatures. The
+ %% "signature_algorithms_cert" extension applies to signatures in
+ %% certificates and the "signature_algorithms" extension, which
+ %% originally appeared in TLS 1.2, applies to signatures in
+ %% CertificateVerify messages.
+ %%
+ %% If no "signature_algorithms_cert" extension is
+ %% present, then the "signature_algorithms" extension also applies to
+ %% signatures appearing in certificates.
+ case is_supported_sign(SignAlgo, Param, ClientHashSigns, ClientSignatureSchemes) of
+ true ->
+ case lists:filter(fun({_, S} = Algos) when S == PublicKeyAlgo ->
+ is_acceptable_hash_sign(Algos, KeyExAlgo, SupportedHashSigns);
+ (_) ->
+ false
+ end, ClientHashSigns) of
+ [] ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm);
+ [HashSign | _] ->
+ HashSign
+ end;
+ false ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
end;
select_hashsign(_, Cert, _, _, Version) ->
#'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
@@ -1093,21 +1190,23 @@ select_hashsign(_, Cert, _, _, Version) ->
%%
%% Description: Handles signature algorithms selection for certificate requests (client)
%%--------------------------------------------------------------------
-select_hashsign(#certificate_request{hashsign_algorithms = #hash_sign_algos{hash_sign_algos = HashSigns},
- certificate_types = Types}, Cert, SupportedHashSigns,
+select_hashsign(#certificate_request{
+ hashsign_algorithms = #hash_sign_algos{
+ hash_sign_algos = HashSigns},
+ certificate_types = Types},
+ Cert,
+ SupportedHashSigns,
{Major, Minor}) when Major >= 3 andalso Minor >= 3->
- #'OTPCertificate'{tbsCertificate = TBSCert} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPCertificate'{tbsCertificate = TBSCert,
- signatureAlgorithm = {_,SignAlgo, _}} = public_key:pkix_decode_cert(Cert, otp),
- #'OTPSubjectPublicKeyInfo'{algorithm = {_, SubjAlgo, _}} =
- TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
-
- Sign = sign_algo(SignAlgo),
- SubSign = sign_algo(SubjAlgo),
-
- case is_acceptable_cert_type(SubSign, HashSigns, Types) andalso is_supported_sign(Sign, HashSigns) of
+ {SignAlgo0, Param, PublicKeyAlgo0} = get_cert_params(Cert),
+ SignAlgo = sign_algo(SignAlgo0),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ case is_acceptable_cert_type(PublicKeyAlgo, Types) andalso
+ %% certificate_request has no "signature_algorithms_cert"
+ %% extension in TLS 1.2.
+ is_supported_sign(SignAlgo, Param, HashSigns, undefined) of
true ->
- case lists:filter(fun({_, S} = Algos) when S == SubSign ->
+ case lists:filter(fun({_, S} = Algos) when S == PublicKeyAlgo ->
is_acceptable_hash_sign(Algos, SupportedHashSigns);
(_) ->
false
@@ -1120,8 +1219,38 @@ select_hashsign(#certificate_request{hashsign_algorithms = #hash_sign_algos{hash
false ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
end;
-select_hashsign(#certificate_request{}, Cert, _, Version) ->
- select_hashsign(undefined, Cert, undefined, [], Version).
+select_hashsign(#certificate_request{certificate_types = Types}, Cert, _, Version) ->
+ {_, _, PublicKeyAlgo0} = get_cert_params(Cert),
+ PublicKeyAlgo = public_key_algo(PublicKeyAlgo0),
+
+ %% Check cert even for TLS 1.0/1.1
+ case is_acceptable_cert_type(PublicKeyAlgo, Types) of
+ true ->
+ select_hashsign(undefined, Cert, undefined, [], Version);
+ false ->
+ ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)
+ end.
+
+
+%% Gets the relevant parameters of a certificate:
+%% - signature algorithm
+%% - parameters of the signature algorithm
+%% - public key algorithm (key type)
+get_cert_params(Cert) ->
+ #'OTPCertificate'{tbsCertificate = TBSCert,
+ signatureAlgorithm =
+ {_,SignAlgo, Param}} = public_key:pkix_decode_cert(Cert, otp),
+ #'OTPSubjectPublicKeyInfo'{algorithm = {_, PublicKeyAlgo, _}} =
+ TBSCert#'OTPTBSCertificate'.subjectPublicKeyInfo,
+ {SignAlgo, Param, PublicKeyAlgo}.
+
+
+get_signature_scheme(undefined) ->
+ undefined;
+get_signature_scheme(#signature_scheme_list{
+ signature_scheme_list = ClientSignatureSchemes}) ->
+ ClientSignatureSchemes.
+
%%--------------------------------------------------------------------
-spec select_hashsign_algs({atom(), atom()}| undefined, oid(), ssl_record:ssl_version()) ->
@@ -1190,33 +1319,30 @@ int_to_bin(I) ->
L = (length(integer_to_list(I, 16)) + 1) div 2,
<<I:(L*8)>>.
-certificate_types(_, {N, M}) when N >= 3 andalso M >= 3 ->
- case proplists:get_bool(ecdsa,
- proplists:get_value(public_keys, crypto:supports())) of
- true ->
- <<?BYTE(?ECDSA_SIGN), ?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>;
- false ->
- <<?BYTE(?RSA_SIGN), ?BYTE(?DSS_SIGN)>>
- end;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == rsa;
- KeyExchange == dh_rsa;
- KeyExchange == dhe_rsa;
- KeyExchange == ecdhe_rsa ->
- <<?BYTE(?RSA_SIGN)>>;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == dh_dss;
- KeyExchange == dhe_dss;
- KeyExchange == srp_dss ->
- <<?BYTE(?DSS_SIGN)>>;
-
-certificate_types(#{key_exchange := KeyExchange}, _) when KeyExchange == dh_ecdsa;
- KeyExchange == dhe_ecdsa;
- KeyExchange == ecdh_ecdsa;
- KeyExchange == ecdhe_ecdsa ->
- <<?BYTE(?ECDSA_SIGN)>>;
+%% TLS 1.0+
+%% The end-entity certificate provided by the client MUST contain a
+%% key that is compatible with certificate_types.
+certificate_types(_, {N, M}) when N >= 3 andalso M >= 1 ->
+ ECDSA = supported_cert_type_or_empty(ecdsa, ?ECDSA_SIGN),
+ RSA = supported_cert_type_or_empty(rsa, ?RSA_SIGN),
+ DSS = supported_cert_type_or_empty(dss, ?DSS_SIGN),
+ <<ECDSA/binary,RSA/binary,DSS/binary>>;
+%% SSL 3.0
certificate_types(_, _) ->
- <<?BYTE(?RSA_SIGN)>>.
+ RSA = supported_cert_type_or_empty(rsa, ?RSA_SIGN),
+ DSS = supported_cert_type_or_empty(dss, ?DSS_SIGN),
+ <<RSA/binary,DSS/binary>>.
+
+%% Returns encoded certificate_type if algorithm is supported
+supported_cert_type_or_empty(Algo, Type) ->
+ case proplists:get_bool(
+ Algo,
+ proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ <<?BYTE(Type)>>;
+ false ->
+ <<>>
+ end.
certificate_authorities(CertDbHandle, CertDbRef) ->
Authorities = certificate_authorities_from_db(CertDbHandle, CertDbRef),
@@ -1308,6 +1434,45 @@ apply_user_fun(Fun, OtpCert, ExtensionOrError, UserState0, SslState, _CertPath)
{unknown, {SslState, UserState}}
end.
+handle_path_validation_error({bad_cert, unknown_ca} = Reason, PeerCert, Chain,
+ Opts, Options, CertDbHandle, CertsDbRef) ->
+ handle_incomplete_chain(PeerCert, Chain, Opts, Options, CertDbHandle, CertsDbRef, Reason);
+handle_path_validation_error({bad_cert, invalid_issuer} = Reason, PeerCert, Chain0,
+ Opts, Options, CertDbHandle, CertsDbRef) ->
+ case ssl_certificate:certificate_chain(PeerCert, CertDbHandle, CertsDbRef, Chain0) of
+ {ok, _, [PeerCert | Chain] = OrdedChain} when Chain =/= Chain0 -> %% Chain appaears to be unorded
+ {Trusted, Path} = ssl_certificate:trusted_cert_and_path(OrdedChain,
+ CertDbHandle, CertsDbRef,
+ Opts#ssl_options.partial_chain),
+ case public_key:pkix_path_validation(Trusted, Path, Options) of
+ {ok, {PublicKeyInfo,_}} ->
+ {PeerCert, PublicKeyInfo};
+ {error, PathError} ->
+ handle_path_validation_error(PathError, PeerCert, Path,
+ Opts, Options, CertDbHandle, CertsDbRef)
+ end;
+ _ ->
+ path_validation_alert(Reason)
+ end;
+handle_path_validation_error(Reason, _, _, _, _,_, _) ->
+ path_validation_alert(Reason).
+
+handle_incomplete_chain(PeerCert, Chain0, Opts, Options, CertDbHandle, CertsDbRef, PathError0) ->
+ case ssl_certificate:certificate_chain(PeerCert, CertDbHandle, CertsDbRef) of
+ {ok, _, [PeerCert | _] = Chain} when Chain =/= Chain0 -> %% Chain candidate found
+ {Trusted, Path} = ssl_certificate:trusted_cert_and_path(Chain,
+ CertDbHandle, CertsDbRef,
+ Opts#ssl_options.partial_chain),
+ case public_key:pkix_path_validation(Trusted, Path, Options) of
+ {ok, {PublicKeyInfo,_}} ->
+ {PeerCert, PublicKeyInfo};
+ {error, PathError} ->
+ path_validation_alert(PathError)
+ end;
+ _ ->
+ path_validation_alert(PathError0)
+ end.
+
path_validation_alert({bad_cert, cert_expired}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_EXPIRED);
path_validation_alert({bad_cert, invalid_issuer}) ->
@@ -1320,8 +1485,6 @@ path_validation_alert({bad_cert, unknown_critical_extension}) ->
?ALERT_REC(?FATAL, ?UNSUPPORTED_CERTIFICATE);
path_validation_alert({bad_cert, {revoked, _}}) ->
?ALERT_REC(?FATAL, ?CERTIFICATE_REVOKED);
-%%path_validation_alert({bad_cert, revocation_status_undetermined}) ->
-%% ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE);
path_validation_alert({bad_cert, {revocation_status_undetermined, Details}}) ->
Alert = ?ALERT_REC(?FATAL, ?BAD_CERTIFICATE),
Alert#alert{reason = Details};
@@ -1722,16 +1885,18 @@ encode_alpn(undefined, _) ->
encode_alpn(Protocols, _) ->
#alpn{extension_data = lists:foldl(fun encode_protocol/2, <<>>, Protocols)}.
-hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
- srp = SRP,
- signature_algs = HashSigns,
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
- alpn = ALPN,
- next_protocol_negotiation = NextProtocolNegotiation,
- sni = Sni}) ->
- [Ext || Ext <- [RenegotiationInfo, SRP, HashSigns,
- EcPointFormats, EllipticCurves, ALPN, NextProtocolNegotiation, Sni], Ext =/= undefined].
+
+encode_versions(Versions) ->
+ encode_versions(lists:reverse(Versions), <<>>).
+%%
+encode_versions([], Acc) ->
+ Acc;
+encode_versions([{M,N}|T], Acc) ->
+ encode_versions(T, <<?BYTE(M),?BYTE(N),Acc/binary>>).
+
+
+hello_extensions_list(HelloExtensions) ->
+ [Ext || {_, Ext} <- maps:to_list(HelloExtensions), Ext =/= undefined].
%%-------------Decode handshakes---------------------------------
dec_server_key(<<?UINT16(PLen), P:PLen/binary,
@@ -1871,16 +2036,16 @@ dec_server_key_signature(Params, <<?UINT16(Len), Signature:Len/binary>>, _) ->
dec_server_key_signature(_, _, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, failed_to_decrypt_server_key_sign)).
-dec_hello_extensions(<<>>, Acc) ->
+decode_extensions(<<>>, Acc) ->
Acc;
-dec_hello_extensions(<<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc)
+decode_extensions(<<?UINT16(?ALPN_EXT), ?UINT16(ExtLen), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc)
when Len + 2 =:= ExtLen ->
ALPN = #alpn{extension_data = ExtensionData},
- dec_hello_extensions(Rest, Acc#hello_extensions{alpn = ALPN});
-dec_hello_extensions(<<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Acc#{alpn => ALPN});
+decode_extensions(<<?UINT16(?NEXTPROTONEG_EXT), ?UINT16(Len), ExtensionData:Len/binary, Rest/binary>>, Acc) ->
NextP = #next_protocol_negotiation{extension_data = ExtensionData},
- dec_hello_extensions(Rest, Acc#hello_extensions{next_protocol_negotiation = NextP});
-dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Acc#{next_protocol_negotiation => NextP});
+decode_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binary, Rest/binary>>, Acc) ->
RenegotiateInfo = case Len of
1 -> % Initial handshake
Info; % should be <<0>> will be matched in handle_renegotiation_info
@@ -1889,24 +2054,34 @@ dec_hello_extensions(<<?UINT16(?RENEGOTIATION_EXT), ?UINT16(Len), Info:Len/binar
<<?BYTE(VerifyLen), VerifyInfo/binary>> = Info,
VerifyInfo
end,
- dec_hello_extensions(Rest, Acc#hello_extensions{renegotiation_info =
- #renegotiation_info{renegotiated_connection =
- RenegotiateInfo}});
+ decode_extensions(Rest, Acc#{renegotiation_info =>
+ #renegotiation_info{renegotiated_connection =
+ RenegotiateInfo}});
-dec_hello_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
+decode_extensions(<<?UINT16(?SRP_EXT), ?UINT16(Len), ?BYTE(SRPLen), SRP:SRPLen/binary, Rest/binary>>, Acc)
when Len == SRPLen + 2 ->
- dec_hello_extensions(Rest, Acc#hello_extensions{srp = #srp{username = SRP}});
+ decode_extensions(Rest, Acc#{srp => #srp{username = SRP}});
-dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
+decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
SignAlgoListLen = Len - 2,
<<?UINT16(SignAlgoListLen), SignAlgoList/binary>> = ExtData,
HashSignAlgos = [{ssl_cipher:hash_algorithm(Hash), ssl_cipher:sign_algorithm(Sign)} ||
<<?BYTE(Hash), ?BYTE(Sign)>> <= SignAlgoList],
- dec_hello_extensions(Rest, Acc#hello_extensions{signature_algs =
- #hash_sign_algos{hash_sign_algos = HashSignAlgos}});
+ decode_extensions(Rest, Acc#{signature_algs =>
+ #hash_sign_algos{hash_sign_algos = HashSignAlgos}});
-dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
+decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) ->
+ SignSchemeListLen = Len - 2,
+ <<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
+ SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList],
+ decode_extensions(Rest, Acc#{signature_algs_cert =>
+ #signature_scheme_list{
+ signature_scheme_list = SignSchemes}});
+
+decode_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?UINT16(_), EllipticCurveList/binary>> = ExtData,
%% Ignore unknown curves
@@ -1919,31 +2094,42 @@ dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
end
end,
EllipticCurves = lists:filtermap(Pick, [ECC || <<ECC:16>> <= EllipticCurveList]),
- dec_hello_extensions(Rest, Acc#hello_extensions{elliptic_curves =
- #elliptic_curves{elliptic_curve_list =
- EllipticCurves}});
-dec_hello_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
+ decode_extensions(Rest, Acc#{elliptic_curves =>
+ #elliptic_curves{elliptic_curve_list =
+ EllipticCurves}});
+decode_extensions(<<?UINT16(?EC_POINT_FORMATS_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?BYTE(_), ECPointFormatList/binary>> = ExtData,
ECPointFormats = binary_to_list(ECPointFormatList),
- dec_hello_extensions(Rest, Acc#hello_extensions{ec_point_formats =
- #ec_point_formats{ec_point_format_list =
- ECPointFormats}});
+ decode_extensions(Rest, Acc#{ec_point_formats =>
+ #ec_point_formats{ec_point_format_list =
+ ECPointFormats}});
-dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len), Rest/binary>>, Acc) when Len == 0 ->
- dec_hello_extensions(Rest, Acc#hello_extensions{sni = ""}); %% Server may send an empy SNI
+decode_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len), Rest/binary>>, Acc) when Len == 0 ->
+ decode_extensions(Rest, Acc#{sni => #sni{hostname = ""}}); %% Server may send an empy SNI
-dec_hello_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
+decode_extensions(<<?UINT16(?SNI_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?UINT16(_), NameList/binary>> = ExtData,
- dec_hello_extensions(Rest, Acc#hello_extensions{sni = dec_sni(NameList)});
+ decode_extensions(Rest, Acc#{sni => dec_sni(NameList)});
+
+decode_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ExtData:Len/binary, Rest/binary>>, Acc) when Len > 2 ->
+ <<?UINT16(_),Versions/binary>> = ExtData,
+ decode_extensions(Rest, Acc#{client_hello_versions =>
+ #client_hello_versions{versions = decode_versions(Versions)}});
+
+decode_extensions(<<?UINT16(?SUPPORTED_VERSIONS_EXT), ?UINT16(Len),
+ ?UINT16(Version), Rest/binary>>, Acc) when Len =:= 2, Version =:= 16#0304 ->
+ decode_extensions(Rest, Acc#{server_hello_selected_version =>
+ #server_hello_selected_version{selected_version = {3,4}}});
+
%% Ignore data following the ClientHello (i.e.,
%% extensions) if not understood.
-
-dec_hello_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Acc) ->
- dec_hello_extensions(Rest, Acc);
+decode_extensions(<<?UINT16(_), ?UINT16(Len), _Unknown:Len/binary, Rest/binary>>, Acc) ->
+ decode_extensions(Rest, Acc);
%% This theoretically should not happen if the protocol is followed, but if it does it is ignored.
-dec_hello_extensions(_, Acc) ->
+decode_extensions(_, Acc) ->
Acc.
dec_hashsign(<<?BYTE(HashAlgo), ?BYTE(SignAlgo)>>) ->
@@ -1961,6 +2147,15 @@ decode_alpn(undefined) ->
decode_alpn(#alpn{extension_data=Data}) ->
decode_protocols(Data, []).
+decode_versions(Versions) ->
+ decode_versions(Versions, []).
+%%
+decode_versions(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_versions(<<?BYTE(M),?BYTE(N),Rest/binary>>, Acc) ->
+ decode_versions(Rest, [{M,N}|Acc]).
+
+
decode_next_protocols({next_protocol_negotiation, Protocols}) ->
decode_protocols(Protocols, []).
@@ -2218,17 +2413,6 @@ handle_srp_extension(undefined, Session) ->
handle_srp_extension(#srp{username = Username}, Session) ->
Session#session{srp_username = Username}.
-
-sign_algo(?rsaEncryption) ->
- rsa;
-sign_algo(?'id-ecPublicKey') ->
- ecdsa;
-sign_algo(?'id-dsa') ->
- dsa;
-sign_algo(Alg) ->
- {_, Sign} =public_key:pkix_sign_types(Alg),
- Sign.
-
is_acceptable_hash_sign( _, KeyExAlgo, _) when
KeyExAlgo == psk;
KeyExAlgo == dhe_psk;
@@ -2244,15 +2428,80 @@ is_acceptable_hash_sign(Algos,_, SupportedHashSigns) ->
is_acceptable_hash_sign(Algos, SupportedHashSigns) ->
lists:member(Algos, SupportedHashSigns).
-is_acceptable_cert_type(Sign, _HashSigns, Types) ->
+is_acceptable_cert_type(Sign, Types) ->
lists:member(sign_type(Sign), binary_to_list(Types)).
-is_supported_sign(Sign, HashSigns) ->
- [] =/= lists:dropwhile(fun({_, S}) when S =/= Sign ->
- true;
- (_)->
- false
- end, HashSigns).
+%% signature_algorithms_cert = undefined
+is_supported_sign(SignAlgo, _, HashSigns, undefined) ->
+ lists:member(SignAlgo, HashSigns);
+
+%% {'SignatureAlgorithm',{1,2,840,113549,1,1,11},'NULL'}
+is_supported_sign({Hash, Sign}, 'NULL', _, SignatureSchemes) ->
+ Fun = fun (Scheme, Acc) ->
+ {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme),
+ S1 = case S0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ H1 = case H0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ Acc orelse (Sign =:= S1 andalso
+ Hash =:= H1)
+ end,
+ lists:foldl(Fun, false, SignatureSchemes);
+
+%% TODO: Implement validation for the curve used in the signature
+%% RFC 3279 - 2.2.3 ECDSA Signature Algorithm
+%% When the ecdsa-with-SHA1 algorithm identifier appears as the
+%% algorithm field in an AlgorithmIdentifier, the encoding MUST omit the
+%% parameters field. That is, the AlgorithmIdentifier SHALL be a
+%% SEQUENCE of one component: the OBJECT IDENTIFIER ecdsa-with-SHA1.
+%%
+%% The elliptic curve parameters in the subjectPublicKeyInfo field of
+%% the certificate of the issuer SHALL apply to the verification of the
+%% signature.
+is_supported_sign({Hash, Sign}, _Param, _, SignatureSchemes) ->
+ Fun = fun (Scheme, Acc) ->
+ {H0, S0, _} = ssl_cipher:scheme_to_components(Scheme),
+ S1 = case S0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ H1 = case H0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ Acc orelse (Sign =:= S1 andalso
+ Hash =:= H1)
+ end,
+ lists:foldl(Fun, false, SignatureSchemes).
+
+%% SupportedPublicKeyAlgorithms PUBLIC-KEY-ALGORITHM-CLASS ::= {
+%% dsa | rsa-encryption | dh | kea | ec-public-key }
+public_key_algo(?rsaEncryption) ->
+ rsa;
+public_key_algo(?'id-ecPublicKey') ->
+ ecdsa;
+public_key_algo(?'id-dsa') ->
+ dsa.
+
+%% SupportedSignatureAlgorithms SIGNATURE-ALGORITHM-CLASS ::= {
+%% dsa-with-sha1 | dsaWithSHA1 | md2-with-rsa-encryption |
+%% md5-with-rsa-encryption | sha1-with-rsa-encryption | sha-1with-rsa-encryption |
+%% sha224-with-rsa-encryption |
+%% sha256-with-rsa-encryption |
+%% sha384-with-rsa-encryption |
+%% sha512-with-rsa-encryption |
+%% ecdsa-with-sha1 |
+%% ecdsa-with-sha224 |
+%% ecdsa-with-sha256 |
+%% ecdsa-with-sha384 |
+%% ecdsa-with-sha512 }
+sign_algo(Alg) ->
+ public_key:pkix_sign_types(Alg).
+
sign_type(rsa) ->
?RSA_SIGN;
sign_type(dsa) ->
@@ -2425,7 +2674,7 @@ handle_renegotiation_info(_RecordCB, ConnectionStates, SecureRenegotation) ->
cert_curve(_, _, no_suite) ->
{no_curve, no_suite};
cert_curve(Cert, ECCCurve0, CipherSuite) ->
- case ssl_cipher:suite_definition(CipherSuite) of
+ case ssl_cipher_format:suite_definition(CipherSuite) of
#{key_exchange := Kex} when Kex == ecdh_ecdsa;
Kex == ecdh_rsa ->
OtpCert = public_key:pkix_decode_cert(Cert, otp),
@@ -2438,4 +2687,39 @@ cert_curve(Cert, ECCCurve0, CipherSuite) ->
{ECCCurve0, CipherSuite}
end.
-
+empty_hello_extensions({3, 4}, server) ->
+ #{server_hello_selected_version => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined,
+ sni => undefined
+ };
+empty_hello_extensions({3, 4}, client) ->
+ #{client_hello_versions => undefined,
+ signature_algs => undefined,
+ signature_algs_cert => undefined,
+ sni => undefined,
+ alpn => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined
+ };
+empty_hello_extensions({3, 3}, client) ->
+ Ext = empty_hello_extensions({3,2}, client),
+ Ext#{client_hello_versions => undefined,
+ signature_algs => undefined,
+ signature_algs_cert => undefined};
+empty_hello_extensions(_, client) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ srp => undefined,
+ ec_point_formats => undefined,
+ elliptic_curves => undefined,
+ sni => undefined};
+empty_hello_extensions(_, server) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ ec_point_formats => undefined,
+ sni => undefined}.
+empty_extensions() ->
+ #{}.
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index a191fcf766..b14bc21862 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -105,7 +105,10 @@
srp,
ec_point_formats,
elliptic_curves,
- sni
+ sni,
+ client_hello_versions,
+ server_hello_selected_version,
+ signature_algs_cert
}).
-record(server_hello, {
@@ -318,7 +321,7 @@
}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Application-Layer Protocol Negotiation RFC 7301
+%% RFC 7301 Application-Layer Protocol Negotiation
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(ALPN_EXT, 16).
@@ -338,7 +341,7 @@
-record(next_protocol, {selected_protocol}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% ECC Extensions RFC 4492 section 4 and 5
+%% ECC Extensions RFC 8422 section 4 and 5 (RFC 7919 not supported)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(ELLIPTIC_CURVES_EXT, 10).
@@ -365,10 +368,11 @@
-define(NAMED_CURVE, 3).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Server name indication RFC 6066 section 3
+%% RFC 6066 Server name indication
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--define(SNI_EXT, 16#0000).
+%% section 3
+-define(SNI_EXT, 0).
%% enum { host_name(0), (255) } NameType;
-define(SNI_NAMETYPE_HOST_NAME, 0).
@@ -377,4 +381,56 @@
hostname = undefined
}).
+%% Other possible values from RFC 6066, not supported
+-define(MAX_FRAGMENT_LENGTH, 1).
+-define(CLIENT_CERTIFICATE_URL, 2).
+-define(TRUSTED_CA_KEYS, 3).
+-define(TRUNCATED_HMAC, 4).
+-define(STATUS_REQUEST, 5).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7250 Using Raw Public Keys in Transport Layer Security (TLS)
+%% and Datagram Transport Layer Security (DTLS)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(CLIENT_CERTIFICATE_TYPE, 19).
+-define(SERVER_CERTIFICATE_TYPE, 20).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 6520 Transport Layer Security (TLS) and
+%% Datagram Transport Layer Security (DTLS) Heartbeat Extension
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(HS_HEARTBEAT, 15).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 6962 Certificate Transparency
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(SIGNED_CERTIFICATE_TIMESTAMP, 18).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% RFC 7685 A Transport Layer Security (TLS) ClientHello Padding Extension
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Not supported
+-define(PADDING, 21).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Supported Versions RFC 8446 (TLS 1.3) section 4.2.1 also affects TLS-1.2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SUPPORTED_VERSIONS_EXT, 43).
+
+-record(client_hello_versions, {versions}).
+-record(server_hello_selected_version, {selected_version}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Signature Algorithms RFC 8446 (TLS 1.3) section 4.2.3 also affects TLS-1.2
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SIGNATURE_ALGORITHMS_CERT_EXT, 50).
+
+-record(signature_scheme_list, {signature_scheme_list}).
+
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index a98cbf8542..5a18f6aa99 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -72,14 +72,39 @@
-define(FALSE, 1).
%% sslv3 is considered insecure due to lack of padding check (Poodle attack)
-%% Keep as interop with legacy software but do not support as default
--define(ALL_AVAILABLE_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+%% Keep as interop with legacy software but do not support as default
+%% tlsv1.3 is under development (experimental).
+-define(ALL_AVAILABLE_VERSIONS, ['tlsv1.3', 'tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
-define(ALL_AVAILABLE_DATAGRAM_VERSIONS, ['dtlsv1.2', dtlsv1]).
+%% Defines the default versions when not specified by an ssl option.
-define(ALL_SUPPORTED_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1]).
-define(MIN_SUPPORTED_VERSIONS, ['tlsv1.1', tlsv1]).
+
+%% Versions allowed in TLSCiphertext.version (TLS 1.2 and prior) and
+%% TLSCiphertext.legacy_record_version (TLS 1.3).
+%% TLS 1.3 sets TLSCiphertext.legacy_record_version to 0x0303 for all records
+%% generated other than an than an initial ClientHello, where it MAY also be 0x0301.
+%% Thus, the allowed range is limited to 0x0300 - 0x0303.
+-define(ALL_TLS_RECORD_VERSIONS, ['tlsv1.2', 'tlsv1.1', tlsv1, sslv3]).
+
-define(ALL_DATAGRAM_SUPPORTED_VERSIONS, ['dtlsv1.2', dtlsv1]).
-define(MIN_DATAGRAM_SUPPORTED_VERSIONS, [dtlsv1]).
+%% TLS 1.3 - Section 4.1.3
+%%
+%% If negotiating TLS 1.2, TLS 1.3 servers MUST set the last eight bytes
+%% of their Random value to the bytes:
+%%
+%% 44 4F 57 4E 47 52 44 01
+%%
+%% If negotiating TLS 1.1 or below, TLS 1.3 servers MUST and TLS 1.2
+%% servers SHOULD set the last eight bytes of their Random value to the
+%% bytes:
+%%
+%% 44 4F 57 4E 47 52 44 00
+-define(RANDOM_OVERRIDE_TLS12, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#01>>).
+-define(RANDOM_OVERRIDE_TLS11, <<16#44,16#4F,16#57,16#4E,16#47,16#52,16#44,16#00>>).
+
-define('24H_in_msec', 86400000).
-define('24H_in_sec', 86400).
@@ -121,7 +146,7 @@
%% undefined if not hibernating, or number of ms of
%% inactivity after which ssl_connection will go into
%% hibernation
- hibernate_after :: timeout(),
+ hibernate_after :: timeout(),
%% This option should only be set to true by inet_tls_dist
erl_dist = false :: boolean(),
alpn_advertised_protocols = undefined :: [binary()] | undefined ,
@@ -143,6 +168,7 @@
crl_check :: boolean() | peer | best_effort,
crl_cache,
signature_algs,
+ signature_algs_cert,
eccs,
honor_ecc_order :: boolean(),
max_handshake_size :: integer(),
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
index 23e9e096cc..35c8dcfd48 100644
--- a/lib/ssl/src/ssl_logger.erl
+++ b/lib/ssl/src/ssl_logger.erl
@@ -156,7 +156,9 @@ version({3,2}) ->
version({3,1}) ->
"TLS 1.0";
version({3,0}) ->
- "SSL 3.0".
+ "SSL 3.0";
+version({M,N}) ->
+ io_lib:format("TLS [0x0~B0~B]", [M,N]).
header_prefix(inbound) ->
@@ -183,7 +185,6 @@ header_prefix_tls_record(outbound) ->
"writing".
-
tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(3),_/binary>>|_]) ->
io_lib:format("TLS 1.2 Record Protocol, ~s", [msg_type(B)]);
tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(2),_/binary>>|_]) ->
@@ -191,7 +192,9 @@ tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(2),_/binary>>|_]) ->
tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(1),_/binary>>|_]) ->
io_lib:format("TLS 1.0 Record Protocol, ~s", [msg_type(B)]);
tls_record_version([<<?BYTE(B),?BYTE(3),?BYTE(0),_/binary>>|_]) ->
- io_lib:format("SSL 3.0 Record Protocol, ~s", [msg_type(B)]).
+ io_lib:format("SSL 3.0 Record Protocol, ~s", [msg_type(B)]);
+tls_record_version([<<?BYTE(B),?BYTE(M),?BYTE(N),_/binary>>|_]) ->
+ io_lib:format("TLS [0x0~B0~B] Record Protocol, ~s", [M, N, msg_type(B)]).
msg_type(20) -> "change_cipher_spec";
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index f44fe6a2bf..c938772bc1 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -127,7 +127,13 @@ cache_pem_file(File, DbHandle) ->
[Content] ->
{ok, Content};
undefined ->
- ssl_pem_cache:insert(File)
+ case ssl_pkix_db:decode_pem_file(File) of
+ {ok, Content} ->
+ ssl_pem_cache:insert(File, Content),
+ {ok, Content};
+ Error ->
+ Error
+ end
end.
%%--------------------------------------------------------------------
@@ -499,10 +505,10 @@ last_delay_timer({{_,_},_}, TRef, {LastServer, _}) ->
last_delay_timer({_,_}, TRef, {_, LastClient}) ->
{TRef, LastClient}.
-%% If we can not generate a not allready in use session ID in
+%% If we cannot generate a not allready in use session ID in
%% ?GEN_UNIQUE_ID_MAX_TRIES we make the new session uncacheable The
%% value of ?GEN_UNIQUE_ID_MAX_TRIES is stolen from open SSL which
-%% states : "If we can not find a session id in
+%% states : "If we cannot find a session id in
%% ?GEN_UNIQUE_ID_MAX_TRIES either the RAND code is broken or someone
%% is trying to open roughly very close to 2^128 (or 2^256) SSL
%% sessions to our server"
@@ -513,7 +519,7 @@ new_id(Port, Tries, Cache, CacheCb) ->
case CacheCb:lookup(Cache, {Port, Id}) of
undefined ->
Now = erlang:monotonic_time(),
- %% New sessions can not be set to resumable
+ %% New sessions cannot be set to resumable
%% until handshake is compleate and the
%% other session values are set.
CacheCb:update(Cache, {Port, Id}, #session{session_id = Id,
diff --git a/lib/ssl/src/ssl_pem_cache.erl b/lib/ssl/src/ssl_pem_cache.erl
index 115ab4451d..41bca2f7b5 100644
--- a/lib/ssl/src/ssl_pem_cache.erl
+++ b/lib/ssl/src/ssl_pem_cache.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 20016-2017. All Rights Reserved.
+%% Copyright Ericsson AB 20016-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@
-export([start_link/1,
start_link_dist/1,
name/1,
- insert/1,
+ insert/2,
clear/0]).
% Spawn export
@@ -45,7 +45,7 @@
-record(state, {
pem_cache,
- last_pem_check :: erlang:timestamp(),
+ last_pem_check :: integer(),
clear :: integer()
}).
@@ -90,19 +90,17 @@ start_link_dist(_) ->
%%--------------------------------------------------------------------
--spec insert(binary()) -> {ok, term()} | {error, reason()}.
+-spec insert(binary(), term()) -> ok | {error, reason()}.
%%
%% Description: Cache a pem file and return its content.
%%--------------------------------------------------------------------
-insert(File) ->
- {ok, PemBin} = file:read_file(File),
- Content = public_key:pem_decode(PemBin),
+insert(File, Content) ->
case bypass_cache() of
true ->
- {ok, Content};
+ ok;
false ->
cast({cache_pem, File, Content}),
- {ok, Content}
+ ok
end.
%%--------------------------------------------------------------------
@@ -136,8 +134,9 @@ init([Name]) ->
PemCache = ssl_pkix_db:create_pem_cache(Name),
Interval = pem_check_interval(),
erlang:send_after(Interval, self(), clear_pem_cache),
+ erlang:system_time(second),
{ok, #state{pem_cache = PemCache,
- last_pem_check = os:timestamp(),
+ last_pem_check = erlang:convert_time_unit(os:system_time(), native, second),
clear = Interval
}}.
@@ -185,7 +184,7 @@ handle_cast({invalidate_pem, File}, #state{pem_cache = Db} = State) ->
handle_info(clear_pem_cache, #state{pem_cache = PemCache,
clear = Interval,
last_pem_check = CheckPoint} = State) ->
- NewCheckPoint = os:timestamp(),
+ NewCheckPoint = erlang:convert_time_unit(os:system_time(), native, second),
start_pem_cache_validator(PemCache, CheckPoint),
erlang:send_after(Interval, self(), clear_pem_cache),
{noreply, State#state{last_pem_check = NewCheckPoint}};
@@ -231,24 +230,14 @@ init_pem_cache_validator([CacheName, PemCache, CheckPoint]) ->
CheckPoint, PemCache).
pem_cache_validate({File, _}, CheckPoint) ->
- case file:read_file_info(File, []) of
- {ok, #file_info{mtime = Time}} ->
- case is_before_checkpoint(Time, CheckPoint) of
- true ->
- ok;
- false ->
- invalidate_pem(File)
- end;
+ case file:read_file_info(File, [{time, posix}]) of
+ {ok, #file_info{mtime = Time}} when Time < CheckPoint ->
+ ok;
_ ->
invalidate_pem(File)
end,
CheckPoint.
-is_before_checkpoint(Time, CheckPoint) ->
- calendar:datetime_to_gregorian_seconds(
- calendar:now_to_datetime(CheckPoint)) -
- calendar:datetime_to_gregorian_seconds(Time) > 0.
-
pem_check_interval() ->
case application:get_env(ssl, ssl_pem_cache_clean) of
{ok, Interval} when is_integer(Interval) ->
diff --git a/lib/ssl/src/ssl_pkix_db.erl b/lib/ssl/src/ssl_pkix_db.erl
index 4132733ae0..dec48fa914 100644
--- a/lib/ssl/src/ssl_pkix_db.erl
+++ b/lib/ssl/src/ssl_pkix_db.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -158,7 +158,7 @@ extract_trusted_certs(File) ->
{error, {badmatch, Error}}
end.
--spec decode_pem_file(binary()) -> {ok, term()}.
+-spec decode_pem_file(binary()) -> {ok, term()} | {error, term()}.
decode_pem_file(File) ->
case file:read_file(File) of
{ok, PemBin} ->
@@ -317,11 +317,16 @@ decode_certs(Ref, Cert) ->
end.
new_trusted_cert_entry(File, [CertsDb, RefsDb, _ | _]) ->
- Ref = make_ref(),
- init_ref_db(Ref, File, RefsDb),
- {ok, Content} = ssl_pem_cache:insert(File),
- add_certs_from_pem(Content, Ref, CertsDb),
- {ok, Ref}.
+ case decode_pem_file(File) of
+ {ok, Content} ->
+ Ref = make_ref(),
+ init_ref_db(Ref, File, RefsDb),
+ ok = ssl_pem_cache:insert(File, Content),
+ add_certs_from_pem(Content, Ref, CertsDb),
+ {ok, Ref};
+ Error ->
+ Error
+ end.
add_crls([_,_,_, {_, Mapping} | _], ?NO_DIST_POINT, CRLs) ->
[add_crls(CRL, Mapping) || CRL <- CRLs];
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 659e1485ac..ddc83821b4 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -45,7 +45,7 @@
-export([compress/3, uncompress/3, compressions/0]).
%% Payload encryption/decryption
--export([cipher/4, decipher/4, cipher_aead/4, is_correct_mac/2]).
+-export([cipher/4, decipher/4, cipher_aead/4, decipher_aead/5, is_correct_mac/2, nonce_seed/3]).
-export_type([ssl_version/0, ssl_atom_version/0, connection_states/0, connection_state/0]).
@@ -278,13 +278,12 @@ compress(?NULL, Data, CS) ->
{Data, CS}.
%%--------------------------------------------------------------------
--spec compressions() -> [binary()].
+-spec compressions() -> [integer()].
%%
%% Description: return a list of compressions supported (currently none)
%%--------------------------------------------------------------------
compressions() ->
- [?byte(?NULL)].
-
+ [?NULL].
%%====================================================================
%% Payload encryption/decryption
@@ -306,22 +305,20 @@ cipher(Version, Fragment,
{CipherFragment, CipherS1} =
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
{CipherFragment, WriteState0#{cipher_state => CipherS1}}.
-%% %%--------------------------------------------------------------------
-%% -spec cipher_aead(ssl_version(), iodata(), connection_state(), MacHash::binary()) ->
-%% {CipherFragment::binary(), connection_state()}.
-%% %%
-%% %% Description: Payload encryption
+%%--------------------------------------------------------------------
+-spec cipher_aead(ssl_version(), iodata(), connection_state(), AAD::binary()) ->
+ {CipherFragment::binary(), connection_state()}.
+
+%% Description: Payload encryption
%% %%--------------------------------------------------------------------
cipher_aead(Version, Fragment,
#{cipher_state := CipherS0,
- sequence_number := SeqNo,
security_parameters :=
#security_parameters{bulk_cipher_algorithm =
BulkCipherAlgo}
} = WriteState0, AAD) ->
-
{CipherFragment, CipherS1} =
- ssl_cipher:cipher_aead(BulkCipherAlgo, CipherS0, SeqNo, AAD, Fragment, Version),
+ cipher_aead(BulkCipherAlgo, CipherS0, AAD, Fragment, Version),
{CipherFragment, WriteState0#{cipher_state => CipherS1}}.
%%--------------------------------------------------------------------
@@ -344,10 +341,39 @@ decipher(Version, CipherFragment,
#alert{} = Alert ->
Alert
end.
+%%--------------------------------------------------------------------
+-spec decipher_aead(ssl_cipher:cipher_enum(), #cipher_state{},
+ binary(), binary(), ssl_record:ssl_version()) ->
+ {binary(), #cipher_state{}} | #alert{}.
+%%
+%% Description: Decrypts the data and checks the associated data (AAD) MAC using
+%% cipher described by cipher_enum() and updating the cipher state.
+%% Use for suites that use authenticated encryption with associated data (AEAD)
+%%-------------------------------------------------------------------
+decipher_aead(Type, #cipher_state{key = Key} = CipherState, AAD0, CipherFragment, _) ->
+ try
+ Nonce = decrypt_nonce(Type, CipherState, CipherFragment),
+ {AAD, CipherText, CipherTag} = aead_ciphertext_split(Type, CipherState, CipherFragment, AAD0),
+ case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ {Content, CipherState};
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end.
+
+nonce_seed(?CHACHA20_POLY1305, Seed, CipherState) ->
+ ssl_cipher:nonce_seed(Seed, CipherState);
+nonce_seed(_,_, CipherState) ->
+ CipherState.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+
empty_connection_state(ConnectionEnd, BeastMitigation) ->
SecParams = empty_security_params(ConnectionEnd),
#{security_parameters => SecParams,
@@ -400,3 +426,37 @@ initial_security_params(ConnectionEnd) ->
compression_algorithm = ?NULL},
ssl_cipher:security_parameters(?TLS_NULL_WITH_NULL_NULL, SecParams).
+cipher_aead(?CHACHA20_POLY1305 = Type, #cipher_state{key=Key} = CipherState, AAD0, Fragment, _Version) ->
+ AAD = end_additional_data(AAD0, erlang:iolist_size(Fragment)),
+ Nonce = encrypt_nonce(Type, CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {<<Content/binary, CipherTag/binary>>, CipherState};
+cipher_aead(Type, #cipher_state{key=Key, nonce = ExplicitNonce} = CipherState, AAD0, Fragment, _Version) ->
+ AAD = end_additional_data(AAD0, erlang:iolist_size(Fragment)),
+ Nonce = encrypt_nonce(Type, CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {<<ExplicitNonce:64/integer, Content/binary, CipherTag/binary>>, CipherState#cipher_state{nonce = ExplicitNonce + 1}}.
+
+encrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}) ->
+ crypto:exor(<<?UINT32(0), Nonce/binary>>, IV);
+encrypt_nonce(?AES_GCM, #cipher_state{iv = IV, nonce = ExplicitNonce}) ->
+ <<Salt:4/bytes, _/binary>> = IV,
+ <<Salt/binary, ExplicitNonce:64/integer>>.
+
+decrypt_nonce(?CHACHA20_POLY1305, #cipher_state{nonce = Nonce, iv = IV}, _) ->
+ crypto:exor(<<Nonce:96/unsigned-big-integer>>, IV);
+decrypt_nonce(?AES_GCM, #cipher_state{iv = <<Salt:4/bytes, _/binary>>}, <<ExplicitNonce:8/bytes, _/binary>>) ->
+ <<Salt/binary, ExplicitNonce/binary>>.
+
+aead_ciphertext_split(?CHACHA20_POLY1305, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+ CipherLen = size(CipherTextFragment) - Len,
+ <<CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
+ {end_additional_data(AAD, CipherLen), CipherText, CipherTag};
+aead_ciphertext_split(?AES_GCM, #cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+ CipherLen = size(CipherTextFragment) - (Len + 8), %% 8 is length of explicit Nonce
+ << _:8/bytes, CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
+ {end_additional_data(AAD, CipherLen), CipherText, CipherTag}.
+
+end_additional_data(AAD, Len) ->
+ <<AAD/binary, ?UINT16(Len)>>.
+
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index ed007f58d7..4cb19d9d0d 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -74,7 +74,7 @@
-define(INITIAL_BYTES, 5).
-define(MAX_SEQENCE_NUMBER, 18446744073709551615). %% (1 bsl 64) - 1 = 18446744073709551615
-%% Sequence numbers can not wrap so when max is about to be reached we should renegotiate.
+%% Sequence numbers cannot wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
%% often as we can have a cheaper test to check if it is time to renegotiate. It will still
@@ -140,6 +140,7 @@
-define(ALERT, 21).
-define(HANDSHAKE, 22).
-define(APPLICATION_DATA, 23).
+-define(HEARTBEAT, 24).
-define(MAX_PLAIN_TEXT_LENGTH, 16384).
-define(MAX_COMPRESSED_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+1024)).
-define(MAX_CIPHER_TEXT_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+2048)).
diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl
index 82d165f995..4eab60b440 100644
--- a/lib/ssl/src/ssl_v3.erl
+++ b/lib/ssl/src/ssl_v3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -131,7 +131,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec suites() -> [ssl_cipher:cipher_suite()].
+-spec suites() -> [ssl_cipher_format:cipher_suite()].
suites() ->
[
diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl
deleted file mode 100644
index aa41cd1ba6..0000000000
--- a/lib/ssl/src/tls.erl
+++ /dev/null
@@ -1,112 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : Reflect TLS specific API options (fairly simple wrapper at the moment)
-
--module(tls).
-
--include("ssl_api.hrl").
--include("ssl_internal.hrl").
-
--export([connect/2, connect/3, listen/2, accept/1, accept/2,
- handshake/1, handshake/2, handshake/3]).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Connect to an TLS server.
-%%--------------------------------------------------------------------
-
--spec connect(host() | port(), [connect_option()]) -> {ok, #sslsocket{}} |
- {error, reason()}.
-
-connect(Socket, Options) when is_port(Socket) ->
- connect(Socket, Options, infinity).
-
--spec connect(host() | port(), [connect_option()] | inet:port_number(),
- timeout() | list()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Socket, SslOptions, Timeout) when is_port(Socket) ->
- TLSOpts = [{protocol, tls} | SslOptions],
- ssl:connect(Socket, TLSOpts, Timeout);
-connect(Host, Port, Options) ->
- connect(Host, Port, Options, infinity).
-
--spec connect(host() | port(), inet:port_number(), list(), timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-connect(Host, Port, Options, Timeout) ->
- TLSOpts = [{protocol, tls} | Options],
- ssl:connect(Host, Port, TLSOpts, Timeout).
-
-%%--------------------------------------------------------------------
--spec listen(inet:port_number(), [listen_option()]) ->{ok, #sslsocket{}} | {error, reason()}.
-
-%%
-%% Description: Creates an ssl listen socket.
-%%--------------------------------------------------------------------
-listen(Port, Options) ->
- TLSOpts = [{protocol, tls} | Options],
- ssl:listen(Port, TLSOpts).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs transport accept on an ssl listen socket
-%%--------------------------------------------------------------------
--spec accept(#sslsocket{}) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(ListenSocket) ->
- accept(ListenSocket, infinity).
-
--spec accept(#sslsocket{}, timeout()) -> {ok, #sslsocket{}} |
- {error, reason()}.
-accept(Socket, Timeout) ->
- ssl:transport_accept(Socket, Timeout).
-
-%%--------------------------------------------------------------------
-%%
-%% Description: Performs accept on an ssl listen socket. e.i. performs
-%% ssl handshake.
-%%--------------------------------------------------------------------
-
--spec handshake(#sslsocket{}) -> ok | {error, reason()}.
-
-handshake(ListenSocket) ->
- handshake(ListenSocket, infinity).
-
-
--spec handshake(#sslsocket{} | port(), timeout()| [ssl_option()
- | transport_option()]) ->
- ok | {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(#sslsocket{} = Socket, Timeout) ->
- ssl:ssl_accept(Socket, Timeout);
-
-handshake(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- handshake(ListenSocket, SslOptions, infinity).
-
-
--spec handshake(port(), [ssl_option()| transport_option()], timeout()) ->
- {ok, #sslsocket{}} | {error, reason()}.
-
-handshake(Socket, SslOptions, Timeout) when is_port(Socket) ->
- ssl:ssl_accept(Socket, SslOptions, Timeout).
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 1a0a9b9275..af59dda442 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -44,30 +44,37 @@
%% Internal application API
%% Setup
--export([start_fsm/8, start_link/7, init/1]).
+-export([start_fsm/8, start_link/8, init/1, pids/1]).
%% State transition handling
--export([next_record/1, next_event/3, next_event/4, handle_common_event/4]).
+-export([next_record/1, next_event/3, next_event/4,
+ handle_common_event/4]).
%% Handshake handling
--export([renegotiate/2, send_handshake/2,
+-export([renegotiation/2, renegotiate/2, send_handshake/2,
queue_handshake/2, queue_change_cipher/2,
- reinit_handshake_data/1, select_sni_extension/1, empty_connection_state/2]).
+ reinit/1, reinit_handshake_data/1, select_sni_extension/1,
+ empty_connection_state/2]).
%% Alert and close handling
--export([encode_alert/3, send_alert/2, close/5, protocol_name/0]).
+-export([send_alert/2, send_alert_in_connection/2,
+ send_sync_alert/2,
+ encode_alert/3, close/5, protocol_name/0]).
%% Data handling
--export([encode_data/3, passive_receive/2, next_record_if_active/1, send/3,
- socket/5, setopts/3, getopts/3]).
+-export([encode_data/3, passive_receive/2, next_record_if_active/1,
+ send/3, socket/5, setopts/3, getopts/3]).
%% gen_statem state functions
-export([init/3, error/3, downgrade/3, %% Initiation and take down states
hello/3, user_hello/3, certify/3, cipher/3, abbreviated/3, %% Handshake states
- connection/3, death_row/3]).
+ connection/3]).
%% gen_statem callbacks
-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
+
+-define(DIST_CNTRL_SPAWN_OPTS, [{priority, max}]).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -78,9 +85,10 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_, Tracker}
User, {CbModule, _,_, _} = CbInfo,
Timeout) ->
try
- {ok, Pid} = tls_connection_sup:start_child([Role, Host, Port, Socket,
+ {ok, Sender} = tls_sender:start(),
+ {ok, Pid} = tls_connection_sup:start_child([Role, Sender, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid, Sender], CbModule, Tracker),
ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
@@ -91,9 +99,10 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} =
User, {CbModule, _,_, _} = CbInfo,
Timeout) ->
try
- {ok, Pid} = tls_connection_sup:start_child_dist([Role, Host, Port, Socket,
+ {ok, Sender} = tls_sender:start([{spawn_opt, ?DIST_CNTRL_SPAWN_OPTS}]),
+ {ok, Pid} = tls_connection_sup:start_child_dist([Role, Sender, Host, Port, Socket,
Opts, User, CbInfo]),
- {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule, Tracker),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, [Pid, Sender], CbModule, Tracker),
ssl_connection:handshake(SslSocket, Timeout)
catch
error:{badmatch, {error, _} = Error} ->
@@ -101,25 +110,38 @@ start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_, Tracker} =
end.
%%--------------------------------------------------------------------
--spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
+-spec start_link(atom(), pid(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
{ok, pid()} | ignore | {error, reason()}.
%%
%% Description: Creates a gen_statem process which calls Module:init/1 to
%% initialize.
%%--------------------------------------------------------------------
-start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
- {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
+start_link(Role, Sender, Host, Port, Socket, Options, User, CbInfo) ->
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Sender, Host, Port, Socket, Options, User, CbInfo]])}.
-init([Role, Host, Port, Socket, Options, User, CbInfo]) ->
+init([Role, Sender, Host, Port, Socket, {SslOpts, _, _} = Options, User, CbInfo]) ->
process_flag(trap_exit, true),
- State0 = #state{protocol_specific = Map} = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ link(Sender),
+ case SslOpts#ssl_options.erl_dist of
+ true ->
+ process_flag(priority, max);
+ _ ->
+ ok
+ end,
+ State0 = #state{protocol_specific = Map} = initial_state(Role, Sender,
+ Host, Port, Socket, Options, User, CbInfo),
try
State = ssl_connection:ssl_config(State0#state.ssl_options, Role, State0),
- gen_statem:enter_loop(?MODULE, [], init, State)
+ initialize_tls_sender(State),
+ gen_statem:enter_loop(?MODULE, [], init, State)
catch throw:Error ->
EState = State0#state{protocol_specific = Map#{error => Error}},
gen_statem:enter_loop(?MODULE, [], error, EState)
end.
+
+pids(#state{protocol_specific = #{sender := Sender}}) ->
+ [self(), Sender].
+
%%====================================================================
%% State transition handling
%%====================================================================
@@ -130,9 +152,10 @@ next_record(#state{protocol_buffers =
#protocol_buffers{tls_packets = [], tls_cipher_texts = [CT | Rest]}
= Buffers,
connection_states = ConnStates0,
+ negotiated_version = Version,
ssl_options = #ssl_options{padding_check = Check}} = State) ->
- case tls_record:decode_cipher_text(CT, ConnStates0, Check) of
+ case tls_record:decode_cipher_text(Version, CT, ConnStates0, Check) of
{Plain, ConnStates} ->
{Plain, State#state{protocol_buffers =
Buffers#protocol_buffers{tls_cipher_texts = Rest},
@@ -237,13 +260,15 @@ handle_common_event(internal, #ssl_tls{type = _Unknown}, StateName, State) ->
%%====================================================================
%% Handshake handling
%%====================================================================
+renegotiation(Pid, WriteState) ->
+ gen_statem:call(Pid, {user_renegotiate, WriteState}).
+
renegotiate(#state{role = client} = State, Actions) ->
%% Handle same way as if server requested
%% the renegotiation
Hs0 = ssl_handshake:init_handshake_history(),
{next_state, connection, State#state{tls_handshake_history = Hs0},
[{next_event, internal, #hello_request{}} | Actions]};
-
renegotiate(#state{role = server,
socket = Socket,
transport_cb = Transport,
@@ -303,6 +328,12 @@ queue_change_cipher(Msg, #state{negotiated_version = Version,
State0#state{connection_states = ConnectionStates,
flight_buffer = Flight0 ++ [BinChangeCipher]}.
+reinit(#state{protocol_specific = #{sender := Sender},
+ negotiated_version = Version,
+ connection_states = #{current_write := Write}} = State) ->
+ tls_sender:update_connection_state(Sender, Write, Version),
+ reinit_handshake_data(State).
+
reinit_handshake_data(State) ->
%% premaster_secret, public_key_info and tls_handshake_info
%% are only needed during the handshake phase.
@@ -313,8 +344,8 @@ reinit_handshake_data(State) ->
tls_handshake_history = ssl_handshake:init_handshake_history()
}.
-select_sni_extension(#client_hello{extensions = HelloExtensions}) ->
- HelloExtensions#hello_extensions.sni;
+select_sni_extension(#client_hello{extensions = #{sni := SNI}}) ->
+ SNI;
select_sni_extension(_) ->
undefined.
@@ -324,20 +355,6 @@ empty_connection_state(ConnectionEnd, BeastMitigation) ->
%%====================================================================
%% Alert and close handling
%%====================================================================
-send_alert(Alert, #state{negotiated_version = Version,
- socket = Socket,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- ssl_options = SslOpts} = State0) ->
- {BinMsg, ConnectionStates} =
- encode_alert(Alert, Version, ConnectionStates0),
-
- send(Transport, Socket, BinMsg),
- Report = #{direction => outbound,
- protocol => 'tls_record',
- message => BinMsg},
- ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
- State0#state{connection_states = ConnectionStates}.
%%--------------------------------------------------------------------
-spec encode_alert(#alert{}, ssl_record:ssl_version(), ssl_record:connection_states()) ->
@@ -347,6 +364,42 @@ send_alert(Alert, #state{negotiated_version = Version,
%%--------------------------------------------------------------------
encode_alert(#alert{} = Alert, Version, ConnectionStates) ->
tls_record:encode_alert_record(Alert, Version, ConnectionStates).
+
+send_alert(Alert, #state{negotiated_version = Version,
+ socket = Socket,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ ssl_options = SslOpts} = StateData0) ->
+ {BinMsg, ConnectionStates} = encode_alert(Alert, Version, ConnectionStates0),
+ send(Transport, Socket, BinMsg),
+ Report = #{direction => outbound,
+ protocol => 'tls_record',
+ message => BinMsg},
+ ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
+ StateData0#state{connection_states = ConnectionStates}.
+
+%% If an ALERT sent in the connection state, should cause the TLS
+%% connection to end, we need to synchronize with the tls_sender
+%% process so that the ALERT if possible (that is the tls_sender process is
+%% not blocked) is sent before the connection process terminates and
+%% thereby closes the transport socket.
+send_alert_in_connection(#alert{level = ?FATAL} = Alert, State) ->
+ send_sync_alert(Alert, State);
+send_alert_in_connection(#alert{description = ?CLOSE_NOTIFY} = Alert, State) ->
+ send_sync_alert(Alert, State);
+send_alert_in_connection(Alert,
+ #state{protocol_specific = #{sender := Sender}}) ->
+ tls_sender:send_alert(Sender, Alert).
+send_sync_alert(Alert, #state{protocol_specific = #{sender := Sender}}= State) ->
+ tls_sender:send_and_ack_alert(Sender, Alert),
+ receive
+ {Sender, ack_alert} ->
+ ok
+ after ?DEFAULT_TIMEOUT ->
+ %% Sender is blocked terminate anyway
+ throw({stop, {shutdown, own_alert}, State})
+ end.
+
%% User closes or recursive call!
close({close, Timeout}, Socket, Transport = gen_tcp, _,_) ->
tls_socket:setopts(Transport, Socket, [{active, false}]),
@@ -401,8 +454,8 @@ next_record_if_active(State) ->
send(Transport, Socket, Data) ->
tls_socket:send(Transport, Socket, Data).
-socket(Pid, Transport, Socket, Connection, Tracker) ->
- tls_socket:socket(Pid, Transport, Socket, Connection, Tracker).
+socket(Pids, Transport, Socket, Connection, Tracker) ->
+ tls_socket:socket(Pids, Transport, Socket, Connection, Tracker).
setopts(Transport, Socket, Other) ->
tls_socket:setopts(Transport, Socket, Other).
@@ -479,16 +532,18 @@ error(_, _, _) ->
#state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
-hello(internal, #client_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello},
- start_or_recv_from = From} = State) ->
- {next_state, user_hello, State#state{start_or_recv_from = undefined,
+hello(internal, #client_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ start_or_recv_from = From} = State) ->
+ {next_state, user_hello, State#state{start_or_recv_from = undefined,
hello = Hello},
- [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]};
-hello(internal, #server_hello{extensions = Extensions} = Hello, #state{ssl_options = #ssl_options{handshake = hello},
- start_or_recv_from = From} = State) ->
+ [{reply, From, {ok, Extensions}}]};
+hello(internal, #server_hello{extensions = Extensions} = Hello,
+ #state{ssl_options = #ssl_options{handshake = hello},
+ start_or_recv_from = From} = State) ->
{next_state, user_hello, State#state{start_or_recv_from = undefined,
- hello = Hello},
- [{reply, From, {ok, ssl_connection:map_extensions(Extensions)}}]};
+ hello = Hello},
+ [{reply, From, {ok, Extensions}}]};
hello(internal, #client_hello{client_version = ClientVersion} = Hello,
#state{connection_states = ConnectionStates0,
port = Port, session = #session{own_certificate = Cert} = Session0,
@@ -501,7 +556,9 @@ hello(internal, #client_hello{client_version = ClientVersion} = Hello,
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
ConnectionStates0, Cert, KeyExAlg}, Renegotiation) of
#alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, ClientVersion, hello, State);
+ ssl_connection:handle_own_alert(Alert, ClientVersion, hello,
+ State#state{negotiated_version
+ = ClientVersion});
{Version, {Type, Session},
ConnectionStates, Protocol0, ServerHelloExt, HashSign} ->
Protocol = case Protocol0 of
@@ -524,7 +581,8 @@ hello(internal, #server_hello{} = Hello,
ssl_options = SslOptions} = State) ->
case tls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
#alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, ReqVersion, hello, State);
+ ssl_connection:handle_own_alert(Alert, ReqVersion, hello,
+ State#state{negotiated_version = ReqVersion});
{Version, NewId, ConnectionStates, ProtoExt, Protocol} ->
ssl_connection:handle_session(Hello,
Version, NewId, ConnectionStates, ProtoExt, Protocol, State)
@@ -571,14 +629,19 @@ cipher(Type, Event, State) ->
%%--------------------------------------------------------------------
connection(info, Event, State) ->
gen_info(Event, ?FUNCTION_NAME, State);
+connection({call, From}, {user_renegotiate, WriteState},
+ #state{connection_states = ConnectionStates} = State) ->
+ {next_state, ?FUNCTION_NAME, State#state{connection_states = ConnectionStates#{current_write => WriteState}},
+ [{next_event,{call, From}, renegotiate}]};
connection(internal, #hello_request{},
- #state{role = client, host = Host, port = Port,
+ #state{role = client,
+ renegotiation = {Renegotiation, _},
+ host = Host, port = Port,
session = #session{own_certificate = Cert} = Session0,
session_cache = Cache, session_cache_cb = CacheCb,
- ssl_options = SslOpts,
- connection_states = ConnectionStates0,
- renegotiation = {Renegotiation, _}} = State0) ->
- Hello = tls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates} = State0) ->
+ Hello = tls_handshake:client_hello(Host, Port, ConnectionStates, SslOpts,
Cache, CacheCb, Renegotiation, Cert),
{State1, Actions} = send_handshake(Hello, State0),
{Record, State} =
@@ -587,7 +650,10 @@ connection(internal, #hello_request{},
= Hello#client_hello.session_id}}),
next_event(hello, Record, State, Actions);
connection(internal, #client_hello{} = Hello,
- #state{role = server, allow_renegotiate = true} = State0) ->
+ #state{role = server, allow_renegotiate = true, connection_states = CS,
+ %%protocol_cb = Connection,
+ protocol_specific = #{sender := Sender}
+ } = State0) ->
%% Mitigate Computational DoS attack
%% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
%% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
@@ -596,24 +662,21 @@ connection(internal, #client_hello{} = Hello,
erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
{Record, State} = next_record(State0#state{allow_renegotiate = false,
renegotiation = {true, peer}}),
- next_event(hello, Record, State, [{next_event, internal, Hello}]);
+ {ok, Write} = tls_sender:renegotiate(Sender),
+ next_event(hello, Record, State#state{connection_states = CS#{current_write => Write}},
+ [{next_event, internal, Hello}]);
connection(internal, #client_hello{},
- #state{role = server, allow_renegotiate = false} = State0) ->
+ #state{role = server, allow_renegotiate = false,
+ protocol_cb = Connection} = State0) ->
Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
- State1 = send_alert(Alert, State0),
- {Record, State} = ssl_connection:prepare_connection(State1, ?MODULE),
+ send_alert_in_connection(Alert, State0),
+ State1 = Connection:reinit_handshake_data(State0),
+ {Record, State} = next_record(State1),
next_event(?FUNCTION_NAME, Record, State);
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
%%--------------------------------------------------------------------
--spec death_row(gen_statem:event_type(), term(), #state{}) ->
- gen_statem:state_function_result().
-%%--------------------------------------------------------------------
-death_row(Type, Event, State) ->
- ssl_connection:death_row(Type, Event, State, ?MODULE).
-
-%%--------------------------------------------------------------------
-spec downgrade(gen_statem:event_type(), term(), #state{}) ->
gen_statem:state_function_result().
%%--------------------------------------------------------------------
@@ -627,7 +690,8 @@ callback_mode() ->
state_functions.
terminate(Reason, StateName, State) ->
- catch ssl_connection:terminate(Reason, StateName, State).
+ catch ssl_connection:terminate(Reason, StateName, State),
+ ensure_sender_terminate(Reason, State).
format_status(Type, Data) ->
ssl_connection:format_status(Type, Data).
@@ -638,11 +702,13 @@ code_change(_OldVsn, StateName, State, _) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
+initial_state(Role, Sender, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, User,
{CbModule, DataTag, CloseTag, ErrorTag}) ->
- #ssl_options{beast_mitigation = BeastMitigation} = SSLOptions,
+ #ssl_options{beast_mitigation = BeastMitigation,
+ erl_dist = IsErlDist} = SSLOptions,
ConnectionStates = tls_record:init_connection_states(Role, BeastMitigation),
+ ErlDistData = erl_dist_data(IsErlDist),
SessionCacheCb = case application:get_env(ssl, session_cb) of
{ok, Cb} when is_atom(Cb) ->
Cb;
@@ -650,7 +716,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
ssl_session_cache
end,
- Monitor = erlang:monitor(process, User),
+ UserMonitor = erlang:monitor(process, User),
#state{socket_options = SocketOptions,
ssl_options = SSLOptions,
@@ -663,9 +729,10 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
host = Host,
port = Port,
socket = Socket,
+ erl_dist_data = ErlDistData,
connection_states = ConnectionStates,
protocol_buffers = #protocol_buffers{},
- user_application = {Monitor, User},
+ user_application = {UserMonitor, User},
user_data_buffer = <<>>,
session_cache_cb = SessionCacheCb,
renegotiation = {false, first},
@@ -673,14 +740,42 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions, Tracker}, Us
start_or_recv_from = undefined,
protocol_cb = ?MODULE,
tracker = Tracker,
- flight_buffer = []
+ flight_buffer = [],
+ protocol_specific = #{sender => Sender}
}.
+erl_dist_data(true) ->
+ #{dist_handle => undefined,
+ dist_buffer => <<>>};
+erl_dist_data(false) ->
+ #{}.
+
+initialize_tls_sender(#state{role = Role,
+ socket = Socket,
+ socket_options = SockOpts,
+ tracker = Tracker,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ negotiated_version = Version,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt},
+ connection_states = #{current_write := ConnectionWriteState},
+ protocol_specific = #{sender := Sender}}) ->
+ Init = #{current_write => ConnectionWriteState,
+ role => Role,
+ socket => Socket,
+ socket_options => SockOpts,
+ tracker => Tracker,
+ protocol_cb => Connection,
+ transport_cb => Transport,
+ negotiated_version => Version,
+ renegotiate_at => RenegotiateAt},
+ tls_sender:initialize(Sender, Init).
+
next_tls_record(Data, StateName, #state{protocol_buffers =
#protocol_buffers{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = Buffers,
- ssl_options = SslOpts} = State0) ->
- case tls_record:get_tls_records(Data,
+ ssl_options = SslOpts} = State0) ->
+ case tls_record:get_tls_records(Data,
acceptable_record_versions(StateName, State0),
Buf0, SslOpts) of
{Records, Buf1} ->
@@ -693,10 +788,18 @@ next_tls_record(Data, StateName, #state{protocol_buffers =
end.
+%% TLS 1.3 Client/Server
+%% - Ignore TLSPlaintext.legacy_record_version
+%% - Verify that TLSCiphertext.legacy_record_version is set to 0x0303 for all records
+%% other than an initial ClientHello, where it MAY also be 0x0301.
acceptable_record_versions(hello, _) ->
- [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_AVAILABLE_VERSIONS];
+ [tls_record:protocol_version(Vsn) || Vsn <- ?ALL_TLS_RECORD_VERSIONS];
+acceptable_record_versions(_, #state{negotiated_version = {Major, Minor}})
+ when Major > 3; Major =:= 3, Minor >= 4 ->
+ [{3, 3}];
acceptable_record_versions(_, #state{negotiated_version = Version}) ->
[Version].
+
handle_record_alert(Alert, _) ->
Alert.
@@ -747,6 +850,9 @@ handle_info({CloseTag, Socket}, StateName,
%% and then receive the final message.
next_event(StateName, no_record, State)
end;
+handle_info({'EXIT', Sender, Reason}, _,
+ #state{protocol_specific = #{sender := Sender}} = State) ->
+ {stop, {shutdown, sender_died, Reason}, State};
handle_info(Msg, StateName, State) ->
ssl_connection:StateName(info, Msg, State, ?MODULE).
@@ -815,7 +921,8 @@ unprocessed_events(Events) ->
erlang:length(Events)-1.
-assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>, #ssl_options{max_handshake_size = Max}) when
+assert_buffer_sanity(<<?BYTE(_Type), ?UINT24(Length), Rest/binary>>,
+ #ssl_options{max_handshake_size = Max}) when
Length =< Max ->
case size(Rest) of
N when N < Length ->
@@ -835,3 +942,16 @@ assert_buffer_sanity(Bin, _) ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
malformed_handshake_data))
end.
+
+ensure_sender_terminate(downgrade, _) ->
+ ok; %% Do not terminate sender during downgrade phase
+ensure_sender_terminate(_, #state{protocol_specific = #{sender := Sender}}) ->
+ %% Make sure TLS sender dies when connection process is terminated normally
+ %% This is needed if the tls_sender is blocked in prim_inet:send
+ Kill = fun() ->
+ receive
+ after 5000 ->
+ catch (exit(Sender, kill))
+ end
+ end,
+ spawn(Kill).
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 4e6bbb5061..b39a7732e7 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -61,6 +61,18 @@ client_hello(Host, Port, ConnectionStates,
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
Version = tls_record:highest_protocol_version(Versions),
+
+ %% In TLS 1.3, the client indicates its version preferences in the
+ %% "supported_versions" extension (Section 4.2.1) and the
+ %% legacy_version field MUST be set to 0x0303, which is the version
+ %% number for TLS 1.2.
+ LegacyVersion =
+ case tls_record:is_higher(Version, {3,2}) of
+ true ->
+ {3,3};
+ false ->
+ Version
+ end,
#{security_parameters := SecParams} =
ssl_record:pending_connection_state(ConnectionStates, read),
AvailableCipherSuites = ssl_handshake:available_suites(UserSuites, Version),
@@ -71,7 +83,7 @@ client_hello(Host, Port, ConnectionStates,
CipherSuites = ssl_handshake:cipher_suites(AvailableCipherSuites, Renegotiation, Fallback),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
#client_hello{session_id = Id,
- client_version = Version,
+ client_version = LegacyVersion,
cipher_suites = CipherSuites,
compression_methods = ssl_record:compressions(),
random = SecParams#security_parameters.client_random,
@@ -82,17 +94,75 @@ client_hello(Host, Port, ConnectionStates,
-spec hello(#server_hello{} | #client_hello{}, #ssl_options{},
ssl_record:connection_states() | {inet:port_number(), #session{}, db_handle(),
atom(), ssl_record:connection_states(),
- binary() | undefined, ssl_cipher:key_algo()},
+ binary() | undefined, ssl_cipher_format:key_algo()},
boolean()) ->
{tls_record:tls_version(), session_id(),
ssl_record:connection_states(), alpn | npn, binary() | undefined}|
{tls_record:tls_version(), {resumed | new, #session{}},
ssl_record:connection_states(), binary() | undefined,
- #hello_extensions{}, {ssl_cipher:hash(), ssl_cipher:sign_algo()} |
+ HelloExt::map(), {ssl_cipher_format:hash(), ssl_cipher_format:sign_algo()} |
undefined} | #alert{}.
%%
%% Description: Handles a received hello message
%%--------------------------------------------------------------------
+
+
+%% TLS 1.3 - Section 4.1.3
+%% TLS 1.3 clients receiving a ServerHello indicating TLS 1.2 or below
+%% MUST check that the last eight bytes are not equal to either of these
+%% values.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor =:= 3 andalso %% Negotiating TLS 1.2
+ Down =:= ?RANDOM_OVERRIDE_TLS12) orelse
+
+ (M > 3 orelse M =:= 3 andalso N >= 4) andalso %% TLS 1.3 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+%% TLS 1.2 clients SHOULD also check that the last eight bytes are not
+%% equal to the second value if the ServerHello indicates TLS 1.1 or below.
+hello(#server_hello{server_version = {Major, Minor},
+ random = <<_:24/binary,Down:8/binary>>},
+ #ssl_options{versions = [{M,N}|_]}, _, _)
+ when (M =:= 3 andalso N =:= 3) andalso %% TLS 1.2 client
+ (Major =:= 3 andalso Minor < 3 andalso %% Negotiating TLS 1.1 or prior
+ Down =:= ?RANDOM_OVERRIDE_TLS11) ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+
+
+%% TLS 1.3 - 4.2.1. Supported Versions
+%% If the "supported_versions" extension in the ServerHello contains a
+%% version not offered by the client or contains a version prior to TLS
+%% 1.3, the client MUST abort the handshake with an "illegal_parameter"
+%% alert.
+%%--------------------------------------------------------------------
+%% TLS 1.2 Client
+%%
+%% - If "supported_version" is present (ServerHello):
+%% - Abort handshake with an "illegal_parameter" alert
+hello(#server_hello{server_version = Version,
+ extensions = #{server_hello_selected_version :=
+ #server_hello_selected_version{selected_version = Version}}
+ },
+ #ssl_options{versions = SupportedVersions},
+ _ConnectionStates0, _Renegotiation) ->
+ case tls_record:is_higher({3,4}, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
+ false ->
+ case tls_record:is_acceptable_version(Version, SupportedVersions) of
+ true ->
+ %% Implement TLS 1.3 statem ???
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+ false ->
+ ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)
+ end
+ end;
+
hello(#server_hello{server_version = Version, random = Random,
cipher_suite = CipherSuite,
compression_method = Compression,
@@ -107,6 +177,36 @@ hello(#server_hello{server_version = Version, random = Random,
false ->
?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
end;
+
+
+%% TLS 1.2 Server
+%% - If "supported_versions" is present (ClientHello):
+%% - Select version from "supported_versions" (ignore ClientHello.legacy_version)
+%% - If server only supports versions greater than "supported_versions":
+%% - Abort handshake with a "protocol_version" alert (*)
+%% - If "supported_versions" is absent (ClientHello):
+%% - Negotiate the minimum of ClientHello.legacy_version and TLS 1.2 (**)
+%% - If server only supports versions greater than ClientHello.legacy_version:
+%% - Abort handshake with a "protocol_version" alert
+%%
+%% (*) Sends alert even if there is a gap in supported versions
+%% e.g. Server 1.0,1.2 Client 1.1,1.3
+%% (**) Current implementation can negotiate a version not supported by the client
+%% e.g. Server 1.0,1.2 Client 1.1 -> ServerHello 1.0
+hello(#client_hello{client_version = _ClientVersion,
+ cipher_suites = CipherSuites,
+ extensions = #{client_hello_versions :=
+ #client_hello_versions{versions = ClientVersions}
+ }} = Hello,
+ #ssl_options{versions = Versions} = SslOpts,
+ Info, Renegotiation) ->
+ try
+ Version = ssl_handshake:select_supported_version(ClientVersions, Versions),
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
+ end;
hello(#client_hello{client_version = ClientVersion,
cipher_suites = CipherSuites} = Hello,
@@ -114,19 +214,11 @@ hello(#client_hello{client_version = ClientVersion,
Info, Renegotiation) ->
try
Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
- case ssl_cipher:is_fallback(CipherSuites) of
- true ->
- Highest = tls_record:highest_protocol_version(Versions),
- case tls_record:is_higher(Highest, Version) of
- true ->
- ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end;
- false ->
- handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
- end
+ do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation)
catch
+ error:{case_clause,{asn1, Asn1Reason}} ->
+ %% ASN-1 decode of certificate somehow failed
+ ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {failed_to_decode_own_certificate, Asn1Reason});
_:_ ->
?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, malformed_handshake_data)
end.
@@ -173,10 +265,7 @@ handle_client_hello(Version,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions =
- #hello_extensions{elliptic_curves = Curves,
- signature_algs = ClientHashSigns}
- = HelloExt},
+ extensions = HelloExt},
#ssl_options{versions = Versions,
signature_algs = SupportedHashSigns,
eccs = SupportedECCs,
@@ -185,6 +274,9 @@ handle_client_hello(Version,
Renegotiation) ->
case tls_record:is_acceptable_version(Version, Versions) of
true ->
+ Curves = maps:get(elliptic_curves, HelloExt, undefined),
+ ClientHashSigns = maps:get(signature_algs, HelloExt, undefined),
+ ClientSignatureSchemes = maps:get(signature_algs_cert, HelloExt, undefined),
AvailableHashSigns = ssl_handshake:available_signature_algs(
ClientHashSigns, SupportedHashSigns, Cert, Version),
ECCCurve = ssl_handshake:select_curve(Curves, SupportedECCs, ECCOrder),
@@ -197,9 +289,11 @@ handle_client_hello(Version,
no_suite ->
?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_ciphers);
_ ->
- #{key_exchange := KeyExAlg} = ssl_cipher:suite_definition(CipherSuite),
- case ssl_handshake:select_hashsign(ClientHashSigns, Cert, KeyExAlg,
- SupportedHashSigns, Version) of
+ #{key_exchange := KeyExAlg} = ssl_cipher_format:suite_definition(CipherSuite),
+ case ssl_handshake:select_hashsign({ClientHashSigns, ClientSignatureSchemes},
+ Cert, KeyExAlg,
+ SupportedHashSigns,
+ Version) of
#alert{} = Alert ->
Alert;
HashSign ->
@@ -242,8 +336,33 @@ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
{ConnectionStates, ProtoExt, Protocol} ->
{Version, SessionId, ConnectionStates, ProtoExt, Protocol}
end.
+
+
+do_hello(undefined, _Versions, _CipherSuites, _Hello, _SslOpts, _Info, _Renegotiation) ->
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION);
+do_hello(Version, Versions, CipherSuites, Hello, SslOpts, Info, Renegotiation) ->
+ case tls_record:is_higher({3,4}, Version) of
+ true -> %% TLS 1.2 and older
+ case ssl_cipher:is_fallback(CipherSuites) of
+ true ->
+ Highest = tls_record:highest_protocol_version(Versions),
+ case tls_record:is_higher(Highest, Version) of
+ true ->
+ ?ALERT_REC(?FATAL, ?INAPPROPRIATE_FALLBACK);
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ handle_client_hello(Version, Hello, SslOpts, Info, Renegotiation)
+ end;
+ false ->
+ %% Implement TLS 1.3 statem ???
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
+ end.
+
+
%%--------------------------------------------------------------------
-enc_handshake(#hello_request{}, _Version) ->
+enc_handshake(#hello_request{}, {3, N}) when N < 4 ->
{?HELLO_REQUEST, <<>>};
enc_handshake(#client_hello{client_version = {Major, Minor},
random = Random,
@@ -262,7 +381,8 @@ enc_handshake(#client_hello{client_version = {Major, Minor},
?BYTE(SIDLength), SessionID/binary,
?UINT16(CsLength), BinCipherSuites/binary,
?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
-
+enc_handshake(HandshakeMsg, {3, 4}) ->
+ tls_handshake_1_3:encode_handshake(HandshakeMsg);
enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
@@ -285,24 +405,25 @@ get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
get_tls_handshake_aux(_Version, Data, _, Acc) ->
{lists:reverse(Acc), Data}.
-decode_handshake(_, ?HELLO_REQUEST, <<>>) ->
+decode_handshake({3, N}, ?HELLO_REQUEST, <<>>) when N < 4 ->
#hello_request{};
-decode_handshake(_Version, ?CLIENT_HELLO,
+decode_handshake(Version, ?CLIENT_HELLO,
<<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
?BYTE(SID_length), Session_ID:SID_length/binary,
?UINT16(Cs_length), CipherSuites:Cs_length/binary,
?BYTE(Cm_length), Comp_methods:Cm_length/binary,
Extensions/binary>>) ->
- DecodedExtensions = ssl_handshake:decode_hello_extensions({client, Extensions}),
+ Exts = ssl_handshake:decode_vector(Extensions),
+ DecodedExtensions = ssl_handshake:decode_hello_extensions(Exts, Version, client),
#client_hello{
client_version = {Major,Minor},
random = Random,
session_id = Session_ID,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
- compression_methods = Comp_methods,
+ compression_methods = erlang:binary_to_list(Comp_methods),
extensions = DecodedExtensions
};
+decode_handshake({3, 4}, Tag, Msg) ->
+ tls_handshake_1_3:decode_handshake(Tag, Msg);
decode_handshake(Version, Tag, Msg) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
-
-
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
new file mode 100644
index 0000000000..199054b43b
--- /dev/null
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -0,0 +1,153 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Help funtions for handling the TLS 1.3 (specific parts of)
+%%% TLS handshake protocol
+%%----------------------------------------------------------------------
+
+-module(tls_handshake_1_3).
+
+-include("tls_handshake_1_3.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_internal.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Encode
+-export([encode_handshake/1, decode_handshake/2]).
+
+encode_handshake(#certificate_request_1_3{
+ certificate_request_context = Context,
+ extensions = Exts})->
+ EncContext = encode_cert_req_context(Context),
+ BinExts = encode_extensions(Exts),
+ {?CERTIFICATE_REQUEST, <<EncContext/binary, BinExts/binary>>};
+encode_handshake(#certificate_1_3{
+ certificate_request_context = Context,
+ entries = Entries}) ->
+ EncContext = encode_cert_req_context(Context),
+ EncEntries = encode_cert_entries(Entries),
+ {?CERTIFICATE, <<EncContext/binary, EncEntries/binary>>};
+encode_handshake(#encrypted_extensions{extensions = Exts})->
+ {?ENCRYPTED_EXTENSIONS, encode_extensions(Exts)};
+encode_handshake(#new_session_ticket{
+ ticket_lifetime = LifeTime,
+ ticket_age_add = Age,
+ ticket_nonce = Nonce,
+ ticket = Ticket,
+ extensions = Exts}) ->
+ TicketSize = byte_size(Ticket),
+ BinExts = encode_extensions(Exts),
+ {?NEW_SESSION_TICKET, <<?UINT32(LifeTime), ?UINT32(Age),
+ ?BYTE(Nonce), ?UINT16(TicketSize), Ticket/binary,
+ BinExts/binary>>};
+encode_handshake(#end_of_early_data{}) ->
+ {?END_OF_EARLY_DATA, <<>>};
+encode_handshake(#key_update{request_update = Update}) ->
+ {?KEY_UPDATE, <<?BYTE(Update)>>};
+encode_handshake(HandshakeMsg) ->
+ ssl_handshake:encode_handshake(HandshakeMsg, {3,4}).
+
+decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(0), ?UINT16(Size), EncExts:Size/binary>>) ->
+ Exts = decode_extensions(EncExts),
+ #certificate_request_1_3{
+ certificate_request_context = <<>>,
+ extensions = Exts};
+decode_handshake(?CERTIFICATE_REQUEST, <<?BYTE(CSize), Context:CSize/binary,
+ ?UINT16(Size), EncExts:Size/binary>>) ->
+ Exts = decode_extensions(EncExts),
+ #certificate_request_1_3{
+ certificate_request_context = Context,
+ extensions = Exts};
+decode_handshake(?CERTIFICATE, <<?BYTE(0), ?UINT24(Size), Certs:Size/binary>>) ->
+ CertList = decode_cert_entries(Certs),
+ #certificate_1_3{
+ certificate_request_context = <<>>,
+ entries = CertList
+ };
+decode_handshake(?CERTIFICATE, <<?BYTE(CSize), Context:CSize/binary,
+ ?UINT24(Size), Certs:Size/binary>>) ->
+ CertList = decode_cert_entries(Certs),
+ #certificate_1_3{
+ certificate_request_context = Context,
+ entries = CertList
+ };
+decode_handshake(?ENCRYPTED_EXTENSIONS, <<?UINT16(Size), EncExts:Size/binary>>) ->
+ #encrypted_extensions{
+ extensions = decode_extensions(EncExts)
+ };
+decode_handshake(?NEW_SESSION_TICKET, <<?UINT32(LifeTime), ?UINT32(Age),
+ ?BYTE(Nonce), ?UINT16(TicketSize), Ticket:TicketSize/binary,
+ BinExts/binary>>) ->
+ Exts = decode_extensions(BinExts),
+ #new_session_ticket{ticket_lifetime = LifeTime,
+ ticket_age_add = Age,
+ ticket_nonce = Nonce,
+ ticket = Ticket,
+ extensions = Exts};
+decode_handshake(?END_OF_EARLY_DATA, _) ->
+ #end_of_early_data{};
+decode_handshake(?KEY_UPDATE, <<?BYTE(Update)>>) ->
+ #key_update{request_update = Update};
+decode_handshake(Tag, HandshakeMsg) ->
+ ssl_handshake:decode_handshake({3,4}, Tag, HandshakeMsg).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+encode_cert_req_context(<<>>) ->
+ <<?BYTE(0)>>;
+encode_cert_req_context(Bin) ->
+ Size = byte_size(Bin),
+ <<?BYTE(Size), Bin/binary>>.
+
+encode_cert_entries(Entries) ->
+ CertEntryList = encode_cert_entries(Entries, []),
+ Size = byte_size(CertEntryList),
+ <<?UINT24(Size), CertEntryList/binary>>.
+
+encode_cert_entries([], Acc) ->
+ iolist_to_binary(lists:reverse(Acc));
+encode_cert_entries([#certificate_entry{data = Data,
+ extensions = Exts} | Rest], Acc) ->
+ DSize = byte_size(Data),
+ BinExts = encode_extensions(Exts),
+ ExtSize = byte_size(BinExts),
+ encode_cert_entries(Rest,
+ [<<?UINT24(DSize), Data/binary, ?UINT16(ExtSize), BinExts/binary>> | Acc]).
+
+decode_cert_entries(Entries) ->
+ decode_cert_entries(Entries, []).
+
+decode_cert_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_cert_entries(<<?UINT24(DSize), Data:DSize/binary, ?UINT16(Esize), BinExts:Esize/binary,
+ Rest/binary>>, Acc) ->
+ Exts = decode_extensions(BinExts),
+ decode_cert_entries(Rest, [#certificate_entry{data = Data,
+ extensions = Exts} | Acc]).
+
+encode_extensions(Exts)->
+ ssl_handshake:encode_extensions(extensions_list(Exts)).
+decode_extensions(Exts) ->
+ ssl_handshake:decode_extensions(Exts).
+
+extensions_list(HelloExtensions) ->
+ [Ext || {_, Ext} <- maps:to_list(HelloExtensions)].
diff --git a/lib/ssl/src/tls_handshake_1_3.hrl b/lib/ssl/src/tls_handshake_1_3.hrl
new file mode 100644
index 0000000000..9ee0e0f845
--- /dev/null
+++ b/lib/ssl/src/tls_handshake_1_3.hrl
@@ -0,0 +1,226 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-handshake protocol
+%% see RFC 8446. Also includes supported hello extensions.
+%%----------------------------------------------------------------------
+
+-ifndef(tls_handshake_1_3).
+-define(tls_handshake_1_3, true).
+
+%% Common to TLS-1.3 and previous TLS versions
+%% Some defenitions may not exist in TLS-1.3 this is
+%% handled elsewhere
+-include("tls_handshake.hrl").
+
+%% New handshake types in TLS-1.3 RFC 8446 B.3
+-define(NEW_SESSION_TICKET, 4).
+-define(END_OF_EARLY_DATA, 5).
+-define(ENCRYPTED_EXTENSIONS, 8).
+-define(KEY_UPDATE, 24).
+%% %% Not really a message but special way to handle handshake hashes
+%% %% when a "hello-retry-request" (special server_hello) is sent
+-define(MESSAGE_HASH, 254).
+
+%% %% RFC 8446 B.3.1.
+%% %% New extension types in TLS-1.3
+-define(PRE_SHARED_KEY_EXT, 41).
+-define(EARLY_DATA_EXT, 42).
+%%-define(SUPPORTED_VERSIONS_EXT, 43). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(COOKIE_EXT, 44).
+-define(PSK_KEY_EXCHANGE_MODES_EXT, 45).
+-define(CERTIFICATE_AUTHORITIES_EXT, 47).
+-define(OID_FILTERS_EXT, 48).
+-define(POST_HANDSHAKE_AUTH_EXT, 49).
+%% -define(SIGNATURE_ALGORITHMS_CERT_EXT, 50). %% Updates TLS 1.2 so defined in ssl_handshake.hrl
+-define(KEY_SHARE_EXT, 51).
+
+%% RFC 8446 B.3.1
+-record(key_share_entry, {
+ group, %NamedGroup
+ key_exchange %key_exchange<1..2^16-1>;
+ }).
+-record(key_share_client_hello, {
+ entries %% KeyShareEntry client_shares<0..2^16-1>;
+ }).
+-record(key_share_hello_retry_request, {
+ selected_group %% NamedGroup
+ }).
+-record(key_share_server_hello, {
+ server_share %% KeyShareEntry server_share;
+ }).
+
+-record(uncompressed_point_representation, {
+ legacy_form = 4, % uint8 legacy_form = 4;
+ x, % opaque X[coordinate_length];
+ y % opaque Y[coordinate_length];
+ }).
+
+-define(PSK_KE, 0).
+-define(PSK_DHE_KE, 1).
+
+-record(psk_keyexchange_modes, {
+ ke_modes % ke_modes<1..255>
+ }).
+-record(empty, {
+ }).
+-record(early_data_indication, {
+ indication % uint32 max_early_data_size (new_session_ticket) |
+ %% #empty{} (client_hello, encrypted_extensions)
+ }).
+-record(psk_identity, {
+ identity, % opaque identity<1..2^16-1>
+ obfuscated_ticket_age % uint32
+ }).
+-record(offered_psks, {
+ psk_identity, %identities<7..2^16-1>;
+ psk_binder_entry %binders<33..2^16-1>, opaque PskBinderEntry<32..255>
+ }).
+-record(pre_shared_keyextension,{
+ extension %OfferedPsks (client_hello) | uint16 selected_identity (server_hello)
+ }).
+
+%% RFC 8446 B.3.1.2.
+-record(cookie, {
+ cookie %cookie<1..2^16-1>;
+ }).
+
+%%% RFC 8446 B.3.1.3. Signature Algorithm Extension
+%% Signature Schemes
+%% RSASSA-PKCS1-v1_5 algorithms
+-define(RSA_PKCS1_SHA256, 16#0401).
+-define(RSA_PKCS1_SHA384, 16#0501).
+-define(RSA_PKCS1_SHA512, 16#0601).
+
+%% ECDSA algorithms
+-define(ECDSA_SECP256R1_SHA256, 16#0403).
+-define(ECDSA_SECP384R1_SHA384, 16#0503).
+-define(ECDSA_SECP521R1_SHA512, 16#0603).
+
+%% RSASSA-PSS algorithms with public key OID rsaEncryption
+-define(RSA_PSS_RSAE_SHA256, 16#0804).
+-define(RSA_PSS_RSAE_SHA384, 16#0805).
+-define(RSA_PSS_RSAE_SHA512, 16#0806).
+
+%% EdDSA algorithms
+-define(ED25519, 16#0807).
+-define(ED448, 16#0808).
+
+%% RSASSA-PSS algorithms with public key OID RSASSA-PSS
+-define(RSA_PSS_PSS_SHA256, 16#0809).
+-define(RSA_PSS_PSS_SHA384, 16#080a).
+-define(RSA_PSS_PSS_SHA512, 16#080b).
+
+%% Legacy algorithms
+-define(RSA_PKCS1_SHA1, 16#201).
+-define(ECDSA_SHA1, 16#0203).
+
+%% RFC 8446 B.3.1.4. Supported Groups Extension
+%% Elliptic Curve Groups (ECDHE)
+-define(SECP256R1, 16#0017).
+-define(SECP384R1, 16#0018).
+-define(SECP521R1, 16#0019).
+-define(X25519, 16#001D).
+-define(X448, 16#001E).
+
+%% RFC 8446 Finite Field Groups (DHE)
+-define(FFDHE2048, 16#0100).
+-define(FFDHE3072, 16#0101).
+-define(FFDHE4096, 16#0102).
+-define(FFDHE6144, 16#0103).
+-define(FFDHE8192 ,16#0104).
+
+-record(named_group_list, {
+ named_group_list %named_group_list<2..2^16-1>;
+ }).
+
+%% RFC 8446 B.3.2 Server Parameters Messages
+%% opaque DistinguishedName<1..2^16-1>;XS
+-record(certificate_authoritie_sextension, {
+ authorities %DistinguishedName authorities<3..2^16-1>;
+ }).
+
+-record(oid_filter, {
+ certificate_extension_oid, % opaque certificate_extension_oid<1..2^8-1>;
+ certificate_extension_values % opaque certificate_extension_values<0..2^16-1>;
+ }).
+
+-record(oid_filter_extension, {
+ filters %OIDFilter filters<0..2^16-1>;
+ }).
+-record(post_handshake_auth, {
+ }).
+
+-record(encrypted_extensions, {
+ extensions %extensions<0..2^16-1>;
+ }).
+
+-record(certificate_request_1_3, {
+ certificate_request_context, % opaque certificate_request_context<0..2^8-1>;
+ extensions %Extension extensions<2..2^16-1>;
+ }).
+
+%% RFC 8446 B.3.3 Authentication Messages
+
+%% Certificate Type
+-define(X509, 0).
+-define(OpenPGP_RESERVED, 1).
+-define(RawPublicKey, 2).
+
+-record(certificate_entry, {
+ data,
+ %% select (certificate_type) {
+ %% case RawPublicKey:
+ %% /* From RFC 7250 ASN.1_subjectPublicKeyInfo */
+ %% opaque ASN1_subjectPublicKeyInfo<1..2^24-1>;
+
+ %% case X509:
+ %% opaque cert_data<1..2^24-1>;
+ %% };
+ extensions %% Extension extensions<0..2^16-1>;
+ }).
+
+-record(certificate_1_3, {
+ certificate_request_context, % opaque certificate_request_context<0..2^8-1>;
+ entries % CertificateEntry certificate_list<0..2^24-1>;
+ }).
+
+%% RFC 8446 B.3.4. Ticket Establishment
+-record(new_session_ticket, {
+ ticket_lifetime, %unit32
+ ticket_age_add, %unit32
+ ticket_nonce, %opaque ticket_nonce<0..255>;
+ ticket, %opaque ticket<1..2^16-1>
+ extensions %extensions<0..2^16-2>
+ }).
+
+%% RFC 8446 B.3.5. Updating Keys
+-record(end_of_early_data, {
+ }).
+
+-define(UPDATE_NOT_REQUESTED, 0).
+-define(UPDATE_REQUESTED, 1).
+
+-record(key_update, {
+ request_update
+ }).
+
+-endif. % -ifdef(tls_handshake_1_3).
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 278d471fdb..7debac7d37 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -41,7 +41,7 @@
-export([encode_plain_text/4]).
%% Decoding
--export([decode_cipher_text/3]).
+-export([decode_cipher_text/4]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/1, lowest_protocol_version/2,
@@ -106,6 +106,8 @@ get_tls_records(Data, Versions, Buffer, SslOpts) ->
%
%% Description: Encodes a handshake message to send on the ssl-socket.
%%--------------------------------------------------------------------
+encode_handshake(Frag, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_handshake(Frag, ConnectionStates);
encode_handshake(Frag, Version,
#{current_write :=
#{beast_mitigation := BeastMitigation,
@@ -126,6 +128,8 @@ encode_handshake(Frag, Version,
%%
%% Description: Encodes an alert message to send on the ssl-socket.
%%--------------------------------------------------------------------
+encode_alert_record(Alert, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_handshake(Alert, ConnectionStates);
encode_alert_record(#alert{level = Level, description = Description},
Version, ConnectionStates) ->
encode_plain_text(?ALERT, Version, <<?BYTE(Level), ?BYTE(Description)>>,
@@ -146,6 +150,8 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
+encode_data(Data, {3, 4}, ConnectionStates) ->
+ tls_record_1_3:encode_data(Data, ConnectionStates);
encode_data(Frag, Version,
#{current_write := #{beast_mitigation := BeastMitigation,
security_parameters :=
@@ -159,12 +165,14 @@ encode_data(Frag, Version,
%%====================================================================
%%--------------------------------------------------------------------
--spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states(), boolean()) ->
+-spec decode_cipher_text(tls_version(), #ssl_tls{}, ssl_record:connection_states(), boolean()) ->
{#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
%%
%% Description: Decode cipher text
%%--------------------------------------------------------------------
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
+decode_cipher_text({3,4}, CipherTextRecord, ConnectionStates, _) ->
+ tls_record_1_3:decode_cipher_text(CipherTextRecord, ConnectionStates);
+decode_cipher_text(_, #ssl_tls{type = Type, version = Version,
fragment = CipherFragment} = CipherText,
#{current_read :=
#{compression_state := CompressionS0,
@@ -177,14 +185,15 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
BulkCipherAlgo,
compression_algorithm = CompAlg}
} = ReadState0} = ConnnectionStates0, _) ->
- AAD = calc_aad(Type, Version, ReadState0),
- case ssl_cipher:decipher_aead(BulkCipherAlgo, CipherS0, Seq, AAD, CipherFragment, Version) of
- {PlainFragment, CipherS1} ->
+ AAD = start_additional_data(Type, Version, ReadState0),
+ CipherS1 = ssl_record:nonce_seed(BulkCipherAlgo, <<?UINT64(Seq)>>, CipherS0),
+ case ssl_record:decipher_aead(BulkCipherAlgo, CipherS1, AAD, CipherFragment, Version) of
+ {PlainFragment, CipherState} ->
{Plain, CompressionS1} = ssl_record:uncompress(CompAlg,
PlainFragment, CompressionS0),
ConnnectionStates = ConnnectionStates0#{
current_read => ReadState0#{
- cipher_state => CipherS1,
+ cipher_state => CipherState,
sequence_number => Seq + 1,
compression_state => CompressionS1}},
{CipherText#ssl_tls{fragment = Plain}, ConnnectionStates};
@@ -192,7 +201,7 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
Alert
end;
-decode_cipher_text(#ssl_tls{type = Type, version = Version,
+decode_cipher_text(_, #ssl_tls{type = Type, version = Version,
fragment = CipherFragment} = CipherText,
#{current_read :=
#{compression_state := CompressionS0,
@@ -230,6 +239,8 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
%%--------------------------------------------------------------------
+protocol_version('tlsv1.3') ->
+ {3, 4};
protocol_version('tlsv1.2') ->
{3, 3};
protocol_version('tlsv1.1') ->
@@ -240,6 +251,8 @@ protocol_version(sslv3) ->
{3, 0};
protocol_version(sslv2) -> %% Backwards compatibility
{2, 0};
+protocol_version({3, 4}) ->
+ 'tlsv1.3';
protocol_version({3, 3}) ->
'tlsv1.2';
protocol_version({3, 2}) ->
@@ -482,15 +495,20 @@ encode_iolist(Type, Data, Version, ConnectionStates0) ->
{lists:reverse(EncodedMsg), ConnectionStates}.
%%--------------------------------------------------------------------
do_encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
- security_parameters :=
+ cipher_state := CipherS0,
+ sequence_number := Seq,
+ security_parameters :=
#security_parameters{
cipher_type = ?AEAD,
+ bulk_cipher_algorithm = BCAlg,
compression_algorithm = CompAlg}
} = WriteState0) ->
{Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
- WriteState1 = WriteState0#{compression_state => CompS1},
- AAD = calc_aad(Type, Version, WriteState1),
- ssl_record:cipher_aead(Version, Comp, WriteState1, AAD);
+ CipherS = ssl_record:nonce_seed(BCAlg, <<?UINT64(Seq)>>, CipherS0),
+ WriteState = WriteState0#{compression_state => CompS1,
+ cipher_state => CipherS},
+ AAD = start_additional_data(Type, Version, WriteState),
+ ssl_record:cipher_aead(Version, Comp, WriteState, AAD);
do_encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
security_parameters :=
#security_parameters{compression_algorithm = CompAlg}
@@ -502,7 +520,7 @@ do_encode_plain_text(Type, Version, Data, #{compression_state := CompS0,
do_encode_plain_text(_,_,_,CS) ->
exit({cs, CS}).
%%--------------------------------------------------------------------
-calc_aad(Type, {MajVer, MinVer},
+start_additional_data(Type, {MajVer, MinVer},
#{sequence_number := SeqNo}) ->
<<?UINT64(SeqNo), ?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer)>>.
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
new file mode 100644
index 0000000000..ff198a09bf
--- /dev/null
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -0,0 +1,260 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+
+-module(tls_record_1_3).
+
+-include("tls_record.hrl").
+-include("tls_record_1_3.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_cipher.hrl").
+
+%% Encoding
+-export([encode_handshake/2, encode_alert_record/2,
+ encode_data/2]).
+-export([encode_plain_text/3]).
+
+%% Decoding
+-export([decode_cipher_text/2]).
+
+%%====================================================================
+%% Encoding
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%
+%% Description: Encodes a handshake message to send on the tls-1.3-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, ConnectionStates) ->
+ case iolist_size(Frag) of
+ N when N > ?MAX_PLAIN_TEXT_LENGTH ->
+ %% TODO: Consider padding here
+ Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH),
+ encode_iolist(?HANDSHAKE, Data, ConnectionStates);
+ _ ->
+ encode_plain_text(?HANDSHAKE, Frag, ConnectionStates)
+ end.
+
+%%--------------------------------------------------------------------
+-spec encode_alert_record(#alert{}, ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes an alert message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_alert_record(#alert{level = Level, description = Description},
+ ConnectionStates) ->
+ encode_plain_text(?ALERT, <<?BYTE(Level), ?BYTE(Description)>>,
+ ConnectionStates).
+%%--------------------------------------------------------------------
+-spec encode_data(binary(), ssl_record:connection_states()) ->
+ {iolist(), ssl_record:connection_states()}.
+%%
+%% Description: Encodes data to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_data(Frag, ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, {3,4}),
+ encode_iolist(?APPLICATION_DATA, Data, ConnectionStates).
+
+encode_plain_text(Type, Data0, #{current_write := Write0} = ConnectionStates) ->
+ PadLen = 0, %% TODO where to specify PadLen?
+ Data = inner_plaintext(Type, Data0, PadLen),
+ {CipherFragment, Write1} = encode_plain_text(Data, Write0),
+ {CipherText, Write} = encode_tls_cipher_text(CipherFragment, Write1),
+ {CipherText, ConnectionStates#{current_write => Write}}.
+
+encode_iolist(Type, Data, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} =
+ encode_plain_text(Type, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
+%%====================================================================
+%% Decoding
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec decode_cipher_text(#ssl_tls{}, ssl_record:connection_states()) ->
+ {#ssl_tls{}, ssl_record:connection_states()}| #alert{}.
+%%
+%% Description: Decode cipher text, use legacy type ssl_tls instead of tls_cipher_text
+%% in decoding context so that we can reuse the code from erlier versions.
+%%--------------------------------------------------------------------
+decode_cipher_text(#ssl_tls{type = ?OPAQUE_TYPE,
+ version = ?LEGACY_VERSION,
+ fragment = CipherFragment},
+ #{current_read :=
+ #{sequence_number := Seq,
+ cipher_state := CipherS0,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD,
+ bulk_cipher_algorithm =
+ BulkCipherAlgo}
+ } = ReadState0} = ConnnectionStates0) ->
+ AAD = start_additional_data(),
+ CipherS1 = ssl_cipher:nonce_seed(<<?UINT64(Seq)>>, CipherS0),
+ case decipher_aead(BulkCipherAlgo, CipherS1, AAD, CipherFragment) of
+ {PlainFragment, CipherS1} ->
+ ConnnectionStates =
+ ConnnectionStates0#{current_read =>
+ ReadState0#{cipher_state => CipherS1,
+ sequence_number => Seq + 1}},
+ decode_inner_plaintext(PlainFragment, ConnnectionStates);
+ #alert{} = Alert ->
+ Alert
+ end;
+decode_cipher_text(#ssl_tls{type = Type}, _) ->
+ %% Version mismatch is already asserted
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, {record_typ_mismatch, Type}).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+split_bin(Bin, ChunkSize) ->
+ split_bin(Bin, ChunkSize, []).
+split_bin(Bin, ChunkSize, _) ->
+ do_split_bin(Bin, ChunkSize, []).
+
+do_split_bin(<<>>, _, Acc) ->
+ lists:reverse(Acc);
+do_split_bin(Bin, ChunkSize, Acc) ->
+ case Bin of
+ <<Chunk:ChunkSize/binary, Rest/binary>> ->
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ _ ->
+ lists:reverse(Acc, [Bin])
+ end.
+
+inner_plaintext(Type, Data, Length) ->
+ #inner_plaintext{
+ content = Data,
+ type = Type,
+ zeros = zero_padding(Length)
+ }.
+zero_padding(Length)->
+ binary:copy(<<?BYTE(0)>>, Length).
+
+encode_plain_text(#inner_plaintext{
+ content = Data,
+ type = Type,
+ zeros = Zeros
+ }, #{cipher_state := CipherS0,
+ sequence_number := Seq,
+ security_parameters :=
+ #security_parameters{
+ cipher_type = ?AEAD}
+ } = WriteState0) ->
+ PlainText = <<Data/binary, ?BYTE(Type), Zeros/binary>>,
+ AAD = start_additional_data(),
+ CipherS1 = ssl_cipher:nonce_seed(<<?UINT64(Seq)>>, CipherS0),
+ {Encoded, WriteState} = cipher_aead(PlainText, WriteState0#{cipher_state => CipherS1}, AAD),
+ {#tls_cipher_text{encoded_record = Encoded}, WriteState};
+encode_plain_text(_, CS) ->
+ exit({cs, CS}).
+
+start_additional_data() ->
+ {MajVer, MinVer} = ?LEGACY_VERSION,
+ <<?BYTE(?OPAQUE_TYPE), ?BYTE(MajVer), ?BYTE(MinVer)>>.
+
+end_additional_data(AAD, Len) ->
+ <<AAD/binary, ?UINT16(Len)>>.
+
+nonce(#cipher_state{nonce = Nonce, iv = IV}) ->
+ Len = size(IV),
+ crypto:exor(<<Nonce:Len/bytes>>, IV).
+
+cipher_aead(Fragment,
+ #{cipher_state := CipherS0,
+ security_parameters :=
+ #security_parameters{bulk_cipher_algorithm =
+ BulkCipherAlgo}
+ } = WriteState0, AAD) ->
+ {CipherFragment, CipherS1} =
+ cipher_aead(BulkCipherAlgo, CipherS0, AAD, Fragment),
+ {CipherFragment, WriteState0#{cipher_state => CipherS1}}.
+
+cipher_aead(Type, #cipher_state{key=Key} = CipherState, AAD0, Fragment) ->
+ AAD = end_additional_data(AAD0, erlang:iolist_size(Fragment)),
+ Nonce = nonce(CipherState),
+ {Content, CipherTag} = ssl_cipher:aead_encrypt(Type, Key, Nonce, Fragment, AAD),
+ {<<Content/binary, CipherTag/binary>>, CipherState}.
+
+encode_tls_cipher_text(#tls_cipher_text{opaque_type = Type,
+ legacy_version = {MajVer, MinVer},
+ encoded_record = Encoded}, #{sequence_number := Seq} = Write) ->
+ Length = erlang:iolist_size(Encoded),
+ {[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Encoded],
+ Write#{sequence_number => Seq +1}}.
+
+decipher_aead(Type, #cipher_state{key = Key} = CipherState, AAD0, CipherFragment) ->
+ try
+ Nonce = nonce(CipherState),
+ {AAD, CipherText, CipherTag} = aead_ciphertext_split(CipherState, CipherFragment, AAD0),
+ case ssl_cipher:aead_decrypt(Type, Key, Nonce, CipherText, CipherTag, AAD) of
+ Content when is_binary(Content) ->
+ {Content, CipherState};
+ _ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end
+ catch
+ _:_ ->
+ ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC, decryption_failed)
+ end.
+
+aead_ciphertext_split(#cipher_state{tag_len = Len}, CipherTextFragment, AAD) ->
+ CipherLen = size(CipherTextFragment) - Len,
+ <<CipherText:CipherLen/bytes, CipherTag:Len/bytes>> = CipherTextFragment,
+ {end_additional_data(AAD, CipherLen), CipherText, CipherTag}.
+
+decode_inner_plaintext(PlainText, ConnnectionStates) ->
+ case remove_padding(PlainText) of
+ #alert{} = Alert ->
+ Alert;
+ {Data, Type} ->
+ {#ssl_tls{type = Type,
+ version = {3,4}, %% Internally use real version
+ fragment = Data}, ConnnectionStates}
+ end.
+
+remove_padding(PlainText)->
+ case binary:split(PlainText, <<0>>, [global, trim]) of
+ [] ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, padding_error);
+ [Content] ->
+ Type = binary:last(Content),
+ split_content(Type, Content, erlang:byte_size(Content) - 1)
+ end.
+
+split_content(?HANDSHAKE, _, 0) ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, empty_handshake);
+split_content(?ALERT, _, 0) ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, empty_alert);
+%% For special middlebox compatible case!
+split_content(?CHANGE_CIPHER_SPEC, _, 0) ->
+ ?ALERT_REC(?FATAL, ?UNEXPECTED_MESSAGE, empty_change_cipher_spec);
+split_content(?APPLICATION_DATA = Type, _, 0) ->
+ {Type, <<>>};
+split_content(Type, Content, N) ->
+ <<Data:N/bytes, ?BYTE(Type)>> = Content,
+ {Type, Data}.
diff --git a/lib/ssl/src/tls_record_1_3.hrl b/lib/ssl/src/tls_record_1_3.hrl
new file mode 100644
index 0000000000..273427a34e
--- /dev/null
+++ b/lib/ssl/src/tls_record_1_3.hrl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Record and constant defenitions for the TLS-1.3-record protocol
+%% see RFC 8446 not present in earlier versions
+%%----------------------------------------------------------------------
+
+-ifndef(tls_record_1_3).
+-define(tls_record_1_3, true).
+
+%% enum {
+%% invalid(0),
+%% %% defined in ssl_record.hrl
+%% change_cipher_spec(20),
+%% alert(21),
+%% handshake(22),
+%% application_data(23),
+%% heartbeat(24), /* RFC 6520 */
+%% (255)
+%% } ContentType;
+
+-define(INVALID, 0).
+-define(LEGACY_VERSION, {3,3}).
+-define(OPAQUE_TYPE, 23).
+
+-record(inner_plaintext, {
+ content, %% data
+ type, %% Contentype
+ zeros %% padding "uint8 zeros[length_of_padding]"
+ }).
+-record(tls_cipher_text, { %% Equivalent of encrypted version of #ssl_tls from previous versions
+ %% decrypted version will still use #ssl_tls for code reuse purposes
+ %% with real values for content type and version
+ opaque_type = ?OPAQUE_TYPE,
+ legacy_version = ?LEGACY_VERSION,
+ encoded_record
+ }).
+
+-endif. % -ifdef(tls_record_1_3).
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
new file mode 100644
index 0000000000..1c3c44cfe5
--- /dev/null
+++ b/lib/ssl/src/tls_sender.erl
@@ -0,0 +1,432 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(tls_sender).
+
+-behaviour(gen_statem).
+
+-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
+-include("ssl_handshake.hrl").
+-include("ssl_api.hrl").
+
+%% API
+-export([start/0, start/1, initialize/2, send_data/2, send_alert/2,
+ send_and_ack_alert/2, setopts/2, renegotiate/1,
+ update_connection_state/3, dist_tls_socket/1, dist_handshake_complete/3]).
+
+%% gen_statem callbacks
+-export([callback_mode/0, init/1, terminate/3, code_change/4]).
+-export([init/3, connection/3, handshake/3, death_row/3]).
+
+-define(SERVER, ?MODULE).
+
+-record(data, {connection_pid,
+ connection_states = #{},
+ role,
+ socket,
+ socket_options,
+ tracker,
+ protocol_cb,
+ transport_cb,
+ negotiated_version,
+ renegotiate_at,
+ connection_monitor,
+ dist_handle
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+%%--------------------------------------------------------------------
+-spec start() -> {ok, Pid :: pid()} |
+ ignore |
+ {error, Error :: term()}.
+-spec start(list()) -> {ok, Pid :: pid()} |
+ ignore |
+ {error, Error :: term()}.
+
+%% Description: Start sender process to avoid dead lock that
+%% may happen when a socket is busy (busy port) and the
+%% same process is sending and receiving
+%%--------------------------------------------------------------------
+start() ->
+ gen_statem:start(?MODULE, [], []).
+start(SpawnOpts) ->
+ gen_statem:start(?MODULE, [], SpawnOpts).
+
+%%--------------------------------------------------------------------
+-spec initialize(pid(), map()) -> ok.
+%% Description: So TLS connection process can initialize it sender
+%% process.
+%%--------------------------------------------------------------------
+initialize(Pid, InitMsg) ->
+ gen_statem:call(Pid, {self(), InitMsg}).
+
+%%--------------------------------------------------------------------
+-spec send_data(pid(), iodata()) -> ok | {error, term()}.
+%% Description: Send application data
+%%--------------------------------------------------------------------
+send_data(Pid, AppData) ->
+ %% Needs error handling for external API
+ call(Pid, {application_data, AppData}).
+
+%%--------------------------------------------------------------------
+-spec send_alert(pid(), #alert{}) -> _.
+%% Description: TLS connection process wants to send an Alert
+%% in the connection state.
+%%--------------------------------------------------------------------
+send_alert(Pid, Alert) ->
+ gen_statem:cast(Pid, Alert).
+
+%%--------------------------------------------------------------------
+-spec send_and_ack_alert(pid(), #alert{}) -> _.
+%% Description: TLS connection process wants to send an Alert
+%% in the connection state and recive an ack.
+%%--------------------------------------------------------------------
+send_and_ack_alert(Pid, Alert) ->
+ gen_statem:cast(Pid, {ack_alert, Alert}).
+%%--------------------------------------------------------------------
+-spec setopts(pid(), [{packet, integer() | atom()}]) -> ok | {error, term()}.
+%% Description: Send application data
+%%--------------------------------------------------------------------
+setopts(Pid, Opts) ->
+ call(Pid, {set_opts, Opts}).
+
+%%--------------------------------------------------------------------
+-spec renegotiate(pid()) -> {ok, WriteState::map()} | {error, closed}.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when handshaking.
+%%--------------------------------------------------------------------
+renegotiate(Pid) ->
+ %% Needs error handling for external API
+ call(Pid, renegotiate).
+%%--------------------------------------------------------------------
+-spec update_connection_state(pid(), WriteState::map(), tls_record:tls_version()) -> ok.
+%% Description: So TLS connection process can synchronize the
+%% encryption state to be used when sending application data.
+%%--------------------------------------------------------------------
+update_connection_state(Pid, NewState, Version) ->
+ gen_statem:cast(Pid, {new_write, NewState, Version}).
+%%--------------------------------------------------------------------
+-spec dist_handshake_complete(pid(), node(), term()) -> ok.
+%% Description: Erlang distribution callback
+%%--------------------------------------------------------------------
+dist_handshake_complete(ConnectionPid, Node, DHandle) ->
+ gen_statem:call(ConnectionPid, {dist_handshake_complete, Node, DHandle}).
+%%--------------------------------------------------------------------
+-spec dist_tls_socket(pid()) -> {ok, #sslsocket{}}.
+%% Description: To enable distribution startup to get a proper "#sslsocket{}"
+%%--------------------------------------------------------------------
+dist_tls_socket(Pid) ->
+ gen_statem:call(Pid, dist_get_tls_socket).
+
+%%%===================================================================
+%%% gen_statem callbacks
+%%%===================================================================
+%%--------------------------------------------------------------------
+-spec callback_mode() -> gen_statem:callback_mode_result().
+%%--------------------------------------------------------------------
+callback_mode() ->
+ state_functions.
+
+%%--------------------------------------------------------------------
+-spec init(Args :: term()) ->
+ gen_statem:init_result(atom()).
+%%--------------------------------------------------------------------
+init(_) ->
+ %% Note: Should not trap exits so that this process
+ %% will be terminated if tls_connection process is
+ %% killed brutally
+ {ok, init, #data{}}.
+
+%%--------------------------------------------------------------------
+-spec init(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+init({call, From}, {Pid, #{current_write := WriteState,
+ role := Role,
+ socket := Socket,
+ socket_options := SockOpts,
+ tracker := Tracker,
+ protocol_cb := Connection,
+ transport_cb := Transport,
+ negotiated_version := Version,
+ renegotiate_at := RenegotiateAt}},
+ #data{connection_states = ConnectionStates} = StateData0) ->
+ Monitor = erlang:monitor(process, Pid),
+ StateData =
+ StateData0#data{connection_pid = Pid,
+ connection_monitor = Monitor,
+ connection_states =
+ ConnectionStates#{current_write => WriteState},
+ role = Role,
+ socket = Socket,
+ socket_options = SockOpts,
+ tracker = Tracker,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ negotiated_version = Version,
+ renegotiate_at = RenegotiateAt},
+ {next_state, handshake, StateData, [{reply, From, ok}]};
+init(info, Msg, StateData) ->
+ handle_info(Msg, ?FUNCTION_NAME, StateData).
+%%--------------------------------------------------------------------
+-spec connection(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+connection({call, From}, renegotiate,
+ #data{connection_states = #{current_write := Write}} = StateData) ->
+ {next_state, handshake, StateData, [{reply, From, {ok, Write}}]};
+connection({call, From}, {application_data, AppData},
+ #data{socket_options = SockOpts} = StateData) ->
+ case encode_packet(AppData, SockOpts) of
+ {error, _} = Error ->
+ {next_state, ?FUNCTION_NAME, StateData, [{reply, From, Error}]};
+ Data ->
+ send_application_data(Data, From, ?FUNCTION_NAME, StateData)
+ end;
+connection({call, From}, {set_opts, _} = Call, StateData) ->
+ handle_call(From, Call, ?FUNCTION_NAME, StateData);
+connection({call, From}, dist_get_tls_socket,
+ #data{protocol_cb = Connection,
+ transport_cb = Transport,
+ socket = Socket,
+ connection_pid = Pid,
+ tracker = Tracker} = StateData) ->
+ TLSSocket = Connection:socket([Pid, self()], Transport, Socket, Connection, Tracker),
+ {next_state, ?FUNCTION_NAME, StateData, [{reply, From, {ok, TLSSocket}}]};
+connection({call, From}, {dist_handshake_complete, _Node, DHandle}, #data{connection_pid = Pid} = StateData) ->
+ ok = erlang:dist_ctrl_input_handler(DHandle, Pid),
+ ok = ssl_connection:dist_handshake_complete(Pid, DHandle),
+ %% From now on we execute on normal priority
+ process_flag(priority, normal),
+ Events = dist_data_events(DHandle, []),
+ {next_state, ?FUNCTION_NAME, StateData#data{dist_handle = DHandle}, [{reply, From, ok} | Events]};
+connection(cast, {ack_alert, #alert{} = Alert}, #data{connection_pid = Pid} =StateData0) ->
+ StateData = send_tls_alert(Alert, StateData0),
+ Pid ! {self(), ack_alert},
+ {next_state, ?FUNCTION_NAME, StateData};
+connection(cast, #alert{} = Alert, StateData0) ->
+ StateData = send_tls_alert(Alert, StateData0),
+ {next_state, ?FUNCTION_NAME, StateData};
+connection(cast, {new_write, WritesState, Version},
+ #data{connection_states = ConnectionStates0} = StateData) ->
+ {next_state, connection,
+ StateData#data{connection_states =
+ ConnectionStates0#{current_write => WritesState},
+ negotiated_version = Version}};
+connection(info, dist_data, #data{dist_handle = DHandle} = StateData) ->
+ Events = dist_data_events(DHandle, []),
+ {next_state, ?FUNCTION_NAME, StateData, Events};
+connection(info, tick, StateData) ->
+ consume_ticks(),
+ {next_state, ?FUNCTION_NAME, StateData,
+ [{next_event, {call, {self(), undefined}},
+ {application_data, <<>>}}]};
+connection(info, {send, From, Ref, Data}, _StateData) ->
+ %% This is for testing only!
+ %%
+ %% Needed by some OTP distribution
+ %% test suites...
+ From ! {Ref, ok},
+ {keep_state_and_data,
+ [{next_event, {call, {self(), undefined}},
+ {application_data, iolist_to_binary(Data)}}]};
+connection(info, Msg, StateData) ->
+ handle_info(Msg, ?FUNCTION_NAME, StateData).
+%%--------------------------------------------------------------------
+-spec handshake(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+handshake({call, From}, {set_opts, _} = Call, StateData) ->
+ handle_call(From, Call, ?FUNCTION_NAME, StateData);
+handshake({call, _}, _, _) ->
+ {keep_state_and_data, [postpone]};
+handshake(cast, {new_write, WritesState, Version},
+ #data{connection_states = ConnectionStates0} = StateData) ->
+ {next_state, connection,
+ StateData#data{connection_states =
+ ConnectionStates0#{current_write => WritesState},
+ negotiated_version = Version}};
+handshake(info, Msg, StateData) ->
+ handle_info(Msg, ?FUNCTION_NAME, StateData).
+
+%%--------------------------------------------------------------------
+-spec death_row(gen_statem:event_type(),
+ Msg :: term(),
+ StateData :: term()) ->
+ gen_statem:event_handler_result(atom()).
+%%--------------------------------------------------------------------
+death_row(state_timeout, Reason, _State) ->
+ {stop, {shutdown, Reason}};
+death_row(_Type, _Msg, _State) ->
+ %% Waste all other events
+ keep_state_and_data.
+
+%%--------------------------------------------------------------------
+-spec terminate(Reason :: term(), State :: term(), Data :: term()) ->
+ any().
+%%--------------------------------------------------------------------
+terminate(_Reason, _State, _Data) ->
+ void.
+
+%%--------------------------------------------------------------------
+-spec code_change(
+ OldVsn :: term() | {down,term()},
+ State :: term(), Data :: term(), Extra :: term()) ->
+ {ok, NewState :: term(), NewData :: term()} |
+ (Reason :: term()).
+%% Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, Data, _Extra) ->
+ {ok, State, Data}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+handle_call(From, {set_opts, Opts}, StateName, #data{socket_options = SockOpts} = StateData) ->
+ {next_state, StateName, StateData#data{socket_options = set_opts(SockOpts, Opts)}, [{reply, From, ok}]}.
+
+handle_info({'DOWN', Monitor, _, _, Reason}, _,
+ #data{connection_monitor = Monitor,
+ dist_handle = Handle} = StateData) when Handle =/= undefined->
+ {next_state, death_row, StateData, [{state_timeout, 5000, Reason}]};
+handle_info({'DOWN', Monitor, _, _, _}, _,
+ #data{connection_monitor = Monitor} = StateData) ->
+ {stop, normal, StateData};
+handle_info(_,_,_) ->
+ {keep_state_and_data}.
+
+send_tls_alert(Alert, #data{negotiated_version = Version,
+ socket = Socket,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0} = StateData0) ->
+ {BinMsg, ConnectionStates} =
+ Connection:encode_alert(Alert, Version, ConnectionStates0),
+ Connection:send(Transport, Socket, BinMsg),
+ %% TODO: fix ssl_options for this process
+ %% Report = #{direction => outbound,
+ %% protocol => 'tls_record',
+ %% message => BinMsg},
+ %% ssl_logger:debug(SslOpts#ssl_options.log_level, Report, #{domain => [otp,ssl,tls_record]}),
+ StateData0#data{connection_states = ConnectionStates}.
+
+send_application_data(Data, From, StateName,
+ #data{connection_pid = Pid,
+ socket = Socket,
+ dist_handle = DistHandle,
+ negotiated_version = Version,
+ protocol_cb = Connection,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ renegotiate_at = RenegotiateAt} = StateData0) ->
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ ssl_connection:internal_renegotiation(Pid, ConnectionStates0),
+ {next_state, handshake, StateData0,
+ [{next_event, {call, From}, {application_data, Data}}]};
+ false ->
+ {Msgs, ConnectionStates} =
+ Connection:encode_data(Data, Version, ConnectionStates0),
+ StateData = StateData0#data{connection_states = ConnectionStates},
+ case Connection:send(Transport, Socket, Msgs) of
+ ok when DistHandle =/= undefined ->
+ {next_state, StateName, StateData, []};
+ Reason when DistHandle =/= undefined ->
+ {next_state, death_row, StateData, [{state_timeout, 5000, Reason}]};
+ ok ->
+ {next_state, StateName, StateData, [{reply, From, ok}]};
+ Result ->
+ {next_state, StateName, StateData, [{reply, From, Result}]}
+ end
+ end.
+
+encode_packet(Data, #socket_options{packet=Packet}) ->
+ case Packet of
+ 1 -> encode_size_packet(Data, 8, (1 bsl 8) - 1);
+ 2 -> encode_size_packet(Data, 16, (1 bsl 16) - 1);
+ 4 -> encode_size_packet(Data, 32, (1 bsl 32) - 1);
+ _ -> Data
+ end.
+
+encode_size_packet(Bin, Size, Max) ->
+ Len = erlang:byte_size(Bin),
+ case Len > Max of
+ true ->
+ {error, {badarg, {packet_to_large, Len, Max}}};
+ false ->
+ <<Len:Size, Bin/binary>>
+ end.
+
+set_opts(SocketOptions, [{packet, N}]) ->
+ SocketOptions#socket_options{packet = N}.
+
+time_to_renegotiate(_Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div
+ %% ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt), but we chose to
+ %% have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
+call(FsmPid, Event) ->
+ try gen_statem:call(FsmPid, Event)
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{{shutdown, _},_} ->
+ {error, closed}
+ end.
+
+%%---------------Erlang distribution --------------------------------------
+
+dist_data_events(DHandle, Events) ->
+ case erlang:dist_ctrl_get_data(DHandle) of
+ none ->
+ erlang:dist_ctrl_get_data_notification(DHandle),
+ lists:reverse(Events);
+ Data ->
+ Event = {next_event, {call, {self(), undefined}}, {application_data, Data}},
+ dist_data_events(DHandle, [Event | Events])
+ end.
+
+consume_ticks() ->
+ receive tick ->
+ consume_ticks()
+ after 0 ->
+ ok
+ end.
diff --git a/lib/ssl/src/tls_socket.erl b/lib/ssl/src/tls_socket.erl
index 154281f1c2..a391bc53de 100644
--- a/lib/ssl/src/tls_socket.erl
+++ b/lib/ssl/src/tls_socket.erl
@@ -64,11 +64,12 @@ accept(ListenSocket, #config{transport_info = {Transport,_,_,_} = CbInfo,
{ok, Socket} ->
{ok, EmOpts} = get_emulated_opts(Tracker),
{ok, Port} = tls_socket:port(Transport, Socket),
- ConnArgs = [server, "localhost", Port, Socket,
+ {ok, Sender} = tls_sender:start(),
+ ConnArgs = [server, Sender, "localhost", Port, Socket,
{SslOpts, emulated_socket_options(EmOpts, #socket_options{}), Tracker}, self(), CbInfo],
case tls_connection_sup:start_child(ConnArgs) of
{ok, Pid} ->
- ssl_connection:socket_control(ConnectionCb, Socket, Pid, Transport, Tracker);
+ ssl_connection:socket_control(ConnectionCb, Socket, [Pid, Sender], Transport, Tracker);
{error, Reason} ->
{error, Reason}
end;
@@ -112,8 +113,8 @@ connect(Address, Port,
{error, {options, {socket_options, UserOpts}}}
end.
-socket(Pid, Transport, Socket, ConnectionCb, Tracker) ->
- #sslsocket{pid = Pid,
+socket(Pids, Transport, Socket, ConnectionCb, Tracker) ->
+ #sslsocket{pid = Pids,
%% "The name "fd" is keept for backwards compatibility
fd = {Transport, Socket, ConnectionCb, Tracker}}.
setopts(gen_tcp, #sslsocket{pid = {ListenSocket, #config{emulated = Tracker}}}, Options) ->
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index d6b500748e..7d28962d2d 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -32,7 +32,8 @@
-export([master_secret/4, finished/5, certificate_verify/3, mac_hash/7, hmac_hash/3,
setup_keys/8, suites/1, prf/5,
ecc_curves/1, ecc_curves/2, oid_to_enum/1, enum_to_oid/1,
- default_signature_algs/1, signature_algs/2]).
+ default_signature_algs/1, signature_algs/2,
+ default_signature_schemes/1, signature_schemes/2]).
-type named_curve() :: sect571r1 | sect571k1 | secp521r1 | brainpoolP512r1 |
sect409k1 | sect409r1 | brainpoolP384r1 | secp384r1 |
@@ -74,7 +75,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
prf(?MD5SHA, MasterSecret, finished_label(Role), [MD5, SHA], 12);
finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
- when Version == 3 ->
+ when Version == 3; Version == 4 ->
%% RFC 5246 - 7.4.9. Finished
%% struct {
%% opaque verify_data[12];
@@ -85,6 +86,7 @@ finished(Role, Version, PrfAlgo, MasterSecret, Handshake)
Hash = crypto:hash(mac_algo(PrfAlgo), Handshake),
prf(PrfAlgo, MasterSecret, finished_label(Role), Hash, 12).
+
-spec certificate_verify(md5sha | sha, integer(), [binary()]) -> binary().
certificate_verify(md5sha, _Version, Handshake) ->
@@ -154,7 +156,7 @@ setup_keys(Version, _PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize
%% TLS v1.2
setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
KeyMatLen, IVSize)
- when Version == 3 ->
+ when Version == 3; Version == 4 ->
%% RFC 5246 - 6.3. Key calculation
%% key_block = PRF(SecurityParameters.master_secret,
%% "key expansion",
@@ -192,7 +194,7 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Fragment]),
Mac.
--spec suites(1|2|3) -> [ssl_cipher:cipher_suite()].
+-spec suites(1|2|3|4) -> [ssl_cipher_format:cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2 ->
[
@@ -244,8 +246,19 @@ suites(3) ->
%% ?TLS_DH_DSS_WITH_AES_256_GCM_SHA384,
%% ?TLS_DH_RSA_WITH_AES_128_GCM_SHA256,
%% ?TLS_DH_DSS_WITH_AES_128_GCM_SHA256
- ] ++ suites(2).
-
+ ] ++ suites(2);
+
+suites(4) ->
+ [?TLS_AES_256_GCM_SHA384,
+ ?TLS_AES_128_GCM_SHA256,
+ ?TLS_CHACHA20_POLY1305_SHA256
+ %% Not supported
+ %% ?TLS_AES_128_CCM_SHA256,
+ %% ?TLS_AES_128_CCM_8_SHA256
+ ] ++ suites(3).
+
+signature_algs({3, 4}, HashSigns) ->
+ signature_algs({3, 3}, HashSigns);
signature_algs({3, 3}, HashSigns) ->
CryptoSupports = crypto:supports(),
Hashes = proplists:get_value(hashs, CryptoSupports),
@@ -273,6 +286,8 @@ signature_algs({3, 3}, HashSigns) ->
end, [], HashSigns),
lists:reverse(Supported).
+default_signature_algs({3, 4}) ->
+ default_signature_algs({3, 3});
default_signature_algs({3, 3} = Version) ->
Default = [%% SHA2
{sha512, ecdsa},
@@ -291,6 +306,64 @@ default_signature_algs({3, 3} = Version) ->
default_signature_algs(_) ->
undefined.
+
+signature_schemes(Version, SignatureSchemes) when is_tuple(Version)
+ andalso Version >= {3, 3} ->
+ CryptoSupports = crypto:supports(),
+ Hashes = proplists:get_value(hashs, CryptoSupports),
+ PubKeys = proplists:get_value(public_keys, CryptoSupports),
+ Curves = proplists:get_value(curves, CryptoSupports),
+ Fun = fun (Scheme, Acc) ->
+ {Hash0, Sign0, Curve} =
+ ssl_cipher:scheme_to_components(Scheme),
+ Sign = case Sign0 of
+ rsa_pkcs1 -> rsa;
+ S -> S
+ end,
+ Hash = case Hash0 of
+ sha1 -> sha;
+ H -> H
+ end,
+ case proplists:get_bool(Sign, PubKeys)
+ andalso proplists:get_bool(Hash, Hashes)
+ andalso (Curve =:= undefined orelse
+ proplists:get_bool(Curve, Curves))
+ andalso is_pair(Hash, Sign, Hashes)
+ of
+ true ->
+ [Scheme | Acc];
+ false ->
+ Acc
+ end
+ end,
+ Supported = lists:foldl(Fun, [], SignatureSchemes),
+ lists:reverse(Supported);
+signature_schemes(_, _) ->
+ [].
+
+
+default_signature_schemes(Version) ->
+ Default = [
+ rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ %% ed25519,
+ %% ed448,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1
+ ],
+ signature_schemes(Version, Default).
+
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 9dfb2eba53..d5ba105478 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -61,6 +61,7 @@ MODULES = \
ssl_ECC\
ssl_upgrade_SUITE\
ssl_sni_SUITE \
+ ssl_eqc_SUITE \
make_certs\
x509_test
@@ -144,7 +145,7 @@ release_tests_spec: opt
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(HRL_FILES_NEEDED_IN_TEST) $(COVER_FILE) "$(RELSYSDIR)"
$(INSTALL_DATA) ssl.spec ssl_bench.spec ssl.cover "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 8fe7c54549..578f6a731a 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -365,7 +365,7 @@ req_cnf(Root, C) ->
"default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -415,7 +415,7 @@ ca_cnf(
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -499,7 +499,7 @@ ca_cnf(
["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = md5\n"
+ "default_md = sha1\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
new file mode 100644
index 0000000000..99c6554f15
--- /dev/null
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -0,0 +1,534 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2018-2018. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssl_eqc_handshake).
+
+-compile(export_all).
+
+-proptest(eqc).
+-proptest([triq,proper]).
+
+-ifndef(EQC).
+-ifndef(PROPER).
+-ifndef(TRIQ).
+-define(EQC,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(EQC).
+-include_lib("eqc/include/eqc.hrl").
+-define(MOD_eqc,eqc).
+
+-else.
+-ifdef(PROPER).
+-include_lib("proper/include/proper.hrl").
+-define(MOD_eqc,proper).
+
+-else.
+-ifdef(TRIQ).
+-define(MOD_eqc,triq).
+-include_lib("triq/include/triq.hrl").
+
+-endif.
+-endif.
+-endif.
+
+-include_lib("kernel/include/inet.hrl").
+-include_lib("ssl/src/tls_handshake_1_3.hrl").
+-include_lib("ssl/src/tls_handshake.hrl").
+-include_lib("ssl/src/ssl_handshake.hrl").
+-include_lib("ssl/src/ssl_alert.hrl").
+-include_lib("ssl/src/ssl_internal.hrl").
+
+-define('TLS_v1.3', {3,4}).
+-define('TLS_v1.2', {3,3}).
+-define('TLS_v1.1', {3,2}).
+-define('TLS_v1', {3,1}).
+-define('SSL_v3', {3,0}).
+
+%%--------------------------------------------------------------------
+%% Properties --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+prop_tls_hs_encode_decode() ->
+ ?FORALL({Handshake, TLSVersion}, ?LET(Version, tls_version(), {tls_msg(Version), Version}),
+ try
+ [Type, _Length, Data] = tls_handshake:encode_handshake(Handshake, TLSVersion),
+ case tls_handshake:decode_handshake(TLSVersion, Type, Data) of
+ Handshake ->
+ true;
+ _ ->
+ false
+ end
+ catch
+ throw:#alert{} ->
+ true
+ end
+ ).
+
+%%--------------------------------------------------------------------
+%% Message Generators --------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_version() ->
+ oneof([?'TLS_v1.3', ?'TLS_v1.2', ?'TLS_v1.1', ?'TLS_v1', ?'SSL_v3']).
+
+tls_msg(?'TLS_v1.3'= Version) ->
+ oneof([client_hello(Version),
+ server_hello(Version),
+ %%new_session_ticket()
+ #end_of_early_data{},
+ encrypted_extensions(),
+ certificate_1_3(),
+ %%certificate_request_1_3,
+ %%certificate_verify()
+ finished(),
+ key_update()
+ ]);
+tls_msg(Version) ->
+ oneof([#hello_request{},
+ client_hello(Version),
+ server_hello(Version),
+ certificate(),
+ %%server_key_exchange()
+ certificate_request(Version),
+ #server_hello_done{},
+ %%certificate_verify()
+ %%client_key_exchange()
+ finished()
+ ]).
+
+client_hello(?'TLS_v1.3' = Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = ?'TLS_v1.2',
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ };
+client_hello(Version) ->
+ #client_hello{session_id = session_id(),
+ client_version = Version,
+ cipher_suites = cipher_suites(Version),
+ compression_methods = compressions(Version),
+ random = client_random(Version),
+ extensions = client_hello_extensions(Version)
+ }.
+
+server_hello(?'TLS_v1.3' = Version) ->
+ #server_hello{server_version = ?'TLS_v1.2',
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ };
+server_hello(Version) ->
+ #server_hello{server_version = Version,
+ session_id = session_id(),
+ random = server_random(Version),
+ cipher_suite = cipher_suite(Version),
+ compression_method = compression(Version),
+ extensions = server_hello_extensions(Version)
+ }.
+
+encrypted_extensions() ->
+ ?LET(Exts, extensions(?'TLS_v1.3'),
+ #encrypted_extensions{extensions = Exts}).
+
+certificate() ->
+ #certificate{
+ asn1_certificates = certificate_chain()
+ }.
+
+certificate_1_3() ->
+ ?LET(Certs, certificate_chain(),
+ #certificate_1_3{
+ certificate_request_context = certificate_request_context(),
+ entries = certificate_entries(Certs, [])
+ }).
+
+key_update() ->
+ #key_update{request_update = request_update()}.
+
+finished() ->
+ ?LET(Size, digest_size(),
+ #finished{verify_data = crypto:strong_rand_bytes(Size)}).
+
+%%--------------------------------------------------------------------
+%% Messge Data Generators -------------------------------------------
+%%--------------------------------------------------------------------
+
+
+cipher_suite(Version) ->
+ oneof(cipher_suites(Version)).
+
+cipher_suites(Version) ->
+ ssl_cipher:suites(Version).
+
+session_id() ->
+ crypto:strong_rand_bytes(?NUM_OF_SESSION_ID_BYTES).
+
+compression(Version) ->
+ oneof(compressions(Version)).
+
+compressions(_) ->
+ ssl_record:compressions().
+
+client_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+server_random(_) ->
+ crypto:strong_rand_bytes(32).
+
+
+client_hello_extensions(?'TLS_v1.3' = Version) ->
+ ?LET({Versions, Ext}, {supported_versions(Version), c_hello_extensions(Version)},
+ maps:merge(Ext, #{client_hello_versions => client_hello_versions(Versions)})
+ );
+client_hello_extensions(?'TLS_v1.2' = Version) ->
+ ?LET({Versions, Exts}, {supported_versions(Version), c_hello_extensions(Version)},
+ maps:merge(Exts, #{client_hello_versions => client_hello_versions(Versions)})
+ );
+client_hello_extensions(Version) ->
+ ?LET(Exts,
+ c_hello_extensions(Version),
+ maps:merge(empty_hello_extensions(Version, client), Exts)).
+
+server_hello_extensions(?'TLS_v1.3' = Version) ->
+ ?LET(Exts,
+ s_hello_extensions(Version),
+ maps:merge(Exts, #{server_hello_selected_version => server_hello_selected_version(Version)}));
+server_hello_extensions(Version) ->
+ ?LET(Exts,
+ s_hello_extensions(Version),
+ Exts).
+
+c_hello_extensions(?'TLS_v1.3'= Version) ->
+ ?LET({KeyShare, PreShare}, {key_share_client_hello(),
+ pre_shared_keyextension()},
+ maps:merge(empty_hello_extensions(Version, client),
+ #{key_share => KeyShare,
+ pre_shared_key => PreShare
+ })
+ );
+c_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version),
+ maps:merge(empty_hello_extensions(Version, client),
+ Exts)).
+
+s_hello_extensions(?'TLS_v1.3'= Version) ->
+ ?LET({KeyShare, PreShare}, {key_share_server_hello(),
+ pre_shared_keyextension()},
+ maps:merge(empty_hello_extensions(Version, server),
+ #{key_share => KeyShare,
+ pre_shared_key => PreShare
+ })
+ );
+s_hello_extensions(Version) ->
+ ?LET(Exts, extensions(Version),
+ maps:merge(empty_hello_extensions(Version, server),
+ Exts)).
+
+key_share_client_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_client_hello{}, undefined]).
+
+key_share_server_hello() ->
+ oneof([undefined]).
+ %%oneof([#key_share_server_hello{}, undefined]).
+
+pre_shared_keyextension() ->
+ oneof([undefined]).
+ %%oneof([#pre_shared_keyextension{},undefined]).
+
+extensions(?'TLS_v1.3') ->
+ ?LET({Ext_1_3, Exts}, {extensions_1_3(), extensions(?'TLS_v1.2')}, maps:merge(Ext_1_3, Exts));
+extensions(?'SSL_v3') ->
+ #{};
+extensions(Version) ->
+ ?LET({SNI, ECPoitF, ECCurves, ALPN, NextP, SRP},
+ {oneof([sni(), undefined]),
+ oneof([ec_poit_formats(), undefined]),
+ oneof([elliptic_curves(Version), undefined]),
+ oneof([alpn(), undefined]),
+ oneof([next_protocol_negotiation(), undefined]),
+ oneof([srp(), undefined])},
+ maps:filter(fun(_, undefined) ->
+ false;
+ (_,_) ->
+ true
+ end,
+ #{sni => SNI,
+ ec_point_formats => ECPoitF,
+ elliptic_curves => ECCurves,
+ alpn => ALPN,
+ next_protocol_negotiation => NextP,
+ srp => SRP})).
+
+extensions_1_3() ->
+ %% ?LET(Entry, key_share_entry(),
+ %% maps:filter(fun(_, undefined) ->
+ %% false;
+ %% (_,_) ->
+ %% true
+ %% end, #{key_share_entry => Entry})).
+ ?LET({HashSign, SigAlgCert}, {oneof([hash_sign_algos(?'TLS_v1.2')]), oneof([signature_scheme_list()])},
+ #{signature_algs => HashSign,
+ signature_algs_cert => SigAlgCert}).
+
+empty_hello_extensions({3, 4}, server) ->
+ #{server_hello_selected_version => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined,
+ sni => undefined
+ };
+empty_hello_extensions({3, 4}, client) ->
+ #{client_hello_versions => undefined,
+ signature_algs => undefined,
+ signature_algs_cert => undefined,
+ sni => undefined,
+ alpn => undefined,
+ key_share => undefined,
+ pre_shared_key => undefined
+ };
+empty_hello_extensions({3, 3}, client) ->
+ Ext = empty_hello_extensions({3,2}, client),
+ Ext#{client_hello_versions => undefined,
+ signature_algs => undefined,
+ signature_algs_cert => undefined};
+empty_hello_extensions(_, client) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ srp => undefined,
+ ec_point_formats => undefined,
+ elliptic_curves => undefined,
+ sni => undefined};
+empty_hello_extensions(_, server) ->
+ #{renegotiation_info => undefined,
+ alpn => undefined,
+ next_protocol_negotiation => undefined,
+ ec_point_formats => undefined,
+ sni => undefined}.
+
+signature_algs_cert() ->
+ ?LET(Algs, signature_scheme_list(),
+ Algs).
+
+signature_scheme_list() ->
+ ?LET(List, sig_scheme_list(),
+ #signature_scheme_list{signature_scheme_list = List}).
+
+sig_scheme_list() ->
+ oneof([[rsa_pkcs1_sha256],
+ [rsa_pkcs1_sha256, ecdsa_sha1],
+ [rsa_pkcs1_sha256,
+ rsa_pkcs1_sha384,
+ rsa_pkcs1_sha512,
+ ecdsa_secp256r1_sha256,
+ ecdsa_secp384r1_sha384,
+ ecdsa_secp521r1_sha512,
+ rsa_pss_rsae_sha256,
+ rsa_pss_rsae_sha384,
+ rsa_pss_rsae_sha512,
+ rsa_pss_pss_sha256,
+ rsa_pss_pss_sha384,
+ rsa_pss_pss_sha512,
+ rsa_pkcs1_sha1,
+ ecdsa_sha1]
+ ]).
+
+supported_versions(?'TLS_v1.3') ->
+ oneof([[{3,4}],
+ [{3,3},{3,4}],
+ [{3,4},{3,3},{3,2},{3,1},{3,0}]
+ ]);
+supported_versions(_) ->
+ oneof([[{3,3}],
+ [{3,3},{3,2}],
+ [{3,3},{3,2},{3,1},{3,0}]
+ ]).
+
+request_update() ->
+ oneof([?UPDATE_NOT_REQUESTED, ?UPDATE_REQUESTED]).
+
+certificate_chain()->
+ Conf = cert_conf(),
+ ?LET(Chain,
+ choose_certificate_chain(Conf),
+ Chain).
+
+choose_certificate_chain(#{server_config := ServerConf,
+ client_config := ClientConf}) ->
+ oneof([certificate_chain(ServerConf), certificate_chain(ClientConf)]).
+
+certificate_request_context() ->
+ <<>>.
+certificate_entries([], Acc) ->
+ lists:reverse(Acc);
+certificate_entries([Cert | Rest], Acc) ->
+ certificate_entries(Rest, [certificate_entry(Cert) | Acc]).
+
+certificate_entry(Cert) ->
+ #certificate_entry{data = Cert,
+ extensions = certificate_entry_extensions()
+ }.
+certificate_entry_extensions() ->
+ #{}.
+
+certificate_chain(Conf) ->
+ CAs = proplists:get_value(cacerts, Conf),
+ Cert = proplists:get_value(cert, Conf),
+ %% Middle argument are of correct type but will not be used
+ {ok, _, Chain} = ssl_certificate:certificate_chain(Cert, ets:new(foo, []), make_ref(), CAs),
+ Chain.
+
+cert_conf()->
+ Hostname = net_adm:localhost(),
+ {ok, #hostent{h_addr_list = [_IP |_]}} = inet:gethostbyname(net_adm:localhost()),
+ public_key:pkix_test_data(#{server_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(1)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(2)}]],
+ peer => [{extensions, [#'Extension'{extnID =
+ ?'id-ce-subjectAltName',
+ extnValue = [{dNSName, Hostname}],
+ critical = false}]},
+ {key, ssl_test_lib:hardcode_rsa_key(3)}
+ ]},
+ client_chain =>
+ #{root => [{key, ssl_test_lib:hardcode_rsa_key(4)}],
+ intermediates => [[{key, ssl_test_lib:hardcode_rsa_key(5)}]],
+ peer => [{key, ssl_test_lib:hardcode_rsa_key(6)}]}}).
+
+certificate_request(Version) ->
+ #certificate_request{certificate_types = certificate_types(Version),
+ hashsign_algorithms = hashsign_algorithms(Version),
+ certificate_authorities = certificate_authorities()}.
+
+certificate_types(?'TLS_v1.3') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>]);
+certificate_types(?'TLS_v1.2') ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]);
+certificate_types(_) ->
+ iolist_to_binary([<<?BYTE(?ECDSA_SIGN)>>, <<?BYTE(?RSA_SIGN)>>, <<?BYTE(?DSS_SIGN)>>]).
+
+hashsign_algorithms({_, N} = Version) when N >= 3 ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)};
+hashsign_algorithms(_) ->
+ undefined.
+
+hash_alg_list(Version) ->
+ ?LET(NumOf, choose(0,15),
+ ?LET(List, [hash_alg(Version) || _ <- lists:seq(1,NumOf)],
+ lists:usort(List)
+ )).
+
+hash_alg(Version) ->
+ ?LET(Alg, sign_algorithm(Version),
+ {hash_algorithm(Version, Alg), Alg}
+ ).
+
+hash_algorithm(?'TLS_v1.3', _) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(?'TLS_v1.2', rsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, rsa) ->
+ oneof([md5, sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, ecdsa) ->
+ oneof([sha, sha224, sha256, sha384, sha512]);
+hash_algorithm(_, dsa) ->
+ sha.
+
+sign_algorithm(?'TLS_v1.3') ->
+ oneof([rsa, ecdsa]);
+sign_algorithm(_) ->
+ oneof([rsa, dsa, ecdsa]).
+
+certificate_authorities() ->
+ #{server_config := ServerConf} = cert_conf(),
+ Authorities = proplists:get_value(cacerts, ServerConf),
+ Enc = fun(#'OTPCertificate'{tbsCertificate=TBSCert}) ->
+ OTPSubj = TBSCert#'OTPTBSCertificate'.subject,
+ DNEncodedBin = public_key:pkix_encode('Name', OTPSubj, otp),
+ DNEncodedLen = byte_size(DNEncodedBin),
+ <<?UINT16(DNEncodedLen), DNEncodedBin/binary>>
+ end,
+ list_to_binary([Enc(public_key:pkix_decode_cert(DERCert, otp)) || DERCert <- Authorities]).
+
+digest_size()->
+ oneof([160,224,256,384,512]).
+
+key_share_entry() ->
+ undefined.
+ %%#key_share_entry{}.
+
+client_hello_versions(Versions) ->
+ #client_hello_versions{versions = Versions}.
+
+server_hello_selected_version(Version) ->
+ #server_hello_selected_version{selected_version = Version}.
+
+sni() ->
+ #sni{hostname = net_adm:localhost()}.
+
+ec_poit_formats() ->
+ #ec_point_formats{ec_point_format_list = ec_point_format_list()}.
+
+ec_point_format_list() ->
+ [?ECPOINT_UNCOMPRESSED].
+
+elliptic_curves({_, Minor}) ->
+ Curves = tls_v1:ecc_curves(Minor),
+ #elliptic_curves{elliptic_curve_list = Curves}.
+
+hash_sign_algos(Version) ->
+ #hash_sign_algos{hash_sign_algos = hash_alg_list(Version)}.
+
+alpn() ->
+ ?LET(ExtD, alpn_protocols(), #alpn{extension_data = ExtD}).
+
+alpn_protocols() ->
+ oneof([<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>, <<"http/1.0">>, <<"http/1.1">>]).
+
+next_protocol_negotiation() ->
+ %% Predecessor to APLN
+ ?LET(ExtD, alpn_protocols(), #next_protocol_negotiation{extension_data = ExtD}).
+
+srp() ->
+ ?LET(Name, gen_name(), #srp{username = list_to_binary(Name)}).
+
+renegotiation_info() ->
+ #renegotiation_info{renegotiated_connection = 0}.
+
+gen_name() ->
+ ?LET(Size, choose(0,10), gen_string(Size)).
+
+gen_char() ->
+ choose($a,$z).
+
+gen_string(N) ->
+ gen_string(N, []).
+
+gen_string(0, Acc) ->
+ Acc;
+gen_string(N, Acc) ->
+ ?LET(Char, gen_char(), gen_string(N-1, [Char | Acc])).
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index 27062d4801..04c4b257d9 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -155,7 +155,7 @@ empty_client(Config) when is_list(Config) ->
run_failing_handshake(Config,
[{alpn_advertised_protocols, []}],
[{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ {error,{tls_alert,"no application protocol"}}).
%--------------------------------------------------------------------------------
@@ -163,7 +163,7 @@ empty_server(Config) when is_list(Config) ->
run_failing_handshake(Config,
[{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
[{alpn_preferred_protocols, []}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ {error,{tls_alert,"no application protocol"}}).
%--------------------------------------------------------------------------------
@@ -171,7 +171,7 @@ empty_client_empty_server(Config) when is_list(Config) ->
run_failing_handshake(Config,
[{alpn_advertised_protocols, []}],
[{alpn_preferred_protocols, []}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ {error,{tls_alert,"no application protocol"}}).
%--------------------------------------------------------------------------------
@@ -179,7 +179,7 @@ no_matching_protocol(Config) when is_list(Config) ->
run_failing_handshake(Config,
[{alpn_advertised_protocols, [<<"http/1.0">>, <<"http/1.1">>]}],
[{alpn_preferred_protocols, [<<"spdy/2">>, <<"spdy/3">>, <<"http/2">>]}],
- {connect_failed,{tls_alert,"no application protocol"}}).
+ {error,{tls_alert,"no application protocol"}}).
%--------------------------------------------------------------------------------
@@ -342,18 +342,19 @@ run_failing_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedResult)
ServerOpts = ServerExtraOpts ++ ssl_test_lib:ssl_options(server_rsa_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, placeholder, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- ExpectedResult
- = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, placeholder, []}},
- {options, ClientOpts}]).
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, placeholder, []}},
+ {options, ClientOpts}]),
+ ssl_test_lib:check_result(Server, ExpectedResult,
+ Client, ExpectedResult).
run_handshake(Config, ClientExtraOpts, ServerExtraOpts, ExpectedProtocol) ->
Data = "hello world",
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 0381d0d87d..97b794c3e2 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -243,7 +243,8 @@ error_handling_tests()->
recv_active,
recv_active_once,
recv_error_handling,
- call_in_error_state
+ call_in_error_state,
+ close_in_error_state
].
error_handling_tests_tls()->
@@ -1182,16 +1183,16 @@ fallback(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
- Client =
- ssl_test_lib:start_client_error([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {from, self()}, {options,
- [{fallback, true},
- {versions, ['tlsv1']}
- | ClientOpts]}]),
+ Client =
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options,
+ [{fallback, true},
+ {versions, ['tlsv1']}
+ | ClientOpts]}]),
- ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}},
- Client, {error,{tls_alert,"inappropriate fallback"}}).
+ ssl_test_lib:check_result(Server, {error,{tls_alert,"inappropriate fallback"}},
+ Client, {error,{tls_alert,"inappropriate fallback"}}).
%%--------------------------------------------------------------------
cipher_format() ->
@@ -2644,14 +2645,14 @@ default_reject_anonymous(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options,
- [{ciphers,[CipherSuite]} |
- ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {options,
+ [{ciphers,[CipherSuite]} |
+ ClientOpts]}]),
ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}},
- Client, {error, {tls_alert, "insufficient security"}}).
+ Client, {error, {tls_alert, "insufficient security"}}).
%%--------------------------------------------------------------------
ciphers_ecdsa_signed_certs() ->
@@ -3269,7 +3270,7 @@ no_reuses_session_server_restart_new_cert(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, DsaServerOpts}]),
+ {options, [{reuseaddr, true} | DsaServerOpts]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
@@ -3330,7 +3331,7 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, Port},
{from, self()},
{mfa, {ssl_test_lib, no_result, []}},
- {options, NewServerOpts1}]),
+ {options, [{reuseaddr, true} | NewServerOpts1]}]),
Client1 =
ssl_test_lib:start_client([{node, ClientNode},
{port, Port}, {host, Hostname},
@@ -3526,7 +3527,7 @@ honor_cipher_order(Config, Honor, ServerCiphers, ClientCiphers, Expected) ->
%%--------------------------------------------------------------------
tls_ciphersuite_vs_version() ->
- [{doc,"Test a SSLv3 client can not negotiate a TLSv* cipher suite."}].
+ [{doc,"Test a SSLv3 client cannot negotiate a TLSv* cipher suite."}].
tls_ciphersuite_vs_version(Config) when is_list(Config) ->
{_ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -3569,14 +3570,14 @@ conf_signature_algs(Config) when is_list(Config) ->
ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ServerOpts]}]),
+ {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib, send_recv_result, []}},
- {options, [{active, false}, {signature_algs, [{sha256, rsa}]} | ClientOpts]}]),
+ {options, [{active, false}, {signature_algs, [{sha, rsa}]} | ClientOpts]}]),
ct:log("Testcase ~p, Client ~p Server ~p ~n",
[self(), Client, Server]),
@@ -3604,14 +3605,14 @@ no_common_signature_algs(Config) when is_list(Config) ->
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {options, [{signature_algs, [{sha384, rsa}]}
- | ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {options, [{signature_algs, [{sha384, rsa}]}
+ | ClientOpts]}]),
ssl_test_lib:check_result(Server, {error, {tls_alert, "insufficient security"}},
- Client, {error, {tls_alert, "insufficient security"}}).
-
+ Client, {error, {tls_alert, "insufficient security"}}).
+
%%--------------------------------------------------------------------
tls_dont_crash_on_handshake_garbage() ->
@@ -3673,7 +3674,7 @@ hibernate(Config) ->
{mfa, {ssl_test_lib, send_recv_result_active, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=Pid}} = ssl_test_lib:start_client([return_socket,
+ {Client, #sslsocket{pid=[Pid|_]}} = ssl_test_lib:start_client([return_socket,
{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
@@ -3716,7 +3717,7 @@ hibernate_right_away(Config) ->
Server1 = ssl_test_lib:start_server(StartServerOpts),
Port1 = ssl_test_lib:inet_port(Server1),
- {Client1, #sslsocket{pid = Pid1}} = ssl_test_lib:start_client(StartClientOpts ++
+ {Client1, #sslsocket{pid = [Pid1|_]}} = ssl_test_lib:start_client(StartClientOpts ++
[{port, Port1}, {options, [{hibernate_after, 0}|ClientOpts]}]),
ssl_test_lib:check_result(Server1, ok, Client1, ok),
@@ -3728,7 +3729,7 @@ hibernate_right_away(Config) ->
Server2 = ssl_test_lib:start_server(StartServerOpts),
Port2 = ssl_test_lib:inet_port(Server2),
- {Client2, #sslsocket{pid = Pid2}} = ssl_test_lib:start_client(StartClientOpts ++
+ {Client2, #sslsocket{pid = [Pid2|_]}} = ssl_test_lib:start_client(StartClientOpts ++
[{port, Port2}, {options, [{hibernate_after, 1}|ClientOpts]}]),
ssl_test_lib:check_result(Server2, ok, Client2, ok),
@@ -3964,13 +3965,13 @@ tls_tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket,
- {node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, receive_msg, []}},
- {options, ClientOpts}]),
-
+ {Client, #sslsocket{pid=[Pid|_]} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
{status, _, _, StatusInfo} = sys:get_status(Pid),
[_, _,_, _, Prop] = StatusInfo,
State = ssl_test_lib:state(Prop),
@@ -4036,6 +4037,33 @@ run_error_server([ Pid | Opts]) ->
%%--------------------------------------------------------------------
+close_in_error_state() ->
+ [{doc,"Special case of closing socket in error state"}].
+close_in_error_state(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_opts, Config),
+ ServerOpts = [{cacertfile, "foo.pem"} | proplists:delete(cacertfile, ServerOpts0)],
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ _ = spawn_link(?MODULE, run_error_server_close, [[self() | ServerOpts]]),
+ receive
+ {_Pid, Port} ->
+ spawn_link(?MODULE, run_client_error, [[Port, ClientOpts]])
+ end,
+ receive
+ ok ->
+ ok;
+ Other ->
+ ct:fail(Other)
+ end.
+
+run_error_server_close([Pid | Opts]) ->
+ {ok, Listen} = ssl:listen(0, Opts),
+ {ok,{_, Port}} = ssl:sockname(Listen),
+ Pid ! {self(), Port},
+ {ok, Socket} = ssl:transport_accept(Listen),
+ Pid ! ssl:close(Socket).
+
+%%--------------------------------------------------------------------
+
rizzo() ->
[{doc, "Test that there is a 1/n-1-split for non RC4 in 'TLS < 1.1' as it is
vunrable to Rizzo/Dungon attack"}].
@@ -4617,6 +4645,7 @@ renegotiate_rejected(Socket) ->
ok;
%% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
{ssl, Socket, "H"} ->
+
receive
{ssl, Socket, "ello world"} ->
ok
@@ -5004,20 +5033,24 @@ run_suites(Ciphers, Config, Type) ->
[{ciphers, Ciphers} |
ssl_test_lib:ssl_options(server_ecdsa_opts, Config)]}
end,
- ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, ssl_test_lib:filter_suites(Ciphers, Version)]),
- Result = lists:map(fun(Cipher) ->
- cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
- ssl_test_lib:filter_suites(Ciphers, Version)),
- case lists:flatten(Result) of
- [] ->
- ok;
- Error ->
- ct:log("Cipher suite errors: ~p~n", [Error]),
- ct:fail(cipher_suite_failed_see_test_case_log)
- end.
-
+ Suites = ssl_test_lib:filter_suites(Ciphers, Version),
+ ct:pal("ssl_test_lib:filter_suites(~p ~p) -> ~p ", [Ciphers, Version, Suites]),
+ Results0 = lists:map(fun(Cipher) ->
+ cipher(Cipher, Version, Config, ClientOpts, ServerOpts) end,
+ ssl_test_lib:filter_suites(Ciphers, Version)),
+ Results = lists:flatten(Results0),
+ true = length(Results) == length(Suites),
+ check_cipher_result(Results).
+
+check_cipher_result([]) ->
+ ok;
+check_cipher_result([ok | Rest]) ->
+ check_cipher_result(Rest);
+check_cipher_result([_ |_] = Error) ->
+ ct:fail(Error).
+
erlang_cipher_suite(Suite) when is_list(Suite)->
- ssl_cipher:suite_definition(ssl_cipher:openssl_suite(Suite));
+ ssl_cipher_format:suite_definition(ssl_cipher_format:openssl_suite(Suite));
erlang_cipher_suite(Suite) ->
Suite.
@@ -5052,7 +5085,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
case Result of
ok ->
- [];
+ [ok];
Error ->
[{ErlangCipherSuite, Error}]
end.
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index 63e9d07d0b..bddcc2514d 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -88,7 +88,8 @@ tests() ->
critical_extension_verify_client,
critical_extension_verify_server,
critical_extension_verify_none,
- customize_hostname_check
+ customize_hostname_check,
+ incomplete_chain
].
error_handling_tests()->
@@ -513,7 +514,7 @@ verify_fun_always_run_client(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(Server),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -552,7 +553,7 @@ verify_fun_always_run_server(Config) when is_list(Config) ->
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
%% If user verify fun is called correctly we fail the connection.
- %% otherwise we can not tell this case apart form where we miss
+ %% otherwise we cannot tell this case apart form where we miss
%% to call users verify fun
FunAndState = {fun(_,{extension, _}, UserState) ->
{unknown, UserState};
@@ -619,8 +620,8 @@ cert_expired(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer}, {active, Active} | ClientOpts]}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "certificate expired"}},
- Client, {error, {tls_alert, "certificate expired"}}).
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "certificate expired"}},
+ Client, {error, {tls_alert, "certificate expired"}}).
two_digits_str(N) when N < 10 ->
lists:flatten(io_lib:format("0~p", [N]));
@@ -728,8 +729,8 @@ critical_extension_verify_server(Config) when is_list(Config) ->
%% This certificate has a critical extension that we don't
%% understand. Therefore, verification should fail.
- tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}},
- Client, {error, {tls_alert, "unsupported certificate"}}),
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "unsupported certificate"}},
+ Client, {error, {tls_alert, "unsupported certificate"}}),
ssl_test_lib:close(Server).
%%--------------------------------------------------------------------
@@ -908,8 +909,8 @@ invalid_signature_server(Config) when is_list(Config) ->
{from, self()},
{options, [{verify, verify_peer} | ClientOpts]}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
- Client, {error, {tls_alert, "unknown ca"}}).
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}},
+ Client, {error, {tls_alert, "unknown ca"}}).
%%--------------------------------------------------------------------
@@ -945,8 +946,8 @@ invalid_signature_client(Config) when is_list(Config) ->
{from, self()},
{options, NewClientOpts}]),
- tcp_delivery_workaround(Server, {error, {tls_alert, "unknown ca"}},
- Client, {error, {tls_alert, "unknown ca"}}).
+ ssl_test_lib:check_result(Server, {error, {tls_alert, "unknown ca"}},
+ Client, {error, {tls_alert, "unknown ca"}}).
%%--------------------------------------------------------------------
@@ -1198,45 +1199,40 @@ customize_hostname_check(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+incomplete_chain() ->
+ [{doc,"Test option verify_peer"}].
+incomplete_chain(Config) when is_list(Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerConf,
+ client_config := ClientConf} = public_key:pkix_test_data(CertChainConf),
+ [ServerRoot| _] = ServerCas = proplists:get_value(cacerts, ServerConf),
+ ClientCas = proplists:get_value(cacerts, ClientConf),
+
+ Active = proplists:get_value(active, Config),
+ ReceiveFunction = proplists:get_value(receive_function, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active}, {verify, verify_peer},
+ {cacerts, [ServerRoot]} |
+ proplists:delete(cacerts, ServerConf)]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, ReceiveFunction, []}},
+ {options, [{active, Active},
+ {verify, verify_peer},
+ {cacerts, ServerCas ++ ClientCas} |
+ proplists:delete(cacerts, ClientConf)]}]),
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
- receive
- {Server, ServerMsg} ->
- client_msg(Client, ClientMsg);
- {Client, ClientMsg} ->
- server_msg(Server, ServerMsg);
- {Client, {error,closed}} ->
- server_msg(Server, ServerMsg);
- {Server, {error,closed}} ->
- client_msg(Client, ClientMsg)
- end.
-
-client_msg(Client, ClientMsg) ->
- receive
- {Client, ClientMsg} ->
- ok;
- {Client, {error,closed}} ->
- ct:log("client got close"),
- ok;
- {Client, {error, Reason}} ->
- ct:log("client got econnaborted: ~p", [Reason]),
- ok;
- Unexpected ->
- ct:fail(Unexpected)
- end.
-server_msg(Server, ServerMsg) ->
- receive
- {Server, ServerMsg} ->
- ok;
- {Server, {error,closed}} ->
- ct:log("server got close"),
- ok;
- {Server, {error, Reason}} ->
- ct:log("server got econnaborted: ~p", [Reason]),
- ok;
- Unexpected ->
- ct:fail(Unexpected)
- end.
diff --git a/lib/ssl/test/ssl_engine_SUITE.erl b/lib/ssl/test/ssl_engine_SUITE.erl
index 7277dad012..1423c99dc2 100644
--- a/lib/ssl/test/ssl_engine_SUITE.erl
+++ b/lib/ssl/test/ssl_engine_SUITE.erl
@@ -117,8 +117,23 @@ private_key(Config) when is_list(Config) ->
EngineServerConf = [{key, #{algorithm => rsa,
engine => Engine,
key_id => ServerKey}} | proplists:delete(key, ServerConf)],
+
+ EngineFileClientConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ClientKey}} |
+ proplists:delete(keyfile, FileClientConf)],
+
+ EngineFileServerConf = [{key, #{algorithm => rsa,
+ engine => Engine,
+ key_id => ServerKey}} |
+ proplists:delete(keyfile, FileServerConf)],
+
%% Test with engine
test_tls_connection(EngineServerConf, EngineClientConf, Config),
+
+ %% Test with engine and present file arugments
+ test_tls_connection(EngineFileServerConf, EngineFileClientConf, Config),
+
%% Test that sofware fallback is available
test_tls_connection(ServerConf, [{reuse_sessions, false} |ClientConf], Config).
diff --git a/lib/ssl/test/ssl_eqc_SUITE.erl b/lib/ssl/test/ssl_eqc_SUITE.erl
new file mode 100644
index 0000000000..bd36d35c02
--- /dev/null
+++ b/lib/ssl/test/ssl_eqc_SUITE.erl
@@ -0,0 +1,58 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015-2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(ssl_eqc_SUITE).
+
+-compile(export_all).
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+all() ->
+ [
+ tls_handshake_encoding
+ ].
+
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+end_per_suite(Config) ->
+ Config.
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_,Config) ->
+ Config.
+
+init_per_testcase(_, Config0) ->
+ Config0.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+tls_handshake_encoding(Config) when is_list(Config) ->
+ %% manual test: proper:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode()).
+ true = ct_property_test:quickcheck(ssl_eqc_handshake:prop_tls_hs_encode_decode(),
+ Config).
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 2c7c62407e..861fecc554 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -25,6 +25,7 @@
-compile(export_all).
-include_lib("common_test/include/ct.hrl").
+-include("ssl_alert.hrl").
-include("ssl_internal.hrl").
-include("tls_handshake.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -40,7 +41,8 @@ all() -> [decode_hello_handshake,
decode_single_hello_sni_extension_correctly,
decode_empty_server_sni_correctly,
select_proper_tls_1_2_rsa_default_hashsign,
- ignore_hassign_extension_pre_tls_1_2].
+ ignore_hassign_extension_pre_tls_1_2,
+ unorded_chain, signature_algorithms].
%%--------------------------------------------------------------------
init_per_suite(Config) ->
@@ -54,7 +56,9 @@ init_per_group(_GroupName, Config) ->
end_per_group(_,Config) ->
Config.
-init_per_testcase(ignore_hassign_extension_pre_tls_1_2, Config0) ->
+init_per_testcase(TC, Config0) when
+ TC =:= ignore_hassign_extension_pre_tls_1_2 orelse
+ TC =:= signature_algorithms ->
catch crypto:stop(),
try crypto:start() of
ok ->
@@ -103,15 +107,13 @@ decode_hello_handshake(_Config) ->
#ssl_options{}),
{Hello, _Data} = hd(Records),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = (Hello#server_hello.extensions)#hello_extensions.renegotiation_info.
-
+ Extensions = Hello#server_hello.extensions,
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_single_hello_extension_correctly(_Config) ->
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(Renegotiation),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_extensions(Renegotiation),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
% List of supported and unsupported curves (RFC4492:S5.1.1)
@@ -122,37 +124,34 @@ decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
Len = ListLen + 2,
Extension = <<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary>>,
% after decoding we should see only valid curves
- #hello_extensions{elliptic_curves = DecodedCurves} = ssl_handshake:decode_hello_extensions(Extension),
- #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]} = DecodedCurves.
+ Extensions = ssl_handshake:decode_hello_extensions(Extension, {3,2}, client),
+ #{elliptic_curves := #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]}} = Extensions.
decode_unknown_hello_extension_correctly(_Config) ->
FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>,
Renegotiation = <<?UINT16(?RENEGOTIATION_EXT), ?UINT16(1), 0>>,
- Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>),
- #renegotiation_info{renegotiated_connection = <<0>>}
- = Extensions#hello_extensions.renegotiation_info.
+ Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>, {3,2}, client),
+ #{renegotiation_info := #renegotiation_info{renegotiated_connection = <<0>>}} = Extensions.
+
encode_single_hello_sni_extension_correctly(_Config) ->
- Exts = #hello_extensions{sni = #sni{hostname = "test.com"}},
SNI = <<16#00, 16#00, 16#00, 16#0d, 16#00, 16#0b, 16#00, 16#00, 16#08,
$t, $e, $s, $t, $., $c, $o, $m>>,
ExtSize = byte_size(SNI),
HelloExt = <<ExtSize:16/unsigned-big-integer, SNI/binary>>,
- Encoded = ssl_handshake:encode_hello_extensions(Exts),
+ Encoded = ssl_handshake:encode_extensions([#sni{hostname = "test.com"}]),
HelloExt = Encoded.
decode_single_hello_sni_extension_correctly(_Config) ->
- Exts = #hello_extensions{sni = #sni{hostname = "test.com"}},
SNI = <<16#00, 16#00, 16#00, 16#0d, 16#00, 16#0b, 16#00, 16#00, 16#08,
$t, $e, $s, $t, $., $c, $o, $m>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, client),
+ #{sni := #sni{hostname = "test.com"}} = Decoded.
decode_empty_server_sni_correctly(_Config) ->
- Exts = #hello_extensions{sni = ""},
SNI = <<?UINT16(?SNI_EXT),?UINT16(0)>>,
- Decoded = ssl_handshake:decode_hello_extensions(SNI),
- Exts = Decoded.
+ Decoded = ssl_handshake:decode_hello_extensions(SNI, {3,3}, server),
+ #{sni := #sni{hostname = ""}} = Decoded.
select_proper_tls_1_2_rsa_default_hashsign(_Config) ->
@@ -167,11 +166,83 @@ ignore_hassign_extension_pre_tls_1_2(Config) ->
Opts = proplists:get_value(server_opts, Config),
CertFile = proplists:get_value(certfile, Opts),
[{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
- HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}]},
- {sha512, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
+ HashSigns = #hash_sign_algos{hash_sign_algos = [{sha512, rsa}, {sha, dsa}, {sha, rsa}]},
+ {sha512, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,3}), {3,3}),
%%% Ignore
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
- {md5sha, rsa} = ssl_handshake:select_hashsign(HashSigns, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,2}), {3,2}),
+ {md5sha, rsa} = ssl_handshake:select_hashsign({HashSigns, undefined}, Cert, ecdhe_rsa, tls_v1:default_signature_algs({3,0}), {3,0}).
+
+unorded_chain(Config) when is_list(Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
+ #{server_config := ServerConf,
+ client_config := _ClientConf} = public_key:pkix_test_data(CertChainConf),
+ PeerCert = proplists:get_value(cert, ServerConf),
+ CaCerts = [_, C1, C2] = proplists:get_value(cacerts, ServerConf),
+ {ok, ExtractedCerts} = ssl_pkix_db:extract_trusted_certs({der, CaCerts}),
+ UnordedChain = case public_key:pkix_is_self_signed(C1) of
+ true ->
+ [C1, C2];
+ false ->
+ [C2, C1]
+ end,
+ OrderedChain = [PeerCert | lists:reverse(UnordedChain)],
+ {ok, _, OrderedChain} =
+ ssl_certificate:certificate_chain(PeerCert, ets:new(foo, []), ExtractedCerts, UnordedChain).
+
+
+signature_algorithms(Config) ->
+ Opts = proplists:get_value(server_opts, Config),
+ CertFile = proplists:get_value(certfile, Opts),
+ io:format("Cert = ~p~n", [CertFile]),
+ [{_, Cert, _}] = ssl_test_lib:pem_to_der(CertFile),
+ HashSigns0 = #hash_sign_algos{
+ hash_sign_algos = [{sha512, rsa},
+ {sha, dsa},
+ {sha, rsa}]},
+ Schemes0 = #signature_scheme_list{
+ signature_scheme_list = [rsa_pkcs1_sha1,
+ ecdsa_sha1]},
+ {sha512, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns0, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns1 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa},
+ {sha, rsa}]},
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes0},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ Schemes1 = #signature_scheme_list{
+ signature_scheme_list = [rsa_pkcs1_sha256,
+ ecdsa_sha1]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns1, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ %% No scheme, hashsign is used
+ {sha, rsa} = ssl_handshake:select_hashsign(
+ {HashSigns1, undefined},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}),
+ HashSigns2 = #hash_sign_algos{
+ hash_sign_algos = [{sha, dsa}]},
+ %% Signature not supported
+ #alert{} = ssl_handshake:select_hashsign(
+ {HashSigns2, Schemes1},
+ Cert, ecdhe_rsa,
+ tls_v1:default_signature_algs({3,3}),
+ {3,3}).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
is_supported(Hash) ->
Algos = crypto:supports(),
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 35af666e9e..46734ba180 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -71,44 +71,46 @@ encode_and_decode_client_hello_test(Config) ->
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_npn_client_hello_test(Config) ->
HandShakeData = create_client_handshake(#next_protocol_negotiation{extension_data = <<>>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#client_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<>>}.
+ Extensions = DecodedHandshakeMessage#client_hello.extensions,
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<>>}} = Extensions.
%%--------------------------------------------------------------------
encode_and_decode_server_hello_test(Config) ->
HandShakeData = create_server_handshake(undefined),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- NextProtocolNegotiation = undefined.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ #{next_protocol_negotiation := undefined} = Extensions.
+
%%--------------------------------------------------------------------
encode_and_decode_npn_server_hello_test(Config) ->
HandShakeData = create_server_handshake(#next_protocol_negotiation{extension_data = <<6, "spdy/2">>}),
Version = ssl_test_lib:protocol_version(Config),
{[{DecodedHandshakeMessage, _Raw}], _} =
tls_handshake:get_tls_handshake(Version, list_to_binary(HandShakeData), <<>>, #ssl_options{}),
- NextProtocolNegotiation = (DecodedHandshakeMessage#server_hello.extensions)#hello_extensions.next_protocol_negotiation,
- ct:log("~p ~n", [NextProtocolNegotiation]),
- NextProtocolNegotiation = #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}.
+ Extensions = DecodedHandshakeMessage#server_hello.extensions,
+ ct:log("~p ~n", [Extensions]),
+ #{next_protocol_negotiation := #next_protocol_negotiation{extension_data = <<6, "spdy/2">>}} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_no_advertised_protocols_test(_Config) ->
- Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #hello_extensions{}),
- undefined = (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(), #{}),
+ Extensions = Hello#server_hello.extensions,
+ #{} = Extensions.
%%--------------------------------------------------------------------
create_server_hello_with_advertised_protocols_test(_Config) ->
Hello = ssl_handshake:server_hello(<<>>, {3, 0}, create_connection_states(),
- #hello_extensions{next_protocol_negotiation = [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
- [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>] =
- (Hello#server_hello.extensions)#hello_extensions.next_protocol_negotiation.
+ #{next_protocol_negotiation => [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]}),
+ Extensions = Hello#server_hello.extensions,
+ #{next_protocol_negotiation := [<<"spdy/1">>, <<"http/1.0">>, <<"http/1.1">>]} = Extensions.
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -120,9 +122,8 @@ create_client_handshake(Npn) ->
session_id = <<>>,
cipher_suites = [?TLS_DHE_DSS_WITH_DES_CBC_SHA],
compression_methods = "",
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_server_handshake(Npn) ->
@@ -133,9 +134,8 @@ create_server_handshake(Npn) ->
session_id = <<>>,
cipher_suite = ?TLS_DHE_DSS_WITH_DES_CBC_SHA,
compression_method = 1,
- extensions = #hello_extensions{
- next_protocol_negotiation = Npn,
- renegotiation_info = #renegotiation_info{}}
+ extensions = #{next_protocol_negotiation => Npn,
+ renegotiation_info => #renegotiation_info{}}
}, Vsn).
create_connection_states() ->
@@ -146,5 +146,5 @@ create_connection_states() ->
}
},
current_read => #{secure_renegotiation => false
- }
+ }
}.
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 3261244ace..ebf8ddbfac 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -141,6 +141,7 @@ socket_active_packet_tests() ->
packet_4_active_some_big,
packet_wait_active,
packet_size_active,
+ packet_switch,
%% inet header option should be deprecated!
header_decode_one_byte_active,
header_decode_two_bytes_active,
@@ -702,6 +703,34 @@ packet_size_passive(Config) when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+packet_switch() ->
+ [{doc,"Test packet option {packet, 2} followd by {packet, 4}"}].
+
+packet_switch(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_switch_packet ,["Hello World", 4]}},
+ {options, [{nodelay, true},{packet, 2} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, recv_switch_packet, ["Hello World", 4]}},
+ {options, [{nodelay, true}, {packet, 2} |
+ ClientOpts]}]),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+
%%--------------------------------------------------------------------
packet_cdr_decode() ->
[{doc,"Test setting the packet option {packet, cdr}, {mode, binary}"}].
@@ -2286,3 +2315,26 @@ client_reject_packet_opt(Config, PacketOpt) ->
ClientOpts]}]),
ssl_test_lib:check_result(Client, {error, {options, {not_supported, PacketOpt}}}).
+
+
+send_switch_packet(SslSocket, Data, NextPacket) ->
+ ssl:send(SslSocket, Data),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:setopts(SslSocket, [{packet, NextPacket}]),
+ ssl:send(SslSocket, Data),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ok
+ end
+ end.
+recv_switch_packet(SslSocket, Data, NextPacket) ->
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:send(SslSocket, Data),
+ ssl:setopts(SslSocket, [{packet, NextPacket}]),
+ receive
+ {ssl, SslSocket, "Hello World"} ->
+ ssl:send(SslSocket, Data)
+ end
+ end.
diff --git a/lib/ssl/test/ssl_pem_cache_SUITE.erl b/lib/ssl/test/ssl_pem_cache_SUITE.erl
index 96b15d9b51..25d2cb300d 100644
--- a/lib/ssl/test/ssl_pem_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_pem_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
- [pem_cleanup].
+ [pem_cleanup, invalid_insert].
groups() ->
[].
@@ -68,6 +68,10 @@ init_per_testcase(pem_cleanup = Case, Config) ->
application:set_env(ssl, ssl_pem_cache_clean, ?CLEANUP_INTERVAL),
ssl:start(),
ct:timetrap({minutes, 1}),
+ Config;
+init_per_testcase(_, Config) ->
+ ssl:start(),
+ ct:timetrap({seconds, 5}),
Config.
end_per_testcase(_TestCase, Config) ->
@@ -108,7 +112,34 @@ pem_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client),
false = Size == Size1.
-
+
+invalid_insert() ->
+ [{doc, "Test that insert of invalid pem does not cause empty cache entry"}].
+invalid_insert(Config)when is_list(Config) ->
+ process_flag(trap_exit, true),
+
+ ClientOpts = proplists:get_value(client_verification_opts, Config),
+ ServerOpts = proplists:get_value(server_verification_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ BadClientOpts = [{cacertfile, "tmp/does_not_exist.pem"} | proplists:delete(cacertfile, ClientOpts)],
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ ssl_test_lib:start_client_error([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {from, self()}, {options, BadClientOpts}]),
+ ssl_test_lib:close(Server),
+ 1 = ssl_pkix_db:db_size(get_fileref_db()).
+
+
+
+%%--------------------------------------------------------------------
+%% Internal funcations
+%%--------------------------------------------------------------------
+
get_pem_cache() ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
@@ -120,6 +151,16 @@ get_pem_cache() ->
undefined
end.
+get_fileref_db() ->
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ case element(6, State) of
+ [_CertDb, {FileRefDb,_} | _] ->
+ FileRefDb;
+ _ ->
+ undefined
+ end.
later()->
DateTime = calendar:now_to_local_time(os:timestamp()),
Gregorian = calendar:datetime_to_gregorian_seconds(DateTime),
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 9862b3ce64..a0fab58b9d 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -487,8 +487,8 @@ test_copts(_, 0, ClientOpts) ->
ClientOpts;
test_copts(max_table_size, N, ClientOpts) ->
Version = tls_record:highest_protocol_version([]),
- CipherSuites = %%lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))),
-[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss],
+ CipherSuites = %%lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))),
+[ Y|| Y = {Alg,_, _, _} <- lists:map(fun(X) -> ssl_cipher_format:suite_definition(X) end, ssl_cipher:filter_suites(ssl_cipher:suites(Version))), Alg =/= ecdhe_ecdsa, Alg =/= ecdh_ecdsa, Alg =/= ecdh_rsa, Alg =/= ecdhe_rsa, Alg =/= dhe_dss, Alg =/= dss],
case length(CipherSuites) of
M when M >= N ->
Cipher = lists:nth(N, CipherSuites),
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 91a9c774a6..39a5bcaad6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -1003,7 +1003,6 @@ ecc_test_error(COpts, SOpts, CECCOpts, SECCOpts, Config) ->
Error = {error, {tls_alert, "insufficient security"}},
check_result(Server, Error, Client, Error).
-
start_client(openssl, Port, ClientOpts, Config) ->
Cert = proplists:get_value(certfile, ClientOpts),
Key = proplists:get_value(keyfile, ClientOpts),
@@ -1221,13 +1220,13 @@ common_ciphers(crypto) ->
common_ciphers(openssl) ->
OpenSslSuites =
string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"),
- [ssl_cipher:suite_definition(S)
+ [ssl_cipher_format:suite_definition(S)
|| S <- ssl_cipher:suites(tls_record:highest_protocol_version([])),
- lists:member(ssl_cipher:openssl_suite_name(S), OpenSslSuites)
+ lists:member(ssl_cipher_format:openssl_suite_name(S), OpenSslSuites)
].
available_suites(Version) ->
- [ssl_cipher:suite_definition(Suite) ||
+ [ssl_cipher_format:suite_definition(Suite) ||
Suite <- ssl_cipher:filter_suites(ssl_cipher:suites(Version))].
@@ -1300,7 +1299,7 @@ string_regex_filter(_Str, _Search) ->
false.
ecdh_dh_anonymous_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:anonymous_suites(Version)],
[{key_exchange,
fun(dh_anon) ->
true;
@@ -1310,7 +1309,7 @@ ecdh_dh_anonymous_suites(Version) ->
false
end}]).
psk_suites({3,_} = Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []);
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites(Version)], []);
psk_suites(Version) ->
ssl:filter_cipher_suites(psk_suites(dtls_v1:corresponding_tls_version(Version)),
[{cipher,
@@ -1321,11 +1320,13 @@ psk_suites(Version) ->
end}]).
psk_anon_suites({3,_} = Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:psk_suites_anon(Version)],
[{key_exchange,
fun(psk) ->
true;
- (psk_dhe) ->
+ (dhe_psk) ->
+ true;
+ (ecdhe_psk) ->
true;
(_) ->
false
@@ -1342,7 +1343,7 @@ psk_anon_suites(Version) ->
srp_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_rsa) ->
true;
@@ -1350,10 +1351,10 @@ srp_suites() ->
false
end}]).
srp_anon_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites_anon()],
[]).
srp_dss_suites() ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <- ssl_cipher:srp_suites()],
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:srp_suites()],
[{key_exchange,
fun(srp_dss) ->
true;
@@ -1361,14 +1362,14 @@ srp_dss_suites() ->
false
end}]).
chacha_suites(Version) ->
- [ssl_cipher:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
+ [ssl_cipher_format:suite_definition(S) || S <- ssl_cipher:filter_suites(ssl_cipher:chacha_suites(Version))].
rc4_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:rc4_suites(Version)], []).
des_suites(Version) ->
- ssl:filter_cipher_suites([ssl_cipher:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []).
+ ssl:filter_cipher_suites([ssl_cipher_format:suite_definition(S) || S <-ssl_cipher:des_suites(Version)], []).
tuple_to_map({Kex, Cipher, Mac}) ->
#{key_exchange => Kex,
@@ -1524,11 +1525,6 @@ v_1_2_check(ecdh_ecdsa, ecdh_rsa) ->
true;
v_1_2_check(ecdh_rsa, ecdh_ecdsa) ->
true;
-v_1_2_check(ecdhe_ecdsa, ecdhe_rsa) ->
- true;
-v_1_2_check(ecdhe_rsa, ecdhe_ecdsa) ->
- true;
-
v_1_2_check(_, _) ->
false.
@@ -1647,6 +1643,8 @@ openssl_dsa_support() ->
true;
"LibreSSL" ++ _ ->
false;
+ "OpenSSL 1.1" ++ Rest ->
+ false;
"OpenSSL 1.0.1" ++ Rest ->
hd(Rest) >= s;
_ ->
@@ -1767,10 +1765,10 @@ version_flag('dtlsv1') ->
"-dtls1".
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_list(Cipher)->
- filter_suites([ssl_cipher:openssl_suite(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:openssl_suite(S) || S <- Ciphers],
AtomVersion);
filter_suites([Cipher | _] = Ciphers, AtomVersion) when is_binary(Cipher)->
- filter_suites([ssl_cipher:suite_definition(S) || S <- Ciphers],
+ filter_suites([ssl_cipher_format:suite_definition(S) || S <- Ciphers],
AtomVersion);
filter_suites(Ciphers0, AtomVersion) ->
Version = tls_version(AtomVersion),
@@ -1782,7 +1780,7 @@ filter_suites(Ciphers0, AtomVersion) ->
++ ssl_cipher:srp_suites_anon()
++ ssl_cipher:rc4_suites(Version),
Supported1 = ssl_cipher:filter_suites(Supported0),
- Supported2 = [ssl_cipher:suite_definition(S) || S <- Supported1],
+ Supported2 = [ssl_cipher_format:suite_definition(S) || S <- Supported1],
[Cipher || Cipher <- Ciphers0, lists:member(Cipher, Supported2)].
-define(OPENSSL_QUIT, "Q\n").
@@ -1857,13 +1855,11 @@ do_supports_ssl_tls_version(Port, Acc) ->
case Acc ++ Data of
"unknown option" ++ _ ->
false;
- Error when length(Error) >= 11 ->
- case lists:member("error", string:tokens(Data, ":")) of
- true ->
- false;
- false ->
- do_supports_ssl_tls_version(Port, Error)
- end;
+ "s_client: Option unknown" ++ _->
+ false;
+ Info when length(Info) >= 24 ->
+ ct:pal("~p", [Info]),
+ true;
_ ->
do_supports_ssl_tls_version(Port, Acc ++ Data)
end
@@ -2064,3 +2060,40 @@ hardcode_dsa_key(3) ->
y = 48598545580251057979126570873881530215432219542526130654707948736559463436274835406081281466091739849794036308281564299754438126857606949027748889019480936572605967021944405048011118039171039273602705998112739400664375208228641666852589396502386172780433510070337359132965412405544709871654840859752776060358,
x = 1457508827177594730669011716588605181448418352823}.
+tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ client_msg(Client, ClientMsg);
+ {Client, ClientMsg} ->
+ server_msg(Server, ServerMsg);
+ {Client, {error,closed}} ->
+ server_msg(Server, ServerMsg);
+ {Server, {error,closed}} ->
+ client_msg(Client, ClientMsg)
+ end.
+client_msg(Client, ClientMsg) ->
+ receive
+ {Client, ClientMsg} ->
+ ok;
+ {Client, {error,closed}} ->
+ ct:log("client got close"),
+ ok;
+ {Client, {error, Reason}} ->
+ ct:log("client got econnaborted: ~p", [Reason]),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
+server_msg(Server, ServerMsg) ->
+ receive
+ {Server, ServerMsg} ->
+ ok;
+ {Server, {error,closed}} ->
+ ct:log("server got close"),
+ ok;
+ {Server, {error, Reason}} ->
+ ct:log("server got econnaborted: ~p", [Reason]),
+ ok;
+ Unexpected ->
+ ct:fail(Unexpected)
+ end.
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 7fc5e13400..5a38f5f9c1 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -598,73 +598,84 @@ erlang_client_openssl_server_anon(Config) when is_list(Config) ->
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cert", CertFile, "-key", KeyFile,
- "-cipher", "aNULL", "-msg"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cert", CertFile, "-key", KeyFile,
+ "-cipher", "aNULL", "-msg"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
{mfa, {?MODULE,
erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ClientOpts]}]),
-
- true = port_command(OpensslPort, Data),
-
- ssl_test_lib:check_result(Client, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client),
- process_flag(trap_exit, false),
- ok.
+ {options, [{ciphers, Ciphers} | ClientOpts]}]),
+
+ true = port_command(OpensslPort, Data),
+
+ ssl_test_lib:check_result(Client, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false)
+ end.
%%--------------------------------------------------------------------
erlang_server_openssl_client_anon() ->
[{doc,"Test erlang server with openssl client, anonymous"}].
erlang_server_openssl_client_anon(Config) when is_list(Config) ->
+
process_flag(trap_exit, true),
ServerOpts = ssl_test_lib:ssl_options(server_anon_opts, Config),
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false)
+ end.
%%--------------------------------------------------------------------
erlang_server_openssl_client_anon_with_cert() ->
@@ -675,30 +686,35 @@ erlang_server_openssl_client_anon_with_cert(Config) when is_list(Config) ->
VersionTuple = ssl_test_lib:protocol_version(Config, tuple),
Ciphers = ssl_test_lib:ecdh_dh_anonymous_suites(VersionTuple),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Data = "From openssl to erlang",
-
- Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
+ case openssl_has_common_ciphers(Ciphers) of
+ false ->
+ {skip, not_supported_by_openssl};
+ true ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
- {options, [{ciphers, Ciphers} | ServerOpts]}]),
- Port = ssl_test_lib:inet_port(Server),
- Version = ssl_test_lib:protocol_version(Config),
- Exe = "openssl",
- Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
- ssl_test_lib:version_flag(Version),
- "-cipher", "aNULL", "-msg"],
-
- OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
- true = port_command(OpenSslPort, Data),
-
- ssl_test_lib:check_result(Server, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server),
- ssl_test_lib:close_port(OpenSslPort),
- process_flag(trap_exit, false).
+ {options, [{ciphers, Ciphers} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_test_lib:protocol_version(Config),
+ Exe = "openssl",
+ Args = ["s_client", "-connect", hostname_format(Hostname) ++ ":" ++ integer_to_list(Port),
+ ssl_test_lib:version_flag(Version),
+ "-cipher", "aNULL", "-msg"],
+
+ OpenSslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ true = port_command(OpenSslPort, Data),
+
+ ssl_test_lib:check_result(Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close_port(OpenSslPort),
+ process_flag(trap_exit, false)
+ end.
%%--------------------------------------------------------------------
erlang_server_openssl_client_reuse_session() ->
@@ -2012,3 +2028,18 @@ no_low_flag("-no_ssl2" = Flag) ->
end;
no_low_flag(Flag) ->
Flag.
+
+
+openssl_has_common_ciphers(Ciphers) ->
+ OCiphers = ssl_test_lib:common_ciphers(openssl),
+ has_common_ciphers(Ciphers, OCiphers).
+
+has_common_ciphers([], OCiphers) ->
+ false;
+has_common_ciphers([Cipher | Rest], OCiphers) ->
+ case lists:member(Cipher, OCiphers) of
+ true ->
+ true;
+ _ ->
+ has_common_ciphers(Rest, OCiphers)
+ end.
diff --git a/lib/stdlib/doc/src/assert_hrl.xml b/lib/stdlib/doc/src/assert_hrl.xml
index 4dc7299609..fb27954235 100644
--- a/lib/stdlib/doc/src/assert_hrl.xml
+++ b/lib/stdlib/doc/src/assert_hrl.xml
@@ -46,7 +46,7 @@
is the macro name, for example, <c>assertEqual</c>. <c>Info</c> is a list
of tagged values, such as <c>[{module, M}, {line, L}, ...]</c>, which
gives more information about the location and cause of the exception. All
- entries in the <c>Info</c> list are optional; do not rely programatically
+ entries in the <c>Info</c> list are optional; do not rely programmatically
on any of them being present.</p>
<p>Each assert macro has a corresponding version with an extra argument,
diff --git a/lib/stdlib/doc/src/beam_lib.xml b/lib/stdlib/doc/src/beam_lib.xml
index 26d0724aaf..213170df7f 100644
--- a/lib/stdlib/doc/src/beam_lib.xml
+++ b/lib/stdlib/doc/src/beam_lib.xml
@@ -180,8 +180,8 @@ io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).</code>
<name name="beam"/>
<desc>
<p>Each of the functions described below accept either the
- module name, the filename, or a binary containing the BEAM
- module.</p>
+ filename (as a string) or a binary containing the BEAM
+ module.</p>
</desc>
</datatype>
<datatype>
diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml
index 1dc0161398..d803d259aa 100644
--- a/lib/stdlib/doc/src/epp.xml
+++ b/lib/stdlib/doc/src/epp.xml
@@ -124,6 +124,10 @@
<fsummary>Open a file for preprocessing.</fsummary>
<desc>
<p>Opens a file for preprocessing.</p>
+ <p>If you want to change the file name of the implicit -file()
+ attributes inserted during preprocessing, you can do with
+ <c>{source_name, <anno>SourceName</anno>}</c>. If unset it will
+ default to the name of the opened file.</p>
<p>If <c>extra</c> is specified in
<c><anno>Options</anno></c>, the return value is
<c>{ok, <anno>Epp</anno>, <anno>Extra</anno>}</c> instead
@@ -169,6 +173,10 @@
<p>Preprocesses and parses an Erlang source file.
Notice that tuple <c>{eof, <anno>Line</anno>}</c> returned at the
end of the file is included as a "form".</p>
+ <p>If you want to change the file name of the implicit -file()
+ attributes inserted during preprocessing, you can do with
+ <c>{source_name, <anno>SourceName</anno>}</c>. If unset it will
+ default to the name of the opened file.</p>
<p>If <c>extra</c> is specified in
<c><anno>Options</anno></c>, the return value is
<c>{ok, [<anno>Form</anno>], <anno>Extra</anno>}</c> instead
diff --git a/lib/stdlib/doc/src/ets.xml b/lib/stdlib/doc/src/ets.xml
index f8c54fb79a..611b176613 100644
--- a/lib/stdlib/doc/src/ets.xml
+++ b/lib/stdlib/doc/src/ets.xml
@@ -611,9 +611,8 @@ Error: fun containing local Erlang function calls
</item>
<item>
<p><c>Item=stats, Value=tuple()</c></p>
- <p>Returns internal statistics about <c>set</c>, <c>bag</c>, and
- <c>duplicate_bag</c> tables on an internal format used by OTP
- test suites. Not for production use.</p></item>
+ <p>Returns internal statistics about tables on an internal format
+ used by OTP test suites. Not for production use.</p></item>
</list>
</desc>
</func>
@@ -1023,7 +1022,7 @@ ets:select(Table, MatchSpec),</code>
be used in subsequent operations. The table identifier can be
sent to other processes so that a table can be shared between
different processes within a node.</p>
- <p>Parameter <c><anno>Options</anno></c> is a list of atoms that
+ <p>Parameter <c><anno>Options</anno></c> is a list of options that
specifies table type, access rights, key position, and whether the
table is named. Default values are used for omitted options.
This means that not specifying any options (<c>[]</c>) is the same
@@ -1135,11 +1134,17 @@ ets:select(Table, MatchSpec),</code>
Functions that makes such promises over many objects (like
<seealso marker="#insert/2"><c>insert/2</c></seealso>)
gain less (or nothing) from this option.</p>
- <p>Table type <c>ordered_set</c> is not affected by this option.
- Also, the memory consumption inflicted by
- both <c>write_concurrency</c> and <c>read_concurrency</c> is a
- constant overhead per table. This overhead can be especially
- large when both options are combined.</p>
+ <p>The memory consumption inflicted by both <c>write_concurrency</c>
+ and <c>read_concurrency</c> is a constant overhead per table for
+ <c>set</c>, <c>bag</c> and <c>duplicate_bag</c>. For
+ <c>ordered_set</c> the memory overhead depends on the number
+ of inserted objects and the amount of actual detected
+ concurrency in runtime. The memory overhead can be especially
+ large when both options are combined.</p>
+ <note>
+ <p>Prior to stdlib-3.7 (OTP-22.0) <c>write_concurrency</c> had no
+ effect on <c>ordered_set</c>.</p>
+ </note>
<marker id="new_2_read_concurrency"></marker>
</item>
<tag><c>{read_concurrency,boolean()}</c></tag>
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index ce19f70df0..36254c2d00 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -84,11 +84,6 @@
reject such filenames.
</p></warning>
</description>
- <datatypes>
- <datatype>
- <name name="basedir_type"/>
- </datatype>
- </datatypes>
<funcs>
<func>
@@ -149,18 +144,37 @@
</func>
<func>
- <name name="basedir" arity="2"/>
- <fsummary>Equivalent to <c>basedir(<anno>Type</anno>,<anno>Application</anno>,#{})</c>.</fsummary>
+ <name name="basedir" arity="2" clause_i="1"/>
+ <name name="basedir" arity="2" clause_i="2"/>
+ <fsummary>Equivalent to <c>basedir(<anno>PathType</anno>,
+ <anno>Application</anno>,#{})</c> or
+ <c>basedir(<anno>PathsType</anno>, <anno>Application</anno>,#{})</c>.
+ </fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
<desc>
<p>
- Equivalent to <seealso marker="#basedir-3">
- basedir(<anno>Type</anno>, <anno>Application</anno>, #{})</seealso>.
+ Equivalent to <seealso marker="#basedir_3_1">
+ basedir(<anno>PathType</anno>, <anno>Application</anno>, #{})</seealso>
+ or <seealso marker="#basedir_3_2">
+basedir(<anno>PathsType</anno>, <anno>Application</anno>, #{})</seealso>.
</p>
</desc>
</func>
<func>
- <name name="basedir" arity="3"/>
+ <name name="basedir" arity="3" clause_i="1" anchor="basedir_3_1"/>
+ <name name="basedir" arity="3" clause_i="2" anchor="basedir_3_2"/>
<fsummary></fsummary>
+ <type variable="PathType" name_i="1"/>
+ <type name="basedir_path_type"/>
+ <type variable="PathsType" name_i="2"/>
+ <type name="basedir_paths_type"/>
+ <type variable="Application"/>
+ <type variable="Opts"/>
+ <type name="basedir_opts"/>
<desc><marker id="basedir-3"/>
<p>
Returns a suitable path, or paths, for a given type. If
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index f793ec7fdf..fc34e51216 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -775,7 +775,7 @@ gen_event:stop -----> Module:terminate/2
<p>This callback is optional, so callback modules need not
export it. The <c>gen_event</c> module provides a default
implementation of this function that logs about the unexpected
- <c>Info</c> message, drops it and returns <c>{noreply, State}</c>.</p>
+ <c>Info</c> message, drops it and returns <c>{ok, State}</c>.</p>
</note>
<p>This function is called for each installed event handler when
an event manager receives any other message than an event or
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index a808d3af55..dfecd235c9 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -167,7 +167,7 @@ erlang:'!' -----> Module:StateName/3
</p>
<marker id="state callback"/>
<p>
- The "<em>state callback</em>" for a specific
+ The <em>state callback</em> for a specific
<seealso marker="#type-state">state</seealso>
in a <c>gen_statem</c> is the callback function that is called
for all events in this state. It is selected depending on which
@@ -179,7 +179,7 @@ erlang:'!' -----> Module:StateName/3
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>, the state must be an atom and
- is used as the state callback name; see
+ is used as the <em>state callback</em> name; see
<seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>.
This co-locates all code for a specific state
in one function as the <c>gen_statem</c> engine
@@ -192,7 +192,7 @@ erlang:'!' -----> Module:StateName/3
When the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>handle_event_function</c>, the state can be any term
- and the state callback name is
+ and the <em>state callback</em> name is
<seealso marker="#Module:handle_event/4"><c>Module:handle_event/4</c></seealso>.
This makes it easy to branch depending on state or event as you desire.
Be careful about which events you handle in which
@@ -200,12 +200,36 @@ erlang:'!' -----> Module:StateName/3
forever creating an infinite busy loop.
</p>
<p>
- The <c>gen_statem</c> enqueues incoming events in order of arrival
- and presents these to the
- <seealso marker="#state callback">state callback</seealso>
- in that order. The state callback can postpone an event
- so it is not retried in the current state.
- After a state change the queue restarts with the postponed events.
+ When <c>gen_statem</c> receives a process message it is
+ converted into an event and the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ is called with the event as two arguments: type and content.
+ When the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ has processed the event it returns to <c>gen_statem</c>
+ which does a <em>state transition</em>.
+ If this <em>state transition</em> is to a different state,
+ that is: <c>NextState =/= State</c>, it is a <em>state change</em>.
+ </p>
+ <p>
+ The
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ may return
+ <seealso marker="#type-action"><em>transition actions</em></seealso>
+ for <c>gen_statem</c>
+ to execute during the <em>state transition</em>,
+ for example to reply to a
+ <seealso marker="#call/2"><c>gen_statem:call/2,3</c></seealso>.
+ </p>
+ <p>
+ One of the possible <em>transition actions</em>
+ is to postpone the current event.
+ Then it is not retried in the current state.
+ The <c>gen_statem</c> engine keeps a queue of events
+ divided into the postponed events
+ and the events still to process.
+ After a <em>state change</em> the queue restarts
+ with the postponed events.
</p>
<p>
The <c>gen_statem</c> event queue model is sufficient
@@ -215,13 +239,17 @@ erlang:'!' -----> Module:StateName/3
to entering a new receive statement.
</p>
<p>
- The <seealso marker="#state callback">state callback</seealso>
+ The
+ <seealso marker="#state callback"><em>state callback</em></seealso>
can insert events using the
- <seealso marker="#type-action"><c>action()</c></seealso>
+ <seealso marker="#type-action"><em>transition actions</em></seealso>
<c>next_event</c>
- and such an event is inserted as the next to present
- to the state callback. That is, as if it is
- the oldest incoming event. A dedicated
+ and such an event is inserted in the event queue
+ as the next to call the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with.
+ That is, as if it is the oldest incoming event.
+ A dedicated
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>internal</c> can be used for such events making them impossible
to mistake for external events.
@@ -236,24 +264,26 @@ erlang:'!' -----> Module:StateName/3
<p>
The <c>gen_statem</c> engine can automatically
make a specialized call to the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
whenever a new state is entered; see
<seealso marker="#type-state_enter"><c>state_enter()</c></seealso>.
This is for writing code common to all state entries.
- Another way to do it is to insert an event at the state transition,
- and/or to use a dedicated state transition function,
+ Another way to do it is to explicitly insert an event
+ at the <em>state transition</em>,
+ and/or to use a dedicated <em>state transition</em> function,
but that is something you will have to remember
- at every state transition to the state(s) that need it.
+ at every <em>state transition</em> to the state(s) that need it.
</p>
<note>
<p>If you in <c>gen_statem</c>, for example, postpone
- an event in one state and then call another state callback
- of yours, you have not changed states and hence the postponed event
- is not retried, which is logical but can be confusing.
+ an event in one state and then call another <em>state callback</em>
+ of yours, you have not done a <em>state change</em>
+ and hence the postponed event is not retried,
+ which is logical but can be confusing.
</p>
</note>
<p>
- For the details of a state transition, see type
+ For the details of a <em>state transition</em>, see type
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>.
</p>
<p>
@@ -276,7 +306,8 @@ erlang:'!' -----> Module:StateName/3
The <c>gen_statem</c> process can go into hibernation; see
<seealso marker="proc_lib#hibernate/3"><c>proc_lib:hibernate/3</c></seealso>.
It is done when a
- <seealso marker="#state callback">state callback</seealso> or
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ or
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
specifies <c>hibernate</c> in the returned
<seealso marker="#type-action"><c>Actions</c></seealso>
@@ -551,7 +582,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>handle_event_function</c>,
the state can be any term.
- After a state change (<c>NextState =/= State</c>),
+ After a <em>state change</em> (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
</desc>
@@ -564,7 +595,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>,
the state must be of this type.
- After a state change (<c>NextState =/= State</c>),
+ After a <em>state change</em> (<c>NextState =/= State</c>),
all postponed events are retried.
</p>
</desc>
@@ -595,7 +626,7 @@ handle_event(_, _, State, Data) ->
</p>
<p>
<c>internal</c> events can only be generated by the
- state machine itself through the state transition action
+ state machine itself through the <em>transition action</em>
<seealso marker="#type-action"><c>next_event</c></seealso>.
</p>
</desc>
@@ -633,9 +664,9 @@ handle_event(_, _, State, Data) ->
This is the return type from
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
and selects
- <seealso marker="#type-callback_mode">callback mode</seealso>
+ <seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
and whether to do
- <seealso marker="#type-state_enter">state enter calls</seealso>,
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
or not.
</p>
</desc>
@@ -684,13 +715,15 @@ handle_event(_, _, State, Data) ->
If
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
returns a list containing <c>state_enter</c>,
- the <c>gen_statem</c> engine will, at every state change,
+ the <c>gen_statem</c> engine will, at every <em>state change</em>,
call the
<seealso marker="#state callback">state callback</seealso>
with arguments <c>(enter, OldState, Data)</c>.
This may look like an event but is really a call
- performed after the previous state callback returned
- and before any event is delivered to the new state callback.
+ performed after the previous
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ returned and before any event is delivered to the new
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
See
<seealso marker="#Module:StateName/3"><c>Module:StateName/3</c></seealso>
and
@@ -703,27 +736,27 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-state_callback_result">
<c>repeat_state_and_data</c>
</seealso>
- tuple from the state callback.
+ tuple from the <em>state callback</em>.
</p>
<p>
If
<seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
- does not return such a list, no state enter calls are done.
+ does not return such a list, no <em>state enter calls</em> are done.
</p>
<p>
If
<seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>
should transform the state,
- it is regarded as a state rename and not a state change,
- which will not cause a state enter call.
+ it is regarded as a state rename and not a <em>state change</em>,
+ which will not cause a <em>state enter call</em>.
</p>
<p>
- Note that a state enter call <em>will</em> be done
+ Note that a <em>state enter call</em> <em>will</em> be done
right before entering the initial state even though this
- formally is not a state change.
- In this case <c>OldState</c> will be the same as <c>State</c>,
+ actually is not a <em>state change</em>.
+ In this case <c>OldState =:= State</c>,
which can not happen for a subsequent state change,
- but will happen when repeating the state enter call.
+ but will happen when repeating the <em>state enter call</em>.
</p>
</desc>
</datatype>
@@ -733,8 +766,11 @@ handle_event(_, _, State, Data) ->
<p>
Transition options can be set by
<seealso marker="#type-action">actions</seealso>
- and modify the state transition.
- Here are the sequence of steps for a state transition:
+ and modify the <em>state transition</em>.
+ The <em>state transition</em> takes place when the
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ has processed an event and returns.
+ Here are the sequence of steps for a <em>state transition</em>:
</p>
<list type="ordered">
<item>
@@ -765,7 +801,7 @@ handle_event(_, _, State, Data) ->
returned by the state callback that caused the state entry.
</p>
<p>
- Should this state enter call return any of
+ Should this <em>state enter call</em> return any of
the mentioned <c>repeat_*</c> callback results
it is repeated again, with the updated <c>Data</c>.
</p>
@@ -787,7 +823,8 @@ handle_event(_, _, State, Data) ->
</item>
<item>
<p>
- If the state changes, the queue of incoming events
+ If this is a <em>state change</em>,
+ the queue of incoming events
is reset to start with the oldest postponed.
</p>
</item>
@@ -821,7 +858,7 @@ handle_event(_, _, State, Data) ->
if the event queue is empty.
</p>
<p>
- A state change cancels a
+ A <em>state change</em> cancels a
<seealso marker="#type-state_timeout"><c>state_timeout()</c></seealso>
and any new transition option of this type
belongs to the new state.
@@ -830,7 +867,7 @@ handle_event(_, _, State, Data) ->
<item>
<p>
If there are enqueued events the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
for the possibly new state
is called with the oldest enqueued event,
and we start again from the top of this list.
@@ -848,7 +885,7 @@ handle_event(_, _, State, Data) ->
the next incoming message awakens the <c>gen_statem</c>,
but if it is a system event it goes right back into hibernation.
When a new message arrives the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
is called with the corresponding event,
and we start again from the top of this sequence.
</p>
@@ -861,7 +898,7 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
If <c>true</c>, postpones the current event and retries
- it when the state changes
+ it after a <em>state change</em>
(<c>NextState =/= State</c>).
</p>
</desc>
@@ -1021,9 +1058,9 @@ handle_event(_, _, State, Data) ->
<name name="action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
when it is called with an
<seealso marker="#type-event_type">event</seealso>,
from
@@ -1054,7 +1091,7 @@ handle_event(_, _, State, Data) ->
<c>transition_option()</c>
</seealso>
<seealso marker="#type-postpone"><c>postpone()</c></seealso>
- for this state transition.
+ for this <em>state transition</em>.
This action is ignored when returned from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or given to
@@ -1093,9 +1130,9 @@ handle_event(_, _, State, Data) ->
<name name="enter_action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
@@ -1119,7 +1156,7 @@ handle_event(_, _, State, Data) ->
Sets the
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>
<seealso marker="#type-hibernate"><c>hibernate()</c></seealso>
- for this state transition.
+ for this <em>state transition</em>.
</p>
</item>
</taglist>
@@ -1129,9 +1166,9 @@ handle_event(_, _, State, Data) ->
<name name="timeout_action"/>
<desc>
<p>
- These state transition actions can be invoked by
+ These <em>transition actions</em> can be invoked by
returning them from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving them to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
@@ -1147,7 +1184,7 @@ handle_event(_, _, State, Data) ->
Short for <c>{timeout,Time,Time}</c>, that is,
the time-out message is the time-out time.
This form exists to make the
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
return value <c>{next_state,NextState,NewData,Time}</c>
allowed like for <c>gen_fsm</c>.
</p>
@@ -1193,9 +1230,9 @@ handle_event(_, _, State, Data) ->
<name name="reply_action"/>
<desc>
<p>
- This state transition action can be invoked by
+ This <em>transition action</em> can be invoked by
returning it from the
- <seealso marker="#state callback">state callback</seealso>, from
+ <seealso marker="#state callback"><em>state callback</em></seealso>, from
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
or by giving it to
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>.
@@ -1210,7 +1247,7 @@ handle_event(_, _, State, Data) ->
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
in a call to a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<p>
Note that using this action from
@@ -1219,7 +1256,7 @@ handle_event(_, _, State, Data) ->
<seealso marker="#enter_loop/5"><c>enter_loop/5,6</c></seealso>
would be weird on the border of witchcraft
since there has been no earlier call to a
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
in this server.
</p>
</desc>
@@ -1239,7 +1276,7 @@ handle_event(_, _, State, Data) ->
The <seealso marker="#type-action"><c>Actions</c></seealso>
are executed when entering the first
<seealso marker="#type-state">state</seealso> just as for a
- <seealso marker="#state callback">state callback</seealso>,
+ <seealso marker="#state callback"><em>state callback</em></seealso>,
except that the action <c>postpone</c> is forced to
<c>false</c> since there is no event to postpone.
</p>
@@ -1256,7 +1293,7 @@ handle_event(_, _, State, Data) ->
<desc>
<p>
<c><anno>State</anno></c> is the current state
- and it can not be changed since the state callback
+ and it cannot be changed since the state callback
was called with a
<seealso marker="#type-state_enter"><em>state enter call</em></seealso>.
</p>
@@ -1292,11 +1329,13 @@ handle_event(_, _, State, Data) ->
<tag><c>next_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> does a state transition to
+ The <c>gen_statem</c> does a <em>state transition</em> to
<c><anno>NextState</anno></c>
(which can be the same as the current state),
sets <c><anno>NewData</anno></c>,
and executes all <c><anno>Actions</anno></c>.
+ If <c><anno>NextState</anno> =/= CurrentState</c>
+ the <em>state transition</em> is a <em>state change</em>.
</p>
</item>
</taglist>
@@ -1318,54 +1357,33 @@ handle_event(_, _, State, Data) ->
<tag><c>keep_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state, or
- does a state transition to the current state if you like,
- sets <c><anno>NewData</anno></c>,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
+ The same as
<c>{next_state,CurrentState,<anno>NewData</anno>,<anno>Actions</anno>}</c>.
</p>
</item>
<tag><c>keep_state_and_data</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state or
- does a state transition to the current state if you like,
- keeps the current server data,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
- <c>{next_state,CurrentState,CurrentData,<anno>Actions</anno>}</c>.
+ The same as
+ <c>{keep_state,CurrentData,<anno>Actions</anno>}</c>.
</p>
</item>
<tag><c>repeat_state</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state, or
- does a state transition to the current state if you like,
- sets <c><anno>NewData</anno></c>,
- and executes all <c><anno>Actions</anno></c>.
If the <c>gen_statem</c> runs with
<seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
- the state enter call is repeated, see type
+ the <em>state enter call</em> is repeated, see type
<seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
- otherwise <c>repeat_state</c> is the same as
+ other than that <c>repeat_state</c> is the same as
<c>keep_state</c>.
</p>
</item>
<tag><c>repeat_state_and_data</c></tag>
<item>
<p>
- The <c>gen_statem</c> keeps the current state and data, or
- does a state transition to the current state if you like,
- and executes all <c><anno>Actions</anno></c>.
- This is the same as
+ The same as
<c>{repeat_state,CurrentData,<anno>Actions</anno>}</c>.
- If the <c>gen_statem</c> runs with
- <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
- the state enter call is repeated, see type
- <seealso marker="#type-transition_option"><c>transition_option()</c></seealso>,
- otherwise <c>repeat_state_and_data</c> is the same as
- <c>keep_state_and_data</c>.
</p>
</item>
<tag><c>stop</c></tag>
@@ -1408,14 +1426,15 @@ handle_event(_, _, State, Data) ->
by sending a request
and waiting until its reply arrives.
The <c>gen_statem</c> calls the
- <seealso marker="#state callback">state callback</seealso> with
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>{call,From}</c> and event content
<c><anno>Request</anno></c>.
</p>
<p>
A <c><anno>Reply</anno></c> is generated when a
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
returns with
<c>{reply,From,<anno>Reply</anno>}</c> as one
<seealso marker="#type-action"><c>action()</c></seealso>,
@@ -1484,7 +1503,8 @@ handle_event(_, _, State, Data) ->
ignoring if the destination node or <c>gen_statem</c>
does not exist.
The <c>gen_statem</c> calls the
- <seealso marker="#state callback">state callback</seealso> with
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ with
<seealso marker="#type-event_type"><c>event_type()</c></seealso>
<c>cast</c> and event content
<c><anno>Msg</anno></c>.
@@ -1598,18 +1618,18 @@ handle_event(_, _, State, Data) ->
<seealso marker="#call/2"><c>call/2</c></seealso>
when the reply cannot be defined in
the return value of a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<p>
<c><anno>From</anno></c> must be the term from argument
<seealso marker="#type-event_type"><c>{call,<anno>From</anno>}</c></seealso>
to the
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
A reply or multiple replies canalso be sent
using one or several
<seealso marker="#type-reply_action"><c>reply_action()</c></seealso>s
from a
- <seealso marker="#state callback">state callback</seealso>.
+ <seealso marker="#state callback"><em>state callback</em></seealso>.
</p>
<note>
<p>
@@ -1826,7 +1846,7 @@ handle_event(_, _, State, Data) ->
for efficiency reasons, so this function is only called
once after server start and after code change,
but before the first
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
in the current code version is called.
More occasions may be added in future versions
of <c>gen_statem</c>.
@@ -1883,7 +1903,7 @@ handle_event(_, _, State, Data) ->
<p>
This callback is optional, so callback modules need not export it.
If a release upgrade/downgrade with
- <c>Change={advanced,Extra}</c>
+ <c>Change = {advanced,Extra}</c>
specified in the <c>.appup</c> file is made
when <c>code_change/4</c> is not implemented
the process will crash with exit reason <c>undef</c>.
@@ -1893,7 +1913,7 @@ handle_event(_, _, State, Data) ->
This function is called by a <c>gen_statem</c> when it is to
update its internal state during a release upgrade/downgrade,
that is, when the instruction <c>{update,Module,Change,...}</c>,
- where <c>Change={advanced,Extra}</c>, is specified in the
+ where <c>Change = {advanced,Extra}</c>, is specified in the
<seealso marker="sasl:appup"><c>appup</c></seealso>
file. For more information, see
<seealso marker="doc/design_principles:release_handling#instr">OTP Design Principles</seealso>.
@@ -1922,7 +1942,7 @@ handle_event(_, _, State, Data) ->
<p>
If the function returns a failure <c>Reason</c>, the ongoing
upgrade fails and rolls back to the old release.
- Note that <c>Reason</c> can not be an <c>{ok,_,_}</c> tuple
+ Note that <c>Reason</c> cannot be an <c>{ok,_,_}</c> tuple
since that will be regarded as a
<c>{ok,NewState,NewData}</c> tuple,
and that a tuple matching <c>{ok,_}</c>
@@ -1933,13 +1953,13 @@ handle_event(_, _, State, Data) ->
<p>
Also note when upgrading a <c>gen_statem</c>,
this function and hence
- the <c>Change={advanced,Extra}</c> parameter in the
+ the <c>Change = {advanced,Extra}</c> parameter in the
<seealso marker="sasl:appup"><c>appup</c></seealso> file
is not only needed to update the internal state
or to act on the <c>Extra</c> argument.
It is also needed if an upgrade or downgrade should change
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>,
- or else the callback mode after the code change
+ or else the <em>callback mode</em> after the code change
will not be honoured,
most probably causing a server crash.
</p>
@@ -2148,7 +2168,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<seealso marker="#type-event_type"><c>{call,From}</c></seealso>,
the caller waits for a reply. The reply can be sent
from this or from any other
- <seealso marker="#state callback">state callback</seealso>
+ <seealso marker="#state callback"><em>state callback</em></seealso>
by returning with <c>{reply,From,Reply}</c> in
<seealso marker="#type-action"><c>Actions</c></seealso>, in
<seealso marker="#type-reply_action"><c>Replies</c></seealso>,
@@ -2173,9 +2193,9 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
</p>
<p>
When the <c>gen_statem</c> runs with
- <seealso marker="#type-state_enter">state enter calls</seealso>,
+ <seealso marker="#type-state_enter"><em>state enter calls</em></seealso>,
these functions are also called with arguments
- <c>(enter, OldState, ...)</c> whenever the state changes.
+ <c>(enter, OldState, ...)</c> during every <em>state change</em>.
In this case there are some restrictions on the
<seealso marker="#type-enter_action">actions</seealso>
that may be returned:
@@ -2208,7 +2228,7 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<seealso marker="erts:erlang#throw/1"><c>throw</c></seealso>
to return the result, which can be useful.
For example to bail out with <c>throw(keep_state_and_data)</c>
- from deep within complex code that can not
+ from deep within complex code that cannot
return <c>{next_state,State,Data}</c> because
<c>State</c> or <c>Data</c> is no longer in scope.
</p>
diff --git a/lib/stdlib/doc/src/maps.xml b/lib/stdlib/doc/src/maps.xml
index a225dea3b5..4c5199ca2b 100644
--- a/lib/stdlib/doc/src/maps.xml
+++ b/lib/stdlib/doc/src/maps.xml
@@ -35,9 +35,10 @@
<datatypes>
<datatype>
- <name name="iterator"/>
+ <name name="iterator" n_vars="2"/>
<desc>
- <p>An iterator representing the key value associations in a map.</p>
+ <p>An iterator representing the associations in a map with keys of type
+ <c><anno>Key</anno></c> and values of type <c><anno>Value</anno></c>.</p>
<p>Created using <seealso marker="#iterator-1"><c>maps:iterator/1</c></seealso>.</p>
<p>Consumed by <seealso marker="#next-1"><c>maps:next/1</c></seealso>,
<seealso marker="#filter-2"><c>maps:filter/2</c></seealso>,
@@ -45,6 +46,10 @@
<seealso marker="#map-2"><c>maps:map/2</c></seealso>.</p>
</desc>
</datatype>
+
+ <datatype>
+ <name name="iterator" n_vars="0"/>
+ </datatype>
</datatypes>
<funcs>
@@ -90,13 +95,13 @@
<name name="fold" arity="3"/>
<fsummary></fsummary>
<desc>
- <p>Calls <c>F(K, V, AccIn)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V</anno></c> association in <c><anno>MapOrIter</anno></c> in
- any order. Function <c>fun F/3</c> must return a new
- accumulator, which is passed to the next successive call.
- This function returns the final value of the accumulator. The initial
- accumulator value <c><anno>Init</anno></c> is returned if the map is
- empty.</p>
+ <p>Calls <c>F(Key, Value, AccIn)</c> for every <c><anno>Key</anno></c>
+ to value <c><anno>Value</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun F/3</c>
+ must return a new accumulator, which is passed to the next successive
+ call. This function returns the final value of the accumulator.
+ The initial accumulator value <c><anno>Init</anno></c> is returned
+ if the map is empty.</p>
<p>The call fails with a <c>{badmap,Map}</c> exception if
<c><anno>MapOrIter</anno></c> is not a map or valid iterator,
or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
@@ -234,11 +239,12 @@ none</code>
<fsummary></fsummary>
<desc>
<p>Produces a new map <c><anno>Map</anno></c> by calling function
- <c>fun F(K, V1)</c> for every <c><anno>K</anno></c> to value
- <c><anno>V1</anno></c> association in <c><anno>MapOrIter</anno></c> in
- any order. Function <c>fun F/2</c> must return value
- <c><anno>V2</anno></c> to be associated with key <c><anno>K</anno></c>
- for the new map <c><anno>Map</anno></c>.</p>
+ <c>fun F(Key, Value1)</c> for every <c><anno>Key</anno></c> to value
+ <c><anno>Value1</anno></c> association in
+ <c><anno>MapOrIter</anno></c> in any order. Function <c>fun Fun/2</c>
+ must return value <c><anno>Value2</anno></c> to be associated with
+ key <c><anno>Key</anno></c> for the new map
+ <c><anno>Map</anno></c>.</p>
<p>The call fails with a <c>{badmap,Map}</c> exception if
<c><anno>MapOrIter</anno></c> is not a map or valid iterator,
or with <c>badarg</c> if <c><anno>Fun</anno></c> is not a
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index 712a474b0b..318643aef8 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,41 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>The specs of <c>filename:basedir/2,3</c> are
+ corrected.</p>
+ <p>
+ Own Id: OTP-15252 Aux Id: ERL-667 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Let <c>dets:open_file()</c> exit with a <c>badarg</c>
+ message if given a raw file name (a binary). </p>
+ <p>
+ Own Id: OTP-15253 Aux Id: OTP-13229, ERL-55 </p>
+ </item>
+ <item>
+ <p> The <c>Format</c> argument of the formatting
+ functions in modules <c>io</c> and <c>io_lib</c> is
+ accepted even if it is, for example, a list of binaries.
+ This is how it used to be before Erlang/OTP 21.0. </p>
+ <p>
+ Own Id: OTP-15304</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -3659,7 +3694,7 @@
you use erlang:halt/2 with an integer first argument and
an option list containing {flush,false} as the second
argument. Note that now is flushing not dependant of the
- exit code, and you can not only flush async threads
+ exit code, and you cannot only flush async threads
operations which we deemed as a strange behaviour anyway.
</p>
<p>Also, erlang:halt/1,2 has gotten a new feature: If the
@@ -4173,9 +4208,9 @@
Supervisors should not save child-specs for temporary
processes when they terminate as they should not be
restarted. Saving the temporary child spec will result in
- that you can not start a new temporary process with the
+ that you cannot start a new temporary process with the
same child spec as an already terminated temporary
- process. Since R14B02 you can not restart a temporary
+ process. Since R14B02 you cannot restart a temporary
temporary process as arguments are no longer saved, it
has however always been semantically incorrect to restart
a temporary process. Thanks to Filipe David Manana for
diff --git a/lib/stdlib/doc/src/rand.xml b/lib/stdlib/doc/src/rand.xml
index 21f680a0ee..8e657698c6 100644
--- a/lib/stdlib/doc/src/rand.xml
+++ b/lib/stdlib/doc/src/rand.xml
@@ -38,25 +38,71 @@
<p>
This module provides a pseudo random number generator.
The module contains a number of algorithms.
- The uniform distribution algorithms use the
+ The uniform distribution algorithms are based on the
<url href="http://xorshift.di.unimi.it">
- xoroshiro116+ and xorshift1024* algorithms by Sebastiano Vigna.
+ Xoroshiro and Xorshift algorithms
</url>
+ by Sebastiano Vigna.
The normal distribution algorithm uses the
<url href="http://www.jstatsoft.org/v05/i08">
Ziggurat Method by Marsaglia and Tsang
</url>
on top of the uniform distribution algorithm.
</p>
- <p>For some algorithms, jump functions are provided for generating
- non-overlapping sequences for parallel computations.
- The jump functions perform calculations
- equivalent to perform a large number of repeated calls
- for calculating new states. </p>
+ <p>
+ For most algorithms, jump functions are provided for generating
+ non-overlapping sequences for parallel computations.
+ The jump functions perform calculations
+ equivalent to perform a large number of repeated calls
+ for calculating new states.
+ </p>
<p>The following algorithms are provided:</p>
<taglist>
+ <tag><c>exsss</c></tag>
+ <item>
+ <p>Xorshift116**, 58 bits precision and period of 2^116-1</p>
+ <p>Jump function: equivalent to 2^64 calls</p>
+ <p>
+ This is the Xorshift116 generator combined with the StarStar scrambler
+ from the 2018 paper by David Blackman and Sebastiano Vigna:
+ <url href="http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf">
+ Scrambled Linear Pseudorandom Number Generators
+ </url>
+ </p>
+ <p>
+ The generator does not need 58-bit rotates so it is faster
+ than the Xoroshiro116 generator, and when combined with
+ the StarStar scrambler it does not have any weak low bits
+ like <c>exrop</c> (Xoroshiro116+).
+ </p>
+ <p>
+ Alas, this combination is about 10% slower than <c>exrop</c>,
+ but is despite that the default algorithm thanks to its
+ statistical qualities.
+ </p>
+ </item>
+ <tag><c>exro928ss</c></tag>
+ <item>
+ <p>Xoroshiro928**, 58 bits precision and a period of 2^928-1</p>
+ <p>Jump function: equivalent to 2^512 calls</p>
+ <p>
+ This is a 58 bit version of Xoroshiro1024**,
+ from the 2018 paper by David Blackman and Sebastiano Vigna:
+ <url href="http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf">
+ Scrambled Linear Pseudorandom Number Generators
+ </url>
+ that on a 64 bit Erlang system executes only about 40% slower than
+ the default <c>exsss</c> algorithm but with much longer period
+ and better statistical properties, and on the flip side
+ a larger state.
+ </p>
+ <p>
+ Many thanks to Sebastiano Vigna for his help with
+ the 58 bit adaption.
+ </p>
+ </item>
<tag><c>exrop</c></tag>
<item>
<p>Xoroshiro116+, 58 bits precision and period of 2^116-1</p>
@@ -83,7 +129,7 @@
</taglist>
<p>
- The default algorithm is <c>exrop</c> (Xoroshiro116+).
+ The default algorithm is <c>exsss</c> (Xorshift116**).
If a specific algorithm is
required, ensure to always use <seealso marker="#seed-1">
<c>seed/1</c></seealso> to initialize the state.
@@ -154,19 +200,19 @@ R1 = rand:uniform(),</pre>
<p>Use a specified algorithm:</p>
<pre>
-_ = rand:seed(exs1024s),
+_ = rand:seed(exs928ss),
R2 = rand:uniform(),</pre>
<p>Use a specified algorithm with a constant seed:</p>
<pre>
-_ = rand:seed(exs1024s, {123, 123534, 345345}),
+_ = rand:seed(exs928ss, {123, 123534, 345345}),
R3 = rand:uniform(),</pre>
<p>Use the functional API with a non-constant seed:</p>
<pre>
-S0 = rand:seed_s(exrop),
+S0 = rand:seed_s(exsss),
{R4, S1} = rand:uniform_s(S0),</pre>
<p>Textbook basic form Box-Muller standard normal deviate</p>
@@ -195,8 +241,9 @@ SND0 = math:sqrt(-2 * math:log(R5)) * math:cos(math:pi() * R6)</pre>
</note>
<p>
- For all these generators the lowest bit(s) has got
- a slightly less random behaviour than all other bits.
+ For all these generators except <c>exro928ss</c> and <c>exsss</c>
+ the lowest bit(s) has got a slightly less
+ random behaviour than all other bits.
1 bit for <c>exrop</c> (and <c>exsp</c>),
and 3 bits for <c>exs1024s</c>.
See for example the explanation in the
@@ -211,7 +258,7 @@ up to (and included) 16TB, with the exception of binary rank tests,
which fail due to the lowest bit being an LFSR; all other bits pass all
tests. We suggest to use a sign test to extract a random Boolean value.</pre>
<p>
- If this is a problem; to generate a boolean
+ If this is a problem; to generate a boolean with these algorithms
use something like this:
</p>
<pre>(rand:uniform(16) > 8)</pre>
@@ -254,21 +301,50 @@ tests. We suggest to use a sign test to extract a random Boolean value.</pre>
</desc>
</datatype>
<datatype>
- <name name="exs64_state"/>
- <desc><p>Algorithm specific internal state</p></desc>
+ <name name="seed"/>
+ <desc>
+ <p>
+ A seed value for the generator.
+ </p>
+ <p>
+ A list of integers sets the generator's internal state directly,
+ after algorithm-dependent checks of the value
+ and masking to the proper word size.
+ </p>
+ <p>
+ An integer is used as the initial state for a SplitMix64 generator.
+ The output values of that is then used for setting
+ the generator's internal state
+ after masking to the proper word size
+ and if needed avoiding zero values.
+ </p>
+ <p>
+ A traditional 3-tuple of integers seed is passed through
+ algorithm-dependent hashing functions to create
+ the generator's initial state.
+ </p>
+ </desc>
</datatype>
<datatype>
<name name="exsplus_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
<datatype>
- <name name="exs1024_state"/>
+ <name name="exro928_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
<datatype>
<name name="exrop_state"/>
<desc><p>Algorithm specific internal state</p></desc>
</datatype>
+ <datatype>
+ <name name="exs1024_state"/>
+ <desc><p>Algorithm specific internal state</p></desc>
+ </datatype>
+ <datatype>
+ <name name="exs64_state"/>
+ <desc><p>Algorithm specific internal state</p></desc>
+ </datatype>
</datatypes>
<funcs>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index 6d5065ca02..5fd5760499 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2017</year>
+ <year>1996</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -208,8 +208,16 @@ child_spec() = #{id => child_id(), % mandatory
the child process is unconditionally terminated using
<c>exit(Child,kill)</c>.</p>
<p>If the child process is another supervisor, the shutdown time
- is to be set to <c>infinity</c> to give the subtree ample
- time to shut down. It is also allowed to set it to <c>infinity</c>,
+ must be set to <c>infinity</c> to give the subtree ample
+ time to shut down.</p>
+ <warning>
+ <p>Setting the shutdown time to anything other
+ than <c>infinity</c> for a child of type <c>supervisor</c>
+ can cause a race condition where the child in question
+ unlinks its own children, but fails to terminate them
+ before it is killed.</p>
+ </warning>
+ <p>It is also allowed to set it to <c>infinity</c>,
if the child process is a worker.</p>
<warning>
<p>Be careful when setting the shutdown time to
diff --git a/lib/stdlib/include/assert.hrl b/lib/stdlib/include/assert.hrl
index 2ec89e7d8a..28d25c6589 100644
--- a/lib/stdlib/include/assert.hrl
+++ b/lib/stdlib/include/assert.hrl
@@ -140,7 +140,7 @@
-endif.
%% This is mostly a convenience which gives more detailed reports.
-%% Note: Guard is a guarded pattern, and can not be used for value.
+%% Note: Guard is a guarded pattern, and cannot be used for value.
-ifdef(NOASSERT).
-define(assertMatch(Guard, Expr), ok).
-define(assertMatch(Guard, Expr, Comment), ok).
@@ -289,7 +289,7 @@
end).
-endif.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Term can be a guarded pattern, but Class cannot.
-ifdef(NOASSERT).
-define(assertException(Class, Term, Expr), ok).
@@ -364,7 +364,7 @@
?assertException(throw, Term, Expr, Comment)).
%% This is the inverse case of assertException, for convenience.
-%% Note: Class and Term are patterns, and can not be used for value.
+%% Note: Class and Term are patterns, and cannot be used for value.
%% Both Class and Term can be guarded patterns.
-ifdef(NOASSERT).
-define(assertNotException(Class, Term, Expr), ok).
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index 01181b1097..3386cfcbe6 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -53,7 +53,7 @@
%%-------------------------------------------------------------------------
--type beam() :: module() | file:filename() | binary().
+-type beam() :: file:filename() | binary().
-type debug_info() :: {DbgiVersion :: atom(), Backend :: module(), Data :: term()} | 'no_debug_info'.
-type forms() :: [erl_parse:abstract_form() | erl_parse:form_info()].
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index e016d5a80e..0488c2bef2 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -616,12 +616,18 @@ next(Tab, Key) ->
%% Assuming that a file already exists, open it with the
%% parameters as already specified in the file itself.
%% Return a ref leading to the file.
-open_file(File) ->
- case dets_server:open_file(to_list(File)) of
- badarg -> % Should not happen.
- erlang:error(dets_process_died, [File]);
- Reply ->
- einval(Reply, [File])
+open_file(File0) ->
+ File = to_list(File0),
+ case is_list(File) of
+ true ->
+ case dets_server:open_file(File) of
+ badarg -> % Should not happen.
+ erlang:error(dets_process_died, [File]);
+ Reply ->
+ einval(Reply, [File])
+ end;
+ false ->
+ erlang:error(badarg, [File0])
end.
-spec open_file(Name, Args) -> {'ok', Name} | {'error', Reason} when
@@ -1088,6 +1094,7 @@ defaults(Tab, Args) ->
debug = false},
Fun = fun repl/2,
Defaults = lists:foldl(Fun, Defaults0, Args),
+ true = is_list(Defaults#open_args.file),
is_comp_min_max(Defaults).
to_list(T) when is_atom(T) -> atom_to_list(T);
@@ -1112,9 +1119,7 @@ repl({delayed_write, {Delay,Size} = C}, Defs)
Defs#open_args{delayed_write = C};
repl({estimated_no_objects, I}, Defs) ->
repl({min_no_slots, I}, Defs);
-repl({file, File}, Defs) when is_list(File) ->
- Defs#open_args{file = File};
-repl({file, File}, Defs) when is_atom(File) ->
+repl({file, File}, Defs) ->
Defs#open_args{file = to_list(File)};
repl({keypos, P}, Defs) when is_integer(P), P > 0 ->
Defs#open_args{keypos =P};
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index cc34d4bdd3..181a524db6 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -117,6 +117,7 @@ open(Name, File, StartLocation, Path, Pdm) ->
{'ok', Epp} | {'ok', Epp, Extra} | {'error', ErrorDescriptor} when
Options :: [{'default_encoding', DefEncoding :: source_encoding()} |
{'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'source_name', SourceName :: file:name()} |
{'macros', PredefMacros :: macros()} |
{'name',FileName :: file:name()} |
'extra'],
@@ -248,6 +249,7 @@ parse_file(Ifile, Path, Predefs) ->
{'ok', [Form]} | {'ok', [Form], Extra} | {error, OpenError} when
FileName :: file:name(),
Options :: [{'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'source_name', SourceName :: file:name()} |
{'macros', PredefMacros :: macros()} |
{'default_encoding', DefEncoding :: source_encoding()} |
'extra'],
@@ -540,9 +542,10 @@ server(Pid, Name, Options, #epp{pre_opened=PreOpened}=St) ->
init_server(Pid, Name, Options, St)
end.
-init_server(Pid, Name, Options, St0) ->
+init_server(Pid, FileName, Options, St0) ->
+ SourceName = proplists:get_value(source_name, Options, FileName),
Pdm = proplists:get_value(macros, Options, []),
- Ms0 = predef_macros(Name),
+ Ms0 = predef_macros(FileName),
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
#epp{file = File, location = AtLocation} = St0,
@@ -552,14 +555,14 @@ init_server(Pid, Name, Options, St0) ->
epp_reply(Pid, {ok,self(),Encoding}),
%% ensure directory of current source file is
%% first in path
- Path = [filename:dirname(Name) |
+ Path = [filename:dirname(FileName) |
proplists:get_value(includes, Options, [])],
- St = St0#epp{delta=0, name=Name, name2=Name,
+ St = St0#epp{delta=0, name=SourceName, name2=SourceName,
path=Path, macs=Ms1,
default_encoding=DefEncoding},
From = wait_request(St),
Anno = erl_anno:new(AtLocation),
- enter_file_reply(From, file_name(Name), Anno,
+ enter_file_reply(From, file_name(SourceName), Anno,
AtLocation, code),
wait_req_scan(St);
{error,E} ->
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index b311a843c2..939abaff00 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -74,6 +74,7 @@ guard_bif(element, 2) -> true;
guard_bif(float, 1) -> true;
guard_bif(floor, 1) -> true;
guard_bif(hd, 1) -> true;
+guard_bif(is_map_key, 2) -> true;
guard_bif(length, 1) -> true;
guard_bif(map_size, 1) -> true;
guard_bif(map_get, 2) -> true;
@@ -109,7 +110,6 @@ new_type_test(is_function, 2) -> true;
new_type_test(is_integer, 1) -> true;
new_type_test(is_list, 1) -> true;
new_type_test(is_map, 1) -> true;
-new_type_test(is_map_key, 2) -> true;
new_type_test(is_number, 1) -> true;
new_type_test(is_pid, 1) -> true;
new_type_test(is_port, 1) -> true;
diff --git a/lib/stdlib/src/erl_posix_msg.erl b/lib/stdlib/src/erl_posix_msg.erl
index 8959fea498..b9ed4a3a9d 100644
--- a/lib/stdlib/src/erl_posix_msg.erl
+++ b/lib/stdlib/src/erl_posix_msg.erl
@@ -81,9 +81,9 @@ message_1(el2hlt) -> <<"level 2 halted">>;
message_1(el2nsync) -> <<"level 2 not synchronized">>;
message_1(el3hlt) -> <<"level 3 halted">>;
message_1(el3rst) -> <<"level 3 reset">>;
-message_1(elibacc) -> <<"can not access a needed shared library">>;
+message_1(elibacc) -> <<"cannot access a needed shared library">>;
message_1(elibbad) -> <<"accessing a corrupted shared library">>;
-message_1(elibexec) -> <<"can not exec a shared library directly">>;
+message_1(elibexec) -> <<"cannot exec a shared library directly">>;
message_1(elibmax) ->
<<"attempting to link in more shared libraries than system limit">>;
message_1(elibscn) -> <<".lib section in a.out corrupted">>;
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index a322bd002d..b7b7b562ab 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -1012,24 +1012,33 @@ filename_string_to_binary(List) ->
%% basedir
%% http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
--type basedir_type() :: 'user_cache' | 'user_config' | 'user_data'
- | 'user_log'
- | 'site_config' | 'site_data'.
+-type basedir_path_type() :: 'user_cache' | 'user_config' | 'user_data'
+ | 'user_log'.
+-type basedir_paths_type() :: 'site_config' | 'site_data'.
--spec basedir(Type,Application) -> file:filename_all() when
- Type :: basedir_type(),
+-type basedir_opts() :: #{author => string() | binary(),
+ os => 'windows' | 'darwin' | 'linux',
+ version => string() | binary()}.
+
+-spec basedir(PathType,Application) -> file:filename_all() when
+ PathType :: basedir_path_type(),
+ Application :: string() | binary();
+ (PathsType,Application) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
Application :: string() | binary().
basedir(Type,Application) when is_atom(Type), is_list(Application) orelse
is_binary(Application) ->
basedir(Type, Application, #{}).
--spec basedir(Type,Application,Opts) -> file:filename_all() when
- Type :: basedir_type(),
+-spec basedir(PathType,Application,Opts) -> file:filename_all() when
+ PathType :: basedir_path_type(),
+ Application :: string() | binary(),
+ Opts :: basedir_opts();
+ (PathsType,Application,Opts) -> [file:filename_all()] when
+ PathsType :: basedir_paths_type(),
Application :: string() | binary(),
- Opts :: #{author => string() | binary(),
- os => 'windows' | 'darwin' | 'linux',
- version => string() | binary()}.
+ Opts :: basedir_opts().
basedir(Type,Application,Opts) when is_atom(Type), is_map(Opts),
is_list(Application) orelse
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index faa43fbc1e..24b268cd38 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -330,6 +330,7 @@
%% Type validation functions
+%% - return true if the value is of the type, false otherwise
-compile(
{inline,
[callback_mode/1, state_enter/1,
@@ -1277,7 +1278,7 @@ parse_actions(StateCall, Debug, S, [Action|Actions], TransOpts) ->
end.
parse_actions_reply(
- StateCall, ?not_sys_debug, S, Actions, TransOpts,
+ StateCall, ?not_sys_debug = Debug, S, Actions, TransOpts,
From, Reply) ->
%%
case from(From) of
@@ -1287,8 +1288,7 @@ parse_actions_reply(
false ->
[error,
{bad_action_from_state_function,{reply,From,Reply}},
- ?STACKTRACE(),
- ?not_sys_debug]
+ ?STACKTRACE(), Debug]
end;
parse_actions_reply(
StateCall, Debug, #state{name = Name, state = State} = S,
@@ -1302,12 +1302,11 @@ parse_actions_reply(
false ->
[error,
{bad_action_from_state_function,{reply,From,Reply}},
- ?STACKTRACE(),
- Debug]
+ ?STACKTRACE(), Debug]
end.
parse_actions_next_event(
- StateCall, ?not_sys_debug, S,
+ StateCall, ?not_sys_debug = Debug, S,
Actions, TransOpts, Type, Content) ->
case event_type(Type) of
true when StateCall ->
@@ -1320,8 +1319,7 @@ parse_actions_next_event(
[error,
{bad_state_enter_action_from_state_function,
{next_event,Type,Content}},
- ?STACKTRACE(),
- ?not_sys_debug]
+ ?STACKTRACE(), Debug]
end;
parse_actions_next_event(
StateCall, Debug, #state{name = Name, state = State} = S,
@@ -1403,13 +1401,13 @@ parse_actions_timeout_add(
loop_event_done(
Parent, ?not_sys_debug,
#state{postponed = P} = S,
+%% #state{postponed = will_not_happen = P} = S,
Events, Event, NextState, NewData,
#trans_opts{
postpone = Postpone, hibernate = Hibernate,
- timeouts_r = [], next_events_r = []}) ->
+ timeouts_r = [], next_events_r = NextEventsR}) ->
%%
- %% Optimize the simple cases
- %% i.e no timer changes, no inserted events and no debug,
+ %% Optimize the simple cases i.e no debug and no timer changes,
%% by duplicate stripped down code
%%
%% Fast path
@@ -1417,14 +1415,12 @@ loop_event_done(
case Postpone of
true ->
loop_event_done_fast(
- Parent, Hibernate,
- S,
- Events, [Event|P], NextState, NewData);
+ Parent, Hibernate, S,
+ Events, [Event|P], NextState, NewData, NextEventsR);
false ->
loop_event_done_fast(
- Parent, Hibernate,
- S,
- Events, P, NextState, NewData)
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR)
end;
loop_event_done(
Parent, Debug_0,
@@ -1456,26 +1452,23 @@ loop_event_done(
{S#state.name,State},
{consume,Event_0,NextState})|P_0]
end,
- {Events_2,P_2,Timers_2} =
- %% Move all postponed events to queue,
- %% cancel the event timer,
- %% and cancel the state timeout if the state changes
- if
- NextState =:= State ->
- {Events_0,P_1,
+ {Events_2,P_2,
+ Timers_2} =
+ %% Cancel the event timeout
+ if
+ NextState =:= State ->
+ {Events_0,P_1,
cancel_timer_by_type(
timeout, {TimerTypes_0,CancelTimers_0})};
- true ->
- {lists:reverse(P_1, Events_0),
- [],
- cancel_timer_by_type(
- state_timeout,
+ true ->
+ %% Move all postponed events to queue
+ %% and cancel the state timeout
+ {lists:reverse(P_1, Events_0),[],
+ cancel_timer_by_type(
+ state_timeout,
cancel_timer_by_type(
timeout, {TimerTypes_0,CancelTimers_0}))}
- %% The state timer is removed from TimerTypes
- %% but remains in TimerRefs until we get
- %% the cancel_timer msg
- end,
+ end,
{TimerRefs_3,{TimerTypes_3,CancelTimers_3},TimeoutEvents} =
%% Stop and start timers
parse_timers(TimerRefs_0, Timers_2, TimeoutsR),
@@ -1495,114 +1488,144 @@ loop_event_done(
hibernate = Hibernate},
lists:reverse(Events_4R)).
+loop_event_done(Parent, Debug, S, Q) ->
+%% io:format(
+%% "loop_event_done:~n"
+%% " state = ~p, data = ~p, postponed = ~p~n "
+%% " timer_refs = ~p, timer_types = ~p, cancel_timers = ~p.~n"
+%% " Q = ~p.~n",
+%% [S#state.state,S#state.data,S#state.postponed,
+%% S#state.timer_refs,S#state.timer_types,S#state.cancel_timers,
+%% Q]),
+ case Q of
+ [] ->
+ %% Get a new event
+ loop(Parent, Debug, S);
+ [{Type,Content}|Events] ->
+ %% Loop until out of enqueued events
+ loop_event(Parent, Debug, S, Events, Type, Content)
+ end.
+
+
%% Fast path
%%
+%% Cancel event timer and state timer only if running
loop_event_done_fast(
Parent, Hibernate,
#state{
state = NextState,
- timer_types = #{timeout := _} = TimerTypes,
+ timer_types = TimerTypes,
cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
- %%
- %% Same state, event timeout active
- %%
- loop_event_done_fast(
- Parent, Hibernate, S,
- Events, P, NextState, NewData,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers}));
-loop_event_done_fast(
- Parent, Hibernate,
- #state{state = NextState} = S,
- Events, P, NextState, NewData) ->
- %%
+ Events, P, NextState, NewData, NextEventsR) ->
%% Same state
- %%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- data = NewData,
- postponed = P,
- hibernate = Hibernate},
- Events);
-loop_event_done_fast(
- Parent, Hibernate,
- #state{
- timer_types = #{timeout := _} = TimerTypes,
- cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
- %%
- %% State change, event timeout active
- %%
- loop_event_done_fast(
- Parent, Hibernate, S,
- lists:reverse(P, Events), [], NextState, NewData,
- cancel_timer_by_type(
- state_timeout,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers})));
+ case TimerTypes of
+ #{timeout := _} ->
+ %% Event timeout active
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR,
+ cancel_timer_by_type(
+ timeout, {TimerTypes,CancelTimers}));
+ _ ->
+ %% No event timeout active
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR,
+ {TimerTypes,CancelTimers})
+ end;
loop_event_done_fast(
Parent, Hibernate,
#state{
- timer_types = #{state_timeout := _} = TimerTypes,
+ timer_types = TimerTypes,
cancel_timers = CancelTimers} = S,
- Events, P, NextState, NewData) ->
- %%
- %% State change, state timeout active
- %%
- loop_event_done_fast(
- Parent, Hibernate, S,
- lists:reverse(P, Events), [], NextState, NewData,
- cancel_timer_by_type(
- state_timeout,
- cancel_timer_by_type(
- timeout, {TimerTypes,CancelTimers})));
+ Events, P, NextState, NewData, NextEventsR) ->
+ %% State change
+ case TimerTypes of
+ #{timeout := _} ->
+ %% Event timeout active
+ %% - cancel state_timeout too since it is faster than inspecting
+ loop_event_done_fast(
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR,
+ cancel_timer_by_type(
+ state_timeout,
+ cancel_timer_by_type(
+ timeout, {TimerTypes,CancelTimers})));
+ #{state_timeout := _} ->
+ %% State_timeout active but not event timeout
+ loop_event_done_fast(
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR,
+ cancel_timer_by_type(
+ state_timeout, {TimerTypes,CancelTimers}));
+ _ ->
+ %% No event nor state_timeout active
+ loop_event_done_fast(
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR,
+ {TimerTypes,CancelTimers})
+ end.
+%%
+%% Retry postponed events
loop_event_done_fast(
- Parent, Hibernate,
- #state{} = S,
- Events, P, NextState, NewData) ->
- %%
- %% State change, no timeout to automatically cancel
- %%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- state = NextState,
- data = NewData,
- postponed = [],
- hibernate = Hibernate},
- lists:reverse(P, Events)).
+ Parent, Hibernate, S,
+ Events, P, NextState, NewData, NextEventsR, TimerTypes_CancelTimers) ->
+ case P of
+ %% Handle 0..2 postponed events without list reversal since
+ %% that will move out all live registers and back again
+ [] ->
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ Events, [], NextState, NewData, NextEventsR,
+ TimerTypes_CancelTimers);
+ [E] ->
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ [E|Events], [], NextState, NewData, NextEventsR,
+ TimerTypes_CancelTimers);
+ [E1,E2] ->
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ [E2,E1|Events], [], NextState, NewData, NextEventsR,
+ TimerTypes_CancelTimers);
+ _ ->
+ %% A bit slower path
+ loop_event_done_fast_2(
+ Parent, Hibernate, S,
+ lists:reverse(P, Events), [], NextState, NewData, NextEventsR,
+ TimerTypes_CancelTimers)
+ end.
%%
%% Fast path
%%
-loop_event_done_fast(
+loop_event_done_fast_2(
Parent, Hibernate, S,
- Events, P, NextState, NewData,
+ Events, P, NextState, NewData, NextEventsR,
{TimerTypes,CancelTimers}) ->
%%
- loop_event_done(
- Parent, ?not_sys_debug,
- S#state{
- state = NextState,
- data = NewData,
- postponed = P,
- timer_types = TimerTypes,
- cancel_timers = CancelTimers,
- hibernate = Hibernate},
- Events).
-
-loop_event_done(Parent, Debug, S, Q) ->
- case Q of
+ NewS =
+ S#state{
+ state = NextState,
+ data = NewData,
+ postponed = P,
+ timer_types = TimerTypes,
+ cancel_timers = CancelTimers,
+ hibernate = Hibernate},
+ case NextEventsR of
+ %% Handle 0..2 next events without list reversal since
+ %% that will move out all live registers and back again
[] ->
- %% Get a new event
- loop(Parent, Debug, S);
- [{Type,Content}|Events] ->
- %% Loop until out of enqueued events
- loop_event(Parent, Debug, S, Events, Type, Content)
+ loop_event_done(Parent, ?not_sys_debug, NewS, Events);
+ [E] ->
+ loop_event_done(Parent, ?not_sys_debug, NewS, [E|Events]);
+ [E2,E1] ->
+ loop_event_done(Parent, ?not_sys_debug, NewS, [E1,E2|Events]);
+ _ ->
+ %% A bit slower path
+ loop_event_done(
+ Parent, ?not_sys_debug, NewS, lists:reverse(NextEventsR, Events))
end.
-
%%---------------------------------------------------------------------------
%% Server loop helpers
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 3a5aba60b4..8223a52873 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -178,11 +178,11 @@ fread(Cont, Chars, Format) ->
Data :: [term()].
format(Format, Args) ->
- case catch io_lib_format:fwrite(Format, Args) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec format(Format, Data, Options) -> chars() when
@@ -193,11 +193,11 @@ format(Format, Args) ->
CharsLimit :: chars_limit().
format(Format, Args, Options) ->
- case catch io_lib_format:fwrite(Format, Args, Options) of
- {'EXIT',_} ->
- erlang:error(badarg, [Format, Args, Options]);
- Other ->
- Other
+ try io_lib_format:fwrite(Format, Args, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec scan_format(Format, Data) -> FormatList when
@@ -208,7 +208,9 @@ format(Format, Args, Options) ->
scan_format(Format, Args) ->
try io_lib_format:scan(Format, Args)
catch
- _:_ -> erlang:error(badarg, [Format, Args])
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [Format, Args])
end.
-spec unscan_format(FormatList) -> {Format, Data} when
@@ -223,7 +225,12 @@ unscan_format(FormatList) ->
FormatList :: [char() | format_spec()].
build_text(FormatList) ->
- io_lib_format:build(FormatList).
+ try io_lib_format:build(FormatList)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList])
+ end.
-spec build_text(FormatList, Options) -> chars() when
FormatList :: [char() | format_spec()],
@@ -232,7 +239,23 @@ build_text(FormatList) ->
CharsLimit :: chars_limit().
build_text(FormatList, Options) ->
- io_lib_format:build(FormatList, Options).
+ try io_lib_format:build(FormatList, Options)
+ catch
+ C:R:S ->
+ test_modules_loaded(C, R, S),
+ erlang:error(badarg, [FormatList, Options])
+ end.
+
+%% Failure to load a module must not be labeled as badarg.
+%% C, R, and S are included so that the original error, which could be
+%% a bug in io_lib_format, can be found by tracing on
+%% test_modules_loaded/3.
+test_modules_loaded(_C, _R, _S) ->
+ Modules = [io_lib_format, io_lib_pretty, string, unicode],
+ case code:ensure_modules_loaded(Modules) of
+ ok -> ok;
+ Error -> erlang:error(Error)
+ end.
-spec print(Term) -> chars() when
Term :: term().
diff --git a/lib/stdlib/src/io_lib_format.erl b/lib/stdlib/src/io_lib_format.erl
index c814ab50d4..ab9031573b 100644
--- a/lib/stdlib/src/io_lib_format.erl
+++ b/lib/stdlib/src/io_lib_format.erl
@@ -38,18 +38,16 @@
%% and it also splits the handling of the control characters into two
%% parts.
--spec fwrite(Format, Data) -> FormatList when
+-spec fwrite(Format, Data) -> io_lib:chars() when
Format :: io:format(),
- Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()].
+ Data :: [term()].
fwrite(Format, Args) ->
build(scan(Format, Args)).
--spec fwrite(Format, Data, Options) -> FormatList when
+-spec fwrite(Format, Data, Options) -> io_lib:chars() when
Format :: io:format(),
Data :: [term()],
- FormatList :: [char() | io_lib:format_spec()],
Options :: [Option],
Option :: {'chars_limit', CharsLimit},
CharsLimit :: io_lib:chars_limit().
@@ -248,7 +246,8 @@ count_small([#{control_char := $W}|Cs], #{w := W} = Cnts) ->
count_small(Cs, Cnts#{w := W + 1});
count_small([#{control_char := $s}|Cs], #{w := W} = Cnts) ->
count_small(Cs, Cnts#{w := W + 1});
-count_small([S|Cs], #{other := Other} = Cnts) when is_list(S) ->
+count_small([S|Cs], #{other := Other} = Cnts) when is_list(S);
+ is_binary(S) ->
count_small(Cs, Cnts#{other := Other + string:length(S)});
count_small([C|Cs], #{other := Other} = Cnts) when is_integer(C) ->
count_small(Cs, Cnts#{other := Other + 1});
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 60463feec2..51965ddb57 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -21,7 +21,7 @@
-module(maps).
-export([get/3, filter/2,fold/3,
- map/2, size/1,
+ map/2, size/1, new/0,
update_with/3, update_with/4,
without/2, with/2,
iterator/1, next/1]).
@@ -29,13 +29,15 @@
%% BIFs
-export([get/2, find/2, from_list/1,
is_key/2, keys/1, merge/2,
- new/0, put/3, remove/2, take/2,
+ put/3, remove/2, take/2,
to_list/1, update/3, values/1]).
--opaque iterator() :: {term(), term(), iterator()}
- | none | nonempty_improper_list(integer(),map()).
+-opaque iterator(Key, Value) :: {Key, Value, iterator(Key, Value)} | none
+ | nonempty_improper_list(integer(), #{Key => Value}).
--export_type([iterator/0]).
+-type iterator() :: iterator(term(), term()).
+
+-export_type([iterator/2, iterator/0]).
-dialyzer({no_improper_lists, iterator/1}).
@@ -50,9 +52,7 @@
get(_,_) -> erlang:nif_error(undef).
-spec find(Key,Map) -> {ok, Value} | error when
- Key :: term(),
- Map :: map(),
- Value :: term().
+ Map :: #{Key => Value, _ => _}.
find(_,_) -> erlang:nif_error(undef).
@@ -75,9 +75,8 @@ is_key(_,_) -> erlang:nif_error(undef).
-spec keys(Map) -> Keys when
- Map :: map(),
- Keys :: [Key],
- Key :: term().
+ Map :: #{Key => _},
+ Keys :: [Key].
keys(_) -> erlang:nif_error(undef).
@@ -91,13 +90,6 @@ keys(_) -> erlang:nif_error(undef).
merge(_,_) -> erlang:nif_error(undef).
-
--spec new() -> Map when
- Map :: map().
-
-new() -> erlang:nif_error(undef).
-
-
%% Shadowed by erl_bif_types: maps:put/3
-spec put(Key,Value,Map1) -> Map2 when
Key :: term(),
@@ -116,17 +108,13 @@ put(_,_,_) -> erlang:nif_error(undef).
remove(_,_) -> erlang:nif_error(undef).
-spec take(Key,Map1) -> {Value,Map2} | error when
- Key :: term(),
- Map1 :: map(),
- Value :: term(),
- Map2 :: map().
+ Map1 :: #{Key => Value, _ => _},
+ Map2 :: #{_ => _}.
take(_,_) -> erlang:nif_error(undef).
-spec to_list(Map) -> [{Key,Value}] when
- Map :: map(),
- Key :: term(),
- Value :: term().
+ Map :: #{Key => Value}.
to_list(Map) when is_map(Map) ->
to_list_internal(erts_internal:map_next(0, Map, []));
@@ -140,79 +128,69 @@ to_list_internal(Acc) ->
%% Shadowed by erl_bif_types: maps:update/3
-spec update(Key,Value,Map1) -> Map2 when
- Key :: term(),
- Value :: term(),
- Map1 :: map(),
- Map2 :: map().
+ Map1 :: #{Key := _, _ => _},
+ Map2 :: #{Key := Value, _ => _}.
update(_,_,_) -> erlang:nif_error(undef).
-spec values(Map) -> Values when
- Map :: map(),
- Values :: [Value],
- Value :: term().
+ Map :: #{_ => Value},
+ Values :: [Value].
values(_) -> erlang:nif_error(undef).
%% End of BIFs
+-spec new() -> Map when
+ Map :: #{}.
+
+new() -> #{}.
+
-spec update_with(Key,Fun,Map1) -> Map2 when
- Key :: term(),
- Map1 :: map(),
- Map2 :: map(),
- Fun :: fun((Value1 :: term()) -> Value2 :: term()).
+ Map1 :: #{Key := Value1, _ => _},
+ Map2 :: #{Key := Value2, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Map) when is_function(Fun,1), is_map(Map) ->
- try maps:get(Key,Map) of
- Val -> maps:update(Key,Fun(Val),Map)
- catch
- error:{badkey,_} ->
- erlang:error({badkey,Key},[Key,Fun,Map])
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> erlang:error({badkey,Key},[Key,Fun,Map])
end;
update_with(Key,Fun,Map) ->
erlang:error(error_type(Map),[Key,Fun,Map]).
-spec update_with(Key,Fun,Init,Map1) -> Map2 when
- Key :: term(),
- Map1 :: Map1,
- Map2 :: Map2,
- Fun :: fun((Value1 :: term()) -> Value2 :: term()),
- Init :: term().
+ Map1 :: #{Key => Value1, _ => _},
+ Map2 :: #{Key := Value2 | Init, _ => _},
+ Fun :: fun((Value1) -> Value2).
update_with(Key,Fun,Init,Map) when is_function(Fun,1), is_map(Map) ->
- case maps:find(Key,Map) of
- {ok,Val} -> maps:update(Key,Fun(Val),Map);
- error -> maps:put(Key,Init,Map)
+ case Map of
+ #{Key := Value} -> Map#{Key := Fun(Value)};
+ #{} -> Map#{Key => Init}
end;
update_with(Key,Fun,Init,Map) ->
erlang:error(error_type(Map),[Key,Fun,Init,Map]).
-spec get(Key, Map, Default) -> Value | Default when
- Key :: term(),
- Map :: map(),
- Value :: term(),
- Default :: term().
+ Map :: #{Key => Value, _ => _}.
get(Key,Map,Default) when is_map(Map) ->
- case maps:find(Key, Map) of
- {ok, Value} ->
- Value;
- error ->
- Default
+ case Map of
+ #{Key := Value} -> Value;
+ #{} -> Default
end;
get(Key,Map,Default) ->
erlang:error({badmap,Map},[Key,Map,Default]).
--spec filter(Pred,MapOrIter) -> Map when
+-spec filter(Pred, MapOrIter) -> Map when
Pred :: fun((Key, Value) -> boolean()),
- Key :: term(),
- Value :: term(),
- MapOrIter :: map() | iterator(),
- Map :: map().
+ MapOrIter :: #{Key => Value} | iterator(Key, Value),
+ Map :: #{Key => Value}.
filter(Pred,Map) when is_function(Pred,2), is_map(Map) ->
maps:from_list(filter_1(Pred, iterator(Map)));
@@ -235,14 +213,11 @@ filter_1(Pred, Iter) ->
end.
-spec fold(Fun,Init,MapOrIter) -> Acc when
- Fun :: fun((K, V, AccIn) -> AccOut),
+ Fun :: fun((Key, Value, AccIn) -> AccOut),
Init :: term(),
- Acc :: term(),
- AccIn :: term(),
- AccOut :: term(),
- MapOrIter :: map() | iterator(),
- K :: term(),
- V :: term().
+ Acc :: AccOut,
+ AccIn :: Init | AccOut,
+ MapOrIter :: #{Key => Value} | iterator(Key, Value).
fold(Fun,Init,Map) when is_function(Fun,3), is_map(Map) ->
fold_1(Fun,Init,iterator(Map));
@@ -260,12 +235,9 @@ fold_1(Fun, Acc, Iter) ->
end.
-spec map(Fun,MapOrIter) -> Map when
- Fun :: fun((K, V1) -> V2),
- MapOrIter :: map() | iterator(),
- Map :: map(),
- K :: term(),
- V1 :: term(),
- V2 :: term().
+ Fun :: fun((Key, Value1) -> Value2),
+ MapOrIter :: #{Key => Value1} | iterator(Key, Value1),
+ Map :: #{Key => Value2}.
map(Fun,Map) when is_function(Fun, 2), is_map(Map) ->
maps:from_list(map_1(Fun, iterator(Map)));
@@ -291,17 +263,15 @@ size(Val) ->
erlang:error({badmap,Val},[Val]).
-spec iterator(Map) -> Iterator when
- Map :: map(),
- Iterator :: iterator().
+ Map :: #{Key => Value},
+ Iterator :: iterator(Key, Value).
iterator(M) when is_map(M) -> [0 | M];
iterator(M) -> erlang:error({badmap, M}, [M]).
-spec next(Iterator) -> {Key, Value, NextIterator} | 'none' when
- Iterator :: iterator(),
- Key :: term(),
- Value :: term(),
- NextIterator :: iterator().
+ Iterator :: iterator(Key, Value),
+ NextIterator :: iterator(Key, Value).
next({K, V, I}) ->
{K, V, I};
next([Path | Map]) when is_integer(Path), is_map(Map) ->
@@ -318,29 +288,26 @@ next(Iter) ->
K :: term().
without(Ks,M) when is_list(Ks), is_map(M) ->
- lists:foldl(fun(K, M1) -> maps:remove(K, M1) end, M, Ks);
+ lists:foldl(fun maps:remove/2, M, Ks);
without(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
-spec with(Ks, Map1) -> Map2 when
Ks :: [K],
- Map1 :: map(),
- Map2 :: map(),
- K :: term().
+ Map1 :: #{K => V, _ => _},
+ Map2 :: #{K => V}.
with(Ks,Map1) when is_list(Ks), is_map(Map1) ->
- Fun = fun(K, List) ->
- case maps:find(K, Map1) of
- {ok, V} ->
- [{K, V} | List];
- error ->
- List
- end
- end,
- maps:from_list(lists:foldl(Fun, [], Ks));
+ maps:from_list(with_1(Ks, Map1));
with(Ks,M) ->
erlang:error(error_type(M),[Ks,M]).
+with_1([K|Ks], Map) ->
+ case Map of
+ #{K := V} -> [{K,V}|with_1(Ks, Map)];
+ #{} -> with_1(Ks, Map)
+ end;
+with_1([], _Map) -> [].
error_type(M) when is_map(M) -> badarg;
error_type(V) -> {badmap, V}.
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index d117481d2e..6d243e1bec 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -224,10 +224,12 @@ transform_from_shell(Dialect, Clauses, BoundEnvironment) ->
%% Called when translating during compiling
%%
--spec parse_transform(Forms, Options) -> Forms2 when
+-spec parse_transform(Forms, Options) -> Forms2 | Errors | Warnings when
Forms :: [erl_parse:abstract_form() | erl_parse:form_info()],
Forms2 :: [erl_parse:abstract_form() | erl_parse:form_info()],
- Options :: term().
+ Options :: term(),
+ Errors :: {error, ErrInfo :: [tuple()], WarnInfo :: []},
+ Warnings :: {warning, Forms2, WarnInfo :: [tuple()]}.
parse_transform(Forms, _Options) ->
SaveFilename = setup_filename(),
@@ -944,6 +946,7 @@ real_guard_function(node,0) -> true;
real_guard_function(node,1) -> true;
real_guard_function(round,1) -> true;
real_guard_function(size,1) -> true;
+real_guard_function(bit_size,1) -> true;
real_guard_function(map_size,1) -> true;
real_guard_function(map_get,2) -> true;
real_guard_function(tl,1) -> true;
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index aaed13ba3a..2cfc702b53 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -398,10 +398,8 @@ obsolete_1(megaco, format_versions, 1) ->
%% *** OS-MON-MIB ***
-obsolete_1(os_mon_mib, init, 1) ->
- {deprecated, {os_mon_mib, load, 1}};
-obsolete_1(os_mon_mib, stop, 1) ->
- {deprecated, {os_mon_mib, unload, 1}};
+obsolete_1(os_mon_mib, _, _) ->
+ {removed, "was removed in 22.0"};
obsolete_1(auth, is_auth, 1) ->
{deprecated, {net_adm, ping, 1}};
diff --git a/lib/stdlib/src/proc_lib.erl b/lib/stdlib/src/proc_lib.erl
index d07c62500b..cfbaf8b242 100644
--- a/lib/stdlib/src/proc_lib.erl
+++ b/lib/stdlib/src/proc_lib.erl
@@ -757,7 +757,8 @@ check(Res) -> Res.
report_cb(#{label:={proc_lib,crash}, report:=CrashReport}, Extra) ->
Default = #{chars_limit => unlimited,
depth => unlimited,
- encoding => latin1},
+ single_line => false,
+ encoding => utf8},
do_format(CrashReport, maps:merge(Default,Extra)).
-spec format(CrashReport) -> string() when
@@ -780,33 +781,48 @@ format(CrashReport, Encoding) ->
format(CrashReport, Encoding, Depth) ->
do_format(CrashReport, #{chars_limit => unlimited,
depth => Depth,
- encoding => Encoding}).
-
-do_format([OwnReport,LinkReport], Extra) ->
- MyIndent = " ",
+ encoding => Encoding,
+ single_line => false}).
+
+do_format([OwnReport,LinkReport], #{single_line:=Single}=Extra) ->
+ Indent = if Single -> "";
+ true -> " "
+ end,
+ MyIndent = Indent ++ Indent,
+ Sep = nl(Single,"; "),
OwnFormat = format_report(OwnReport, MyIndent, Extra),
- LinkFormat = format_link_report(LinkReport, MyIndent, Extra),
- Str = io_lib:format(" crasher:~n~ts neighbours:~n~ts",
- [OwnFormat, LinkFormat]),
+ LinkFormat = lists:join(Sep,format_link_report(LinkReport, MyIndent, Extra)),
+ Nl = nl(Single," "),
+ Str = io_lib:format("~scrasher:"++Nl++"~ts"++Sep++"~sneighbours:"++Nl++"~ts",
+ [Indent,OwnFormat,Indent,LinkFormat]),
lists:flatten(Str).
-format_link_report([Link|Reps], Indent, Extra) ->
+format_link_report([Link|Reps], Indent0, #{single_line:=Single}=Extra) ->
Rep = case Link of
{neighbour,Rep0} -> Rep0;
_ -> Link
end,
+ Indent = if Single -> "";
+ true -> Indent0
+ end,
LinkIndent = [" ",Indent],
- [Indent,"neighbour:\n",format_report(Rep, LinkIndent, Extra)|
+ [[Indent,"neighbour:",nl(Single," "),format_report(Rep, LinkIndent, Extra)]|
format_link_report(Reps, Indent, Extra)];
format_link_report(Rep, Indent, Extra) ->
format_report(Rep, Indent, Extra).
-format_report(Rep, Indent, Extra) when is_list(Rep) ->
- format_rep(Rep, Indent, Extra);
-format_report(Rep, Indent, #{encoding:=Enc,depth:=unlimited}) ->
- io_lib:format("~s~"++modifier(Enc)++"p~n", [Indent, Rep]);
-format_report(Rep, Indent, #{encoding:=Enc,depth:=Depth}) ->
- io_lib:format("~s~"++modifier(Enc)++"P~n", [Indent, Rep, Depth]).
+format_report(Rep, Indent, #{single_line:=Single}=Extra) when is_list(Rep) ->
+ lists:join(nl(Single,", "),format_rep(Rep, Indent, Extra));
+format_report(Rep, Indent0, #{encoding:=Enc,depth:=Depth,
+ chars_limit:=Limit,single_line:=Single}) ->
+ {P,Tl} = p(Enc,Depth),
+ {Indent,Width} = if Single -> {"","0"};
+ true -> {Indent0,""}
+ end,
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ io_lib:format("~s~"++Width++P, [Indent, Rep | Tl], Opts).
format_rep([{initial_call,InitialCall}|Rep], Indent, Extra) ->
[format_mfa(Indent, InitialCall, Extra)|format_rep(Rep, Indent, Extra)];
@@ -818,19 +834,32 @@ format_rep([{Tag,Data}|Rep], Indent, Extra) ->
format_rep(_, _, _Extra) ->
[].
-format_exception(Class, Reason, StackTrace, #{encoding:=Enc}=Extra) ->
+format_exception(Class, Reason, StackTrace,
+ #{encoding:=Enc,depth:=Depth,chars_limit:=Limit,
+ single_line:=Single}=Extra) ->
PF = pp_fun(Extra),
StackFun = fun(M, _F, _A) -> (M =:= erl_eval) or (M =:= ?MODULE) end,
- %% EI = " exception: ",
- EI = " ",
- [EI, erl_error:format_exception(1+length(EI), Class, Reason,
- StackTrace, StackFun, PF, Enc), "\n"].
+ if Single ->
+ {P,Tl} = p(Enc,Depth),
+ Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
+ true -> []
+ end,
+ [atom_to_list(Class), ": ",
+ io_lib:format("~0"++P,[{Reason,StackTrace}|Tl],Opts)];
+ true ->
+ EI = " ",
+ [EI, erl_error:format_exception(1+length(EI), Class, Reason,
+ StackTrace, StackFun, PF, Enc)]
+ end.
-format_mfa(Indent, {M,F,Args}=StartF, #{encoding:=Enc}=Extra) ->
+format_mfa(Indent0, {M,F,Args}=StartF, #{encoding:=Enc,single_line:=Single}=Extra) ->
+ Indent = if Single -> "";
+ true -> Indent0
+ end,
try
A = length(Args),
[Indent,"initial call: ",atom_to_list(M),$:,to_string(F, Enc),$/,
- integer_to_list(A),"\n"]
+ integer_to_list(A)]
catch
error:_ ->
format_tag(Indent, initial_call, StartF, Extra)
@@ -841,21 +870,29 @@ to_string(A, latin1) ->
to_string(A, _) ->
io_lib:write_atom(A).
-pp_fun(#{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
+pp_fun(#{encoding:=Enc,depth:=Depth,chars_limit:=Limit,single_line:=Single}) ->
{P,Tl} = p(Enc, Depth),
+ Width = if Single -> "0";
+ true -> ""
+ end,
Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
true -> []
end,
fun(Term, I) ->
- io_lib:format("~." ++ integer_to_list(I) ++ P, [Term|Tl], Opts)
+ io_lib:format("~" ++ Width ++ "." ++ integer_to_list(I) ++ P,
+ [Term|Tl], Opts)
end.
-format_tag(Indent, Tag, Data, #{encoding:=Enc,depth:=Depth,chars_limit:=Limit}) ->
+format_tag(Indent0, Tag, Data, #{encoding:=Enc,depth:=Depth,chars_limit:=Limit,single_line:=Single}) ->
{P,Tl} = p(Enc, Depth),
+ {Indent,Width} = if Single -> {"","0"};
+ true -> {Indent0,""}
+ end,
Opts = if is_integer(Limit) -> [{chars_limit,Limit}];
true -> []
end,
- io_lib:format("~s~p: ~80.18" ++ P ++ "\n", [Indent, Tag, Data|Tl], Opts).
+ io_lib:format("~s~" ++ Width ++ "p: ~" ++ Width ++ ".18" ++ P,
+ [Indent, Tag, Data|Tl], Opts).
p(Encoding, Depth) ->
{Letter, Tl} = case Depth of
@@ -868,6 +905,8 @@ p(Encoding, Depth) ->
modifier(latin1) -> "";
modifier(_) -> "t".
+nl(true,Else) -> Else;
+nl(false,_) -> "\n".
%%% -----------------------------------------------------------
%%% Stop a process and wait for it to terminate
diff --git a/lib/stdlib/src/rand.erl b/lib/stdlib/src/rand.erl
index 362e98006e..3a9a1e007b 100644
--- a/lib/stdlib/src/rand.erl
+++ b/lib/stdlib/src/rand.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2015-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2015-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -32,18 +32,24 @@
uniform/0, uniform/1, uniform_s/1, uniform_s/2,
uniform_real/0, uniform_real_s/1,
jump/0, jump/1,
- normal/0, normal/2, normal_s/1, normal_s/3
+ normal/0, normal/2, normal_s/1, normal_s/3
]).
+%% Test, dev and internal
+-export([exro928_jump_2pow512/1, exro928_jump_2pow20/1,
+ exro928_seed/1, exro928_next/1, exro928_next_state/1,
+ format_jumpconst58/1, seed58/2]).
+
%% Debug
-export([make_float/3, float2str/1, bc64/1]).
--compile({inline, [exs64_next/1, exsplus_next/1,
+-compile({inline, [exs64_next/1, exsplus_next/1, exsss_next/1,
exs1024_next/1, exs1024_calc/2,
+ exro928_next_state/4,
exrop_next/1, exrop_next_s/2,
get_52/1, normal_kiwi/1]}).
--define(DEFAULT_ALG_HANDLER, exrop).
+-define(DEFAULT_ALG_HANDLER, exsss).
-define(SEED_DICT, rand_seed).
%% =====================================================================
@@ -80,8 +86,8 @@
%% This depends on the algorithm handler function
-type alg_state() ::
- exs64_state() | exsplus_state() | exs1024_state() |
- exrop_state() | term().
+ exsplus_state() | exro928_state() | exrop_state() | exs1024_state() |
+ exs64_state() | term().
%% This is the algorithm handling definition within this module,
%% and the type to use for plugins.
@@ -124,14 +130,17 @@
%% Algorithm state
-type state() :: {alg_handler(), alg_state()}.
--type builtin_alg() :: exs64 | exsplus | exsp | exs1024 | exs1024s | exrop.
+-type builtin_alg() ::
+ exsss | exro928ss | exrop | exs1024s | exsp | exs64 | exsplus | exs1024.
-type alg() :: builtin_alg() | atom().
-type export_state() :: {alg(), alg_state()}.
+-type seed() :: [integer()] | integer() | {integer(), integer(), integer()}.
-export_type(
[builtin_alg/0, alg/0, alg_handler/0, alg_state/0,
- state/0, export_state/0]).
+ state/0, export_state/0, seed/0]).
-export_type(
- [exs64_state/0, exsplus_state/0, exs1024_state/0, exrop_state/0]).
+ [exsplus_state/0, exro928_state/0, exrop_state/0, exs1024_state/0,
+ exs64_state/0]).
%% =====================================================================
%% Range macro and helper
@@ -229,12 +238,12 @@ export_seed() ->
end.
-spec export_seed_s(State :: state()) -> export_state().
-export_seed_s({#{type:=Alg}, Seed}) -> {Alg, Seed}.
+export_seed_s({#{type:=Alg}, AlgState}) -> {Alg, AlgState}.
%% seed(Alg) seeds RNG with runtime dependent values
%% and return the NEW state
-%% seed({Alg,Seed}) setup RNG with a previously exported seed
+%% seed({Alg,AlgState}) setup RNG with a previously exported seed
%% and return the NEW state
-spec seed(
@@ -246,11 +255,11 @@ seed(Alg) ->
-spec seed_s(
AlgOrStateOrExpState :: builtin_alg() | state() | export_state()) ->
state().
-seed_s({AlgHandler, _Seed} = State) when is_map(AlgHandler) ->
+seed_s({AlgHandler, _AlgState} = State) when is_map(AlgHandler) ->
State;
-seed_s({Alg0, Seed}) ->
- {Alg,_SeedFun} = mk_alg(Alg0),
- {Alg, Seed};
+seed_s({Alg, AlgState}) when is_atom(Alg) ->
+ {AlgHandler,_SeedFun} = mk_alg(Alg),
+ {AlgHandler,AlgState};
seed_s(Alg) ->
seed_s(Alg, {erlang:phash2([{node(),self()}]),
erlang:system_time(),
@@ -259,19 +268,15 @@ seed_s(Alg) ->
%% seed/2: seeds RNG with the algorithm and given values
%% and returns the NEW state.
--spec seed(
- Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) ->
- state().
-seed(Alg0, S0) ->
- seed_put(seed_s(Alg0, S0)).
+-spec seed(Alg :: builtin_alg(), Seed :: seed()) -> state().
+seed(Alg, Seed) ->
+ seed_put(seed_s(Alg, Seed)).
--spec seed_s(
- Alg :: builtin_alg(), Seed :: {integer(), integer(), integer()}) ->
- state().
-seed_s(Alg0, S0 = {_, _, _}) ->
- {Alg, Seed} = mk_alg(Alg0),
- AS = Seed(S0),
- {Alg, AS}.
+-spec seed_s(Alg :: builtin_alg(), Seed :: seed()) -> state().
+seed_s(Alg, Seed) ->
+ {AlgHandler,SeedFun} = mk_alg(Alg),
+ AlgState = SeedFun(Seed),
+ {AlgHandler,AlgState}.
%%% uniform/0, uniform/1, uniform_s/1, uniform_s/2 are all
%%% uniformly distributed random numbers.
@@ -281,8 +286,8 @@ seed_s(Alg0, S0 = {_, _, _}) ->
-spec uniform() -> X :: float().
uniform() ->
- {X, Seed} = uniform_s(seed_get()),
- _ = seed_put(Seed),
+ {X, State} = uniform_s(seed_get()),
+ _ = seed_put(State),
X.
%% uniform/1: given an integer N >= 1,
@@ -291,8 +296,8 @@ uniform() ->
-spec uniform(N :: pos_integer()) -> X :: pos_integer().
uniform(N) ->
- {X, Seed} = uniform_s(N, seed_get()),
- _ = seed_put(Seed),
+ {X, State} = uniform_s(N, seed_get()),
+ _ = seed_put(State),
X.
%% uniform_s/1: given a state, uniform_s/1
@@ -486,7 +491,7 @@ uniform_real_s(Alg, Next, M0, BitNo, R1, V1, Bits) ->
{M1 * math:pow(2.0, BitNo - 56), {Alg, R1}};
BitNo =:= -1008 ->
%% Endgame
- %% For the last round we can not have 14 zeros or more
+ %% For the last round we cannot have 14 zeros or more
%% at the top of M1 because then we will underflow,
%% so we need at least 43 bits
if
@@ -613,6 +618,11 @@ mk_alg(exsp) ->
uniform=>fun exsp_uniform/1, uniform_n=>fun exsp_uniform/2,
jump=>fun exsplus_jump/1},
fun exsplus_seed/1};
+mk_alg(exsss) ->
+ {#{type=>exsss, bits=>58, next=>fun exsss_next/1,
+ uniform=>fun exsss_uniform/1, uniform_n=>fun exsss_uniform/2,
+ jump=>fun exsplus_jump/1},
+ fun exsss_seed/1};
mk_alg(exs1024) ->
{#{type=>exs1024, max=>?MASK(64), next=>fun exs1024_next/1,
jump=>fun exs1024_jump/1},
@@ -625,7 +635,13 @@ mk_alg(exrop) ->
{#{type=>exrop, bits=>58, weak_low_bits=>1, next=>fun exrop_next/1,
uniform=>fun exrop_uniform/1, uniform_n=>fun exrop_uniform/2,
jump=>fun exrop_jump/1},
- fun exrop_seed/1}.
+ fun exrop_seed/1};
+mk_alg(exro928ss) ->
+ {#{type=>exro928ss, bits=>58, next=>fun exro928ss_next/1,
+ uniform=>fun exro928ss_uniform/1,
+ uniform_n=>fun exro928ss_uniform/2,
+ jump=>fun exro928_jump/1},
+ fun exro928_seed/1}.
%% =====================================================================
%% exs64 PRNG: Xorshift64*
@@ -635,6 +651,14 @@ mk_alg(exrop) ->
-opaque exs64_state() :: uint64().
+exs64_seed(L) when is_list(L) ->
+ [R] = seed64_nz(1, L),
+ R;
+exs64_seed(A) when is_integer(A) ->
+ [R] = seed64(1, ?MASK(64, A)),
+ R;
+%%
+%% Traditional integer triplet seed
exs64_seed({A1, A2, A3}) ->
{V1, _} = exs64_next((?MASK(32, A1) * 4294967197 + 1)),
{V2, _} = exs64_next((?MASK(32, A2) * 4294967231 + 1)),
@@ -656,11 +680,49 @@ exs64_next(R) ->
%% 58 bits fits into an immediate on 64bits erlang and is thus much faster.
%% Modification of the original Xorshift128+ algorithm to 116
%% by Sebastiano Vigna, a lot of thanks for his help and work.
+%%
+%% Reference C code for Xorshift116+ and Xorshift116**
+%%
+%% #include <stdint.h>
+%%
+%% #define MASK(b, v) (((UINT64_C(1) << (b)) - 1) & (v))
+%% #define BSL(b, v, n) (MASK((b)-(n), (v)) << (n))
+%% #define ROTL(b, v, n) (BSL((b), (v), (n)) | ((v) >> ((b)-(n))))
+%%
+%% uint64_t s[2];
+%%
+%% uint64_t next(void) {
+%% uint64_t s1 = s[0];
+%% const uint64_t s0 = s[1];
+%%
+%% s1 ^= BSL(58, s1, 24); // a
+%% s1 ^= s0 ^ (s1 >> 11) ^ (s0 >> 41); // b, c
+%% s[0] = s0;
+%% s[1] = s1;
+%%
+%% const uint64_t result_plus = MASK(58, s0 + s1);
+%% uint64_t result_starstar = s0;
+%% result_starstar = MASK(58, result_starstar * 5);
+%% result_starstar = ROTL(58, result_starstar, 7);
+%% result_starstar = MASK(58, result_starstar * 9);
+%%
+%% return result_plus;
+%% return result_starstar;
+%% }
+%%
%% =====================================================================
-opaque exsplus_state() :: nonempty_improper_list(uint58(), uint58()).
-dialyzer({no_improper_lists, exsplus_seed/1}).
+exsplus_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exsplus_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Traditional integer triplet seed
exsplus_seed({A1, A2, A3}) ->
{_, R1} = exsplus_next(
[?MASK(58, (A1 * 4294967197) + 1)|
@@ -670,16 +732,62 @@ exsplus_seed({A1, A2, A3}) ->
tl(R1)]),
R2.
+-dialyzer({no_improper_lists, exsss_seed/1}).
+
+exsss_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exsss_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Seed from traditional integer triple - mix into splitmix
+exsss_seed({A1, A2, A3}) ->
+ {_, X0} = seed58(?MASK(64, A1)),
+ {S0, X1} = seed58(?MASK(64, A2) bxor X0),
+ {S1, _} = seed58(?MASK(64, A3) bxor X1),
+ [S0|S1].
+
+%% Advance Xorshift116 state one step
+-define(
+ exs_next(S0, S1, S1_b),
+ begin
+ S1_b = S1 bxor ?BSL(58, S1, 24),
+ S1_b bxor S0 bxor (S1_b bsr 11) bxor (S0 bsr 41)
+ end).
+
+-define(
+ scramble_starstar(S, V_a, V_b),
+ begin
+ %% The multiply by add shifted trick avoids creating bignums
+ %% which improves performance significantly
+ %%
+ V_a = ?MASK(58, S + ?BSL(58, S, 2)), % V_a = S * 5
+ V_b = ?ROTL(58, V_a, 7),
+ ?MASK(58, V_b + ?BSL(58, V_b, 3)) % V_b * 9
+ end).
+
-dialyzer({no_improper_lists, exsplus_next/1}).
-%% Advance xorshift116+ state for one step and generate 58bit unsigned integer
+%% Advance state and generate 58bit unsigned integer
-spec exsplus_next(exsplus_state()) -> {uint58(), exsplus_state()}.
exsplus_next([S1|S0]) ->
%% Note: members s0 and s1 are swapped here
- S11 = S1 bxor ?BSL(58, S1, 24),
- S12 = S11 bxor S0 bxor (S11 bsr 11) bxor (S0 bsr 41),
- {?MASK(58, S0 + S12), [S0|S12]}.
+ NewS1 = ?exs_next(S0, S1, S1_1),
+ {?MASK(58, S0 + NewS1), [S0|NewS1]}.
+%% %% Note: members s0 and s1 are swapped here
+%% S11 = S1 bxor ?BSL(58, S1, 24),
+%% S12 = S11 bxor S0 bxor (S11 bsr 11) bxor (S0 bsr 41),
+%% {?MASK(58, S0 + S12), [S0|S12]}.
+
+-dialyzer({no_improper_lists, exsss_next/1}).
+-spec exsss_next(exsplus_state()) -> {uint58(), exsplus_state()}.
+exsss_next([S1|S0]) ->
+ %% Note: members s0 and s1 are swapped here
+ NewS1 = ?exs_next(S0, S1, S1_1),
+ {?scramble_starstar(S0, V_0, V_1), [S0|NewS1]}.
+%% {?MASK(58, S0 + NewS1), [S0|NewS1]}.
exsp_uniform({Alg, R0}) ->
{I, R1} = exsplus_next(R0),
@@ -687,18 +795,48 @@ exsp_uniform({Alg, R0}) ->
%% randomness quality than the others
{(I bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, R1}}.
+exsss_uniform({Alg, R0}) ->
+ {I, R1} = exsss_next(R0),
+ {(I bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, R1}}.
+
exsp_uniform(Range, {Alg, R}) ->
{V, R1} = exsplus_next(R),
MaxMinusRange = ?BIT(58) - Range,
?uniform_range(Range, Alg, R1, V, MaxMinusRange, I).
+exsss_uniform(Range, {Alg, R}) ->
+ {V, R1} = exsss_next(R),
+ MaxMinusRange = ?BIT(58) - Range,
+ ?uniform_range(Range, Alg, R1, V, MaxMinusRange, I).
-%% This is the jump function for the exsplus generator, equivalent
+
+%% This is the jump function for the exs* generators,
+%% i.e the Xorshift116 generators, equivalent
%% to 2^64 calls to next/1; it can be used to generate 2^52
%% non-overlapping subsequences for parallel computations.
%% Note: the jump function takes 116 times of the execution time of
%% next/1.
-
+%%
+%% #include <stdint.h>
+%%
+%% void jump(void) {
+%% static const uint64_t JUMP[] = { 0x02f8ea6bc32c797,
+%% 0x345d2a0f85f788c };
+%% int i, b;
+%% uint64_t s0 = 0;
+%% uint64_t s1 = 0;
+%% for(i = 0; i < sizeof JUMP / sizeof *JUMP; i++)
+%% for(b = 0; b < 58; b++) {
+%% if (JUMP[i] & 1ULL << b) {
+%% s0 ^= s[0];
+%% s1 ^= s[1];
+%% }
+%% next();
+%% }
+%% s[0] = s0;
+%% s[1] = s1;
+%% }
+%%
%% -define(JUMPCONST, 16#000d174a83e17de2302f8ea6bc32c797).
%% split into 58-bit chunks
%% and two iterative executions
@@ -708,7 +846,8 @@ exsp_uniform(Range, {Alg, R}) ->
-define(JUMPELEMLEN, 58).
-dialyzer({no_improper_lists, exsplus_jump/1}).
--spec exsplus_jump(state()) -> state().
+-spec exsplus_jump({alg_handler(), exsplus_state()}) ->
+ {alg_handler(), exsplus_state()}.
exsplus_jump({Alg, S}) ->
{S1, AS1} = exsplus_jump(S, [0|0], ?JUMPCONST1, ?JUMPELEMLEN),
{_, AS2} = exsplus_jump(S1, AS1, ?JUMPCONST2, ?JUMPELEMLEN),
@@ -735,6 +874,12 @@ exsplus_jump(S, [AS0|AS1], J, N) ->
-opaque exs1024_state() :: {list(uint64()), list(uint64())}.
+exs1024_seed(L) when is_list(L) ->
+ {seed64_nz(16, L), []};
+exs1024_seed(X) when is_integer(X) ->
+ {seed64(16, ?MASK(64, X)), []};
+%%
+%% Seed from traditional triple, remain backwards compatible
exs1024_seed({A1, A2, A3}) ->
B1 = ?MASK(21, (?MASK(21, A1) + 1) * 2097131),
B2 = ?MASK(21, (?MASK(21, A2) + 1) * 2097133),
@@ -806,8 +951,8 @@ exs1024_next({[H], RL}) ->
-define(JUMPTOTALLEN, 1024).
-define(RINGLEN, 16).
--spec exs1024_jump(state()) -> state().
-
+-spec exs1024_jump({alg_handler(), exs1024_state()}) ->
+ {alg_handler(), exs1024_state()}.
exs1024_jump({Alg, {L, RL}}) ->
P = length(RL),
AS = exs1024_jump({L, RL},
@@ -832,6 +977,195 @@ exs1024_jump({L, RL}, AS, JL, J, N, TN) ->
end.
%% =====================================================================
+%% exro928ss PRNG: Xoroshiro928**
+%%
+%% Reference URL: http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
+%% i.e the Xoroshiro1024 generator with ** scrambler
+%% with {S, R, T} = {5, 7, 9} as recommended in the paper.
+%%
+%% {A, B, C} were tried out and selected as {44, 9, 45}
+%% and the jump coefficients calculated.
+%%
+%% Standard jump function pseudocode:
+%%
+%% Jump constant j = 0xb10773cb...44085302f77130ca
+%% Generator state: s
+%% New generator state: t = 0
+%% foreach bit in j, low to high:
+%% if the bit is one:
+%% t ^= s
+%% next s
+%% s = t
+%%
+%% Generator used for reference value calculation:
+%%
+%% #include <stdint.h>
+%% #include <stdio.h>
+%%
+%% int p = 0;
+%% uint64_t s[16];
+%%
+%% #define MASK(x) ((x) & ((UINT64_C(1) << 58) - 1))
+%% static __inline uint64_t rotl(uint64_t x, int n) {
+%% return MASK(x << n) | (x >> (58 - n));
+%% }
+%%
+%% uint64_t next() {
+%% const int q = p;
+%% const uint64_t s0 = s[p = (p + 1) & 15];
+%% uint64_t s15 = s[q];
+%%
+%% const uint64_t result_starstar = MASK(rotl(MASK(s0 * 5), 7) * 9);
+%%
+%% s15 ^= s0;
+%% s[q] = rotl(s0, 44) ^ s15 ^ MASK(s15 << 9);
+%% s[p] = rotl(s15, 45);
+%%
+%% return result_starstar;
+%% }
+%%
+%% static const uint64_t jump_2pow512[15] =
+%% { 0x44085302f77130ca, 0xba05381fdfd14902, 0x10a1de1d7d6813d2,
+%% 0xb83fe51a1eb3be19, 0xa81b0090567fd9f0, 0x5ac26d5d20f9b49f,
+%% 0x4ddd98ee4be41e01, 0x0657e19f00d4b358, 0xf02f778573cf0f0a,
+%% 0xb45a3a8a3cef3cc0, 0x6e62a33cc2323831, 0xbcb3b7c4cc049c53,
+%% 0x83f240c6007e76ce, 0xe19f5fc1a1504acd, 0x00000000b10773cb };
+%%
+%% static const uint64_t jump_2pow20[15] =
+%% { 0xbdb966a3daf905e6, 0x644807a56270cf78, 0xda90f4a806c17e9e,
+%% 0x4a426866bfad3c77, 0xaf699c306d8e7566, 0x8ebc73c700b8b091,
+%% 0xc081a7bf148531fb, 0xdc4d3af15f8a4dfd, 0x90627c014098f4b6,
+%% 0x06df2eb1feaf0fb6, 0x5bdeb1a5a90f2e6b, 0xa480c5878c3549bd,
+%% 0xff45ef33c82f3d48, 0xa30bebc15fefcc78, 0x00000000cb3d181c };
+%%
+%% void jump(const uint64_t *jump) {
+%% uint64_t j, t[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+%% int m, n, k;
+%% for (m = 0; m < 15; m++, jump++) {
+%% for (n = 0, j = *jump; n < 64; n++, j >>= 1) {
+%% if ((j & 1) != 0) {
+%% for (k = 0; k < 16; k++) {
+%% t[k] ^= s[(p + k) & 15];
+%% }
+%% }
+%% next();
+%% }
+%% }
+%% for (k = 0; k < 16; k++) {
+%% s[(p + k) & 15] = t[k];
+%% }
+%% }
+%%
+%% =====================================================================
+
+-opaque exro928_state() :: {list(uint58()), list(uint58())}.
+
+-spec exro928_seed(
+ list(uint58()) | integer() | {integer(), integer(), integer()}) ->
+ exro928_state().
+exro928_seed(L) when is_list(L) ->
+ {seed58_nz(16, L), []};
+exro928_seed(X) when is_integer(X) ->
+ {seed58(16, ?MASK(64, X)), []};
+%%
+%% Seed from traditional integer triple - mix into splitmix
+exro928_seed({A1, A2, A3}) ->
+ {S0, X0} = seed58(?MASK(64, A1)),
+ {S1, X1} = seed58(?MASK(64, A2) bxor X0),
+ {S2, X2} = seed58(?MASK(64, A3) bxor X1),
+ {[S0,S1,S2|seed58(13, X2)], []}.
+
+
+%% Update the state and calculate output word
+-spec exro928ss_next(exro928_state()) -> {uint58(), exro928_state()}.
+exro928ss_next({[S15,S0|Ss], Rs}) ->
+ SR = exro928_next_state(Ss, Rs, S15, S0),
+ %%
+ %% {S, R, T} = {5, 7, 9}
+ %% const uint64_t result_starstar = rotl(s0 * S, R) * T;
+ %%
+ {?scramble_starstar(S0, V_0, V_1), SR};
+%% %% The multiply by add shifted trick avoids creating bignums
+%% %% which improves performance significantly
+%% %%
+%% V0 = ?MASK(58, S0 + ?BSL(58, S0, 2)), % V0 = S0 * 5
+%% V1 = ?ROTL(58, V0, 7),
+%% V = ?MASK(58, V1 + ?BSL(58, V1, 3)), % V = V1 * 9
+%% {V, SR};
+exro928ss_next({[S15], Rs}) ->
+ exro928ss_next({[S15|lists:reverse(Rs)], []}).
+
+-spec exro928_next(exro928_state()) -> {{uint58(),uint58()}, exro928_state()}.
+exro928_next({[S15,S0|Ss], Rs}) ->
+ SR = exro928_next_state(Ss, Rs, S15, S0),
+ {{S15,S0}, SR};
+exro928_next({[S15], Rs}) ->
+ exro928_next({[S15|lists:reverse(Rs)], []}).
+
+%% Just update the state
+-spec exro928_next_state(exro928_state()) -> exro928_state().
+exro928_next_state({[S15,S0|Ss], Rs}) ->
+ exro928_next_state(Ss, Rs, S15, S0);
+exro928_next_state({[S15], Rs}) ->
+ [S0|Ss] = lists:reverse(Rs),
+ exro928_next_state(Ss, [], S15, S0).
+
+exro928_next_state(Ss, Rs, S15, S0) ->
+ %% {A, B, C} = {44, 9, 45},
+ %% s15 ^= s0;
+ %% NewS15: s[q] = rotl(s0, A) ^ s15 ^ (s15 << B);
+ %% NewS0: s[p] = rotl(s15, C);
+ %%
+ Q = S15 bxor S0,
+ NewS15 = ?ROTL(58, S0, 44) bxor Q bxor ?BSL(58, Q, 9),
+ NewS0 = ?ROTL(58, Q, 45),
+ {[NewS0|Ss], [NewS15|Rs]}.
+
+
+exro928ss_uniform({Alg, SR}) ->
+ {V, NewSR} = exro928ss_next(SR),
+ {(V bsr (58-53)) * ?TWO_POW_MINUS53, {Alg, NewSR}}.
+
+exro928ss_uniform(Range, {Alg, SR}) ->
+ {V, NewSR} = exro928ss_next(SR),
+ MaxMinusRange = ?BIT(58) - Range,
+ ?uniform_range(Range, Alg, NewSR, V, MaxMinusRange, I).
+
+
+-spec exro928_jump({alg_handler(), exro928_state()}) ->
+ {alg_handler(), exro928_state()}.
+exro928_jump({Alg, SR}) ->
+ {Alg,exro928_jump_2pow512(SR)}.
+
+-spec exro928_jump_2pow512(exro928_state()) -> exro928_state().
+exro928_jump_2pow512(SR) ->
+ polyjump(
+ SR, fun exro928_next_state/1,
+ %% 2^512
+ [16#4085302F77130CA, 16#54E07F7F4524091,
+ 16#5E1D7D6813D2BA0, 16#4687ACEF8644287,
+ 16#4567FD9F0B83FE5, 16#43E6D27EA06C024,
+ 16#641E015AC26D5D2, 16#6CD61377663B92F,
+ 16#70A0657E19F00D4, 16#43C0BDDE15CF3C3,
+ 16#745A3A8A3CEF3CC, 16#58A8CF308C8E0C6,
+ 16#7B7C4CC049C536E, 16#431801F9DB3AF2C,
+ 16#41A1504ACD83F24, 16#6C41DCF2F867D7F]).
+
+-spec exro928_jump_2pow20(exro928_state()) -> exro928_state().
+exro928_jump_2pow20(SR) ->
+ polyjump(
+ SR, fun exro928_next_state/1,
+ %% 2^20
+ [16#5B966A3DAF905E6, 16#601E9589C33DE2F,
+ 16#74A806C17E9E644, 16#59AFEB4F1DF6A43,
+ 16#46D8E75664A4268, 16#42E2C246BDA670C,
+ 16#4531FB8EBC73C70, 16#537F702069EFC52,
+ 16#4B6DC4D3AF15F8A, 16#5A4189F0050263D,
+ 16#46DF2EB1FEAF0FB, 16#77AC696A43CB9AC,
+ 16#4C5878C3549BD5B, 16#7CCF20BCF522920,
+ 16#415FEFCC78FF45E, 16#72CF460728C2FAF]).
+
+%% =====================================================================
%% exrop PRNG: Xoroshiro116+
%%
%% Reference URL: http://xorshift.di.unimi.it/
@@ -899,6 +1233,15 @@ exs1024_jump({L, RL}, AS, JL, J, N, TN) ->
-opaque exrop_state() :: nonempty_improper_list(uint58(), uint58()).
-dialyzer({no_improper_lists, exrop_seed/1}).
+
+exrop_seed(L) when is_list(L) ->
+ [S0,S1] = seed58_nz(2, L),
+ [S0|S1];
+exrop_seed(X) when is_integer(X) ->
+ [S0,S1] = seed58(2, ?MASK(64, X)),
+ [S0|S1];
+%%
+%% Traditional integer triplet seed
exrop_seed({A1, A2, A3}) ->
[_|S1] =
exrop_next_s(
@@ -962,6 +1305,142 @@ exrop_jump([S__0|S__1] = _S, S0, S1, J, Js) ->
end.
%% =====================================================================
+%% Mask and fill state list, ensure not all zeros
+%% =====================================================================
+
+seed58_nz(N, Ss) ->
+ seed_nz(N, Ss, 58, false).
+
+seed64_nz(N, Ss) ->
+ seed_nz(N, Ss, 64, false).
+
+seed_nz(_N, [], _M, false) ->
+ erlang:error(zero_seed);
+seed_nz(0, [_|_], _M, _NZ) ->
+ erlang:error(too_many_seed_integers);
+seed_nz(0, [], _M, _NZ) ->
+ [];
+seed_nz(N, [], M, true) ->
+ [0|seed_nz(N - 1, [], M, true)];
+seed_nz(N, [S|Ss], M, NZ) ->
+ if
+ is_integer(S) ->
+ R = ?MASK(M, S),
+ [R|seed_nz(N - 1, Ss, M, NZ orelse R =/= 0)];
+ true ->
+ erlang:error(non_integer_seed)
+ end.
+
+%% =====================================================================
+%% Splitmix seeders, lowest bits of SplitMix64, zeros skipped
+%% =====================================================================
+
+-spec seed58(non_neg_integer(), uint64()) -> list(uint58()).
+seed58(0, _X) ->
+ [];
+seed58(N, X) ->
+ {Z,NewX} = seed58(X),
+ [Z|seed58(N - 1, NewX)].
+%%
+seed58(X_0) ->
+ {Z0,X} = splitmix64_next(X_0),
+ case ?MASK(58, Z0) of
+ 0 ->
+ seed58(X);
+ Z ->
+ {Z,X}
+ end.
+
+-spec seed64(non_neg_integer(), uint64()) -> list(uint64()).
+seed64(0, _X) ->
+ [];
+seed64(N, X) ->
+ {Z,NewX} = seed64(X),
+ [Z|seed64(N - 1, NewX)].
+%%
+seed64(X_0) ->
+ {Z,X} = ZX = splitmix64_next(X_0),
+ if
+ Z =:= 0 ->
+ seed64(X);
+ true ->
+ ZX
+ end.
+
+%% The SplitMix64 generator:
+%%
+%% uint64_t splitmix64_next() {
+%% uint64_t z = (x += 0x9e3779b97f4a7c15);
+%% z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
+%% z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
+%% return z ^ (z >> 31);
+%% }
+%%
+splitmix64_next(X_0) ->
+ X = ?MASK(64, X_0 + 16#9e3779b97f4a7c15),
+ Z_0 = ?MASK(64, (X bxor (X bsr 30)) * 16#bf58476d1ce4e5b9),
+ Z_1 = ?MASK(64, (Z_0 bxor (Z_0 bsr 27)) * 16#94d049bb133111eb),
+ {?MASK(64, Z_1 bxor (Z_1 bsr 31)),X}.
+
+%% =====================================================================
+%% Polynomial jump with a jump constant word list,
+%% high bit in each word marking top of word,
+%% SR is a {Forward, Reverse} queue tuple with Forward never empty
+%% =====================================================================
+
+polyjump({Ss, Rs} = SR, NextState, JumpConst) ->
+ %% Create new state accumulator T
+ Ts = lists:duplicate(length(Ss) + length(Rs), 0),
+ polyjump(SR, NextState, JumpConst, Ts).
+%%
+%% Foreach jump word
+polyjump(_SR, _NextState, [], Ts) ->
+ %% Return new calculated state
+ {Ts, []};
+polyjump(SR, NextState, [J|Js], Ts) ->
+ polyjump(SR, NextState, Js, Ts, J).
+%%
+%% Foreach bit in jump word until top bit
+polyjump(SR, NextState, Js, Ts, 1) ->
+ polyjump(SR, NextState, Js, Ts);
+polyjump({Ss, Rs} = SR, NextState, Js, Ts, J) when J =/= 0 ->
+ NewSR = NextState(SR),
+ NewJ = J bsr 1,
+ case ?MASK(1, J) of
+ 0 ->
+ polyjump(NewSR, NextState, Js, Ts, NewJ);
+ 1 ->
+ %% Xor this state onto T
+ polyjump(NewSR, NextState, Js, xorzip_sr(Ts, Ss, Rs), NewJ)
+ end.
+
+xorzip_sr([], [], undefined) ->
+ [];
+xorzip_sr(Ts, [], Rs) ->
+ xorzip_sr(Ts, lists:reverse(Rs), undefined);
+xorzip_sr([T|Ts], [S|Ss], Rs) ->
+ [T bxor S|xorzip_sr(Ts, Ss, Rs)].
+
+%% =====================================================================
+
+format_jumpconst58(String) ->
+ ReOpts = [{newline,any},{capture,all_but_first,binary},global],
+ {match,Matches} = re:run(String, "0x([a-zA-Z0-9]+)", ReOpts),
+ format_jumcons58_matches(lists:reverse(Matches), 0).
+
+format_jumcons58_matches([], J) ->
+ format_jumpconst58_value(J);
+format_jumcons58_matches([[Bin]|Matches], J) ->
+ NewJ = (J bsl 64) bor binary_to_integer(Bin, 16),
+ format_jumcons58_matches(Matches, NewJ).
+
+format_jumpconst58_value(0) ->
+ ok;
+format_jumpconst58_value(J) ->
+ io:format("16#~s,~n", [integer_to_list(?MASK(58, J) bor ?BIT(58), 16)]),
+ format_jumpconst58_value(J bsr 58).
+
+%% =====================================================================
%% Ziggurat cont
%% =====================================================================
-define(NOR_R, 3.6541528853610087963519472518).
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index cd09872b87..9cd425db9a 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -108,7 +108,7 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-10.0","crypto-3.3",
+ {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-@OTP-15128@","crypto-3.3",
"compiler-5.0"]}
]}.
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 8d1cc09a8b..8c0b186288 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -19,8 +19,10 @@
{"%VSN%",
%% Up from - max one major revision back
[{<<"3\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.*
- {<<"3\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}],% OTP-21.*
+ {<<"3\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
+ {<<"3\\.6(\\.[0-9]+)*">>,[restart_new_emulator]}],% OTP-21.1
%% Down to - max one major revision back
[{<<"3\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.*
- {<<"3\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-20.*
+ {<<"3\\.5(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0
+ {<<"3\\.6(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21.1
}.
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 3597d6d94b..6418dc7eb6 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index fe324391af..65977a764a 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -3417,6 +3417,7 @@ otp_11709(Config) when is_list(Config) ->
ok.
%% OTP-13229. open_file() exits with badarg when given binary file name.
+%% Also OTP-15253.
otp_13229(_Config) ->
F = <<"binfile.tab">>,
try dets:open_file(name, [{file, F}]) of
@@ -3425,6 +3426,20 @@ otp_13229(_Config) ->
catch
error:badarg ->
ok
+ end,
+ try dets:open_file(F, []) of % OTP-15253
+ R2 ->
+ exit({open_succeeded, R2})
+ catch
+ error:badarg ->
+ ok
+ end,
+ try dets:open_file(F) of
+ R3 ->
+ exit({open_succeeded, R3})
+ catch
+ error:badarg ->
+ ok
end.
%% OTP-13260. Race when opening a table.
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index a3e294ffea..a90beed4f3 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -29,7 +29,7 @@
otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1,
otp_11728/1, encoding/1, extends/1, function_macro/1,
test_error/1, test_warning/1, otp_14285/1,
- test_if/1]).
+ test_if/1,source_name/1]).
-export([epp_parse_erl_form/2]).
@@ -70,7 +70,7 @@ all() ->
overload_mac, otp_8388, otp_8470, otp_8562,
otp_8665, otp_8911, otp_10302, otp_10820, otp_11728,
encoding, extends, function_macro, test_error, test_warning,
- otp_14285, test_if].
+ otp_14285, test_if, source_name].
groups() ->
[{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
@@ -1372,7 +1372,7 @@ otp_8562(Config) when is_list(Config) ->
otp_8911(Config) when is_list(Config) ->
case test_server:is_cover() of
true ->
- {skip, "Testing cover, so can not run when cover is already running"};
+ {skip, "Testing cover, so cannot run when cover is already running"};
false ->
do_otp_8911(Config)
end.
@@ -1702,6 +1702,18 @@ function_macro(Config) ->
ok.
+source_name(Config) when is_list(Config) ->
+ DataDir = proplists:get_value(data_dir, Config),
+ File = filename:join(DataDir, "source_name.erl"),
+
+ source_name_1(File, "/test/gurka.erl"),
+ source_name_1(File, "gaffel.erl"),
+
+ ok.
+
+source_name_1(File, Expected) ->
+ Res = epp:parse_file(File, [{source_name, Expected}]),
+ {ok, [{attribute,_,file,{Expected,_}} | _Forms]} = Res.
check(Config, Tests) ->
eval_tests(Config, fun check_test/2, Tests).
diff --git a/lib/otp_mibs/src/otp_mibs.appup.src b/lib/stdlib/test/epp_SUITE_data/source_name.erl
index 9437ae2222..71ad2dddb9 100644
--- a/lib/otp_mibs/src/otp_mibs.appup.src
+++ b/lib/stdlib/test/epp_SUITE_data/source_name.erl
@@ -1,7 +1,7 @@
-%% -*- erlang -*-
+%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -16,7 +16,12 @@
%% limitations under the License.
%%
%% %CopyrightEnd%
-{"%VSN%",
- [{<<".*">>,[{restart_application, otp_mibs}]}],
- [{<<".*">>,[{restart_application, otp_mibs}]}]
-}.
+%%
+
+-module(source_name).
+-export([ok/0]).
+
+%% Changing source name should not affect headers
+-include("bar.hrl").
+
+ok() -> ok.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index f9ab83a120..c1613a7273 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -2730,7 +2730,7 @@ bif_clash(Config) when is_list(Config) ->
[],
{errors,[{2,erl_lint,{call_to_redefined_old_bif,{size,1}}}],[]}},
- %% Verify that warnings can not be turned off in the old way.
+ %% Verify that warnings cannot be turned off in the old way.
{clash2,
<<"-export([t/1,size/1]).
t(X) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index fee8b204f4..e49181b12f 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -41,7 +41,7 @@
-export([t_delete_object/1, t_init_table/1, t_whitebox/1,
select_bound_chunk/1,
t_delete_all_objects/1, t_insert_list/1, t_test_ms/1,
- t_select_delete/1,t_select_replace/1,t_ets_dets/1]).
+ t_select_delete/1,t_select_replace/1,t_select_replace_next_bug/1,t_ets_dets/1]).
-export([ordered/1, ordered_match/1, interface_equality/1,
fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
@@ -66,7 +66,9 @@
meta_lookup_named_read/1, meta_lookup_named_write/1,
meta_newdel_unnamed/1, meta_newdel_named/1]).
-export([smp_insert/1, smp_fixed_delete/1, smp_unfix_fix/1, smp_select_delete/1,
- smp_select_replace/1, otp_8166/1, otp_8732/1]).
+ smp_ordered_iteration/1,
+ smp_select_replace/1, otp_8166/1, otp_8732/1, delete_unfix_race/1]).
+-export([throughput_benchmark/0, test_throughput_benchmark/1]).
-export([exit_large_table_owner/1,
exit_many_large_table_owner/1,
exit_many_tables_owner/1,
@@ -125,13 +127,15 @@ all() ->
select_bound_chunk,
t_init_table, t_whitebox, t_delete_all_objects,
t_insert_list, t_test_ms, t_select_delete, t_select_replace,
+ t_select_replace_next_bug,
t_ets_dets, memory, t_select_reverse, t_bucket_disappears,
t_named_select,
select_fail, t_insert_new, t_repair_continuation,
otp_5340, otp_6338, otp_6842_select_1000, otp_7665,
otp_8732, meta_wb, grow_shrink, grow_pseudo_deleted,
shrink_pseudo_deleted, {group, meta_smp}, smp_insert,
- smp_fixed_delete, smp_unfix_fix, smp_select_replace,
+ smp_fixed_delete, smp_unfix_fix, smp_select_replace,
+ smp_ordered_iteration,
smp_select_delete, otp_8166, exit_large_table_owner,
exit_many_large_table_owner, exit_many_tables_owner,
exit_many_many_tables_owner, write_concurrency, heir,
@@ -142,7 +146,9 @@ all() ->
ets_all,
massive_ets_all,
take,
- whereis_table].
+ whereis_table,
+ delete_unfix_race,
+ test_throughput_benchmark].
groups() ->
[{new, [],
@@ -741,7 +747,7 @@ select_bound_chunk(_Config) ->
repeat_for_opts(fun select_bound_chunk_do/1, [all_types]).
select_bound_chunk_do(Opts) ->
- T = ets:new(x, Opts),
+ T = ets_new(x, Opts),
ets:insert(T, [{key, 1}]),
{[{key, 1}], '$end_of_table'} = ets:select(T, [{{key,1},[],['$_']}], 100000),
ok.
@@ -787,38 +793,42 @@ check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
%% Test ets:delete_all_objects/1.
t_delete_all_objects(Config) when is_list(Config) ->
EtsMem = etsmem(),
- repeat_for_opts(fun t_delete_all_objects_do/1),
+ repeat_for_opts_all_set_table_types(fun t_delete_all_objects_do/1),
verify_etsmem(EtsMem).
get_kept_objects(T) ->
case ets:info(T,stats) of
- false ->
- 0;
{_,_,_,_,_,_,KO} ->
- KO
+ KO;
+ _ ->
+ 0
end.
t_delete_all_objects_do(Opts) ->
- T=ets_new(x,Opts),
- filltabint(T,4000),
+ KeyRange = 4000,
+ T=ets_new(x, Opts, KeyRange),
+ filltabint(T,KeyRange),
O=ets:first(T),
ets:next(T,O),
ets:safe_fixtable(T,true),
true = ets:delete_all_objects(T),
'$end_of_table' = ets:next(T,O),
0 = ets:info(T,size),
- 4000 = get_kept_objects(T),
+ case ets:info(T,type) of
+ ordered_set -> ok;
+ _ -> KeyRange = get_kept_objects(T)
+ end,
ets:safe_fixtable(T,false),
0 = ets:info(T,size),
0 = get_kept_objects(T),
- filltabint(T,4000),
- 4000 = ets:info(T,size),
+ filltabint(T, KeyRange),
+ KeyRange = ets:info(T,size),
true = ets:delete_all_objects(T),
0 = ets:info(T,size),
ets:delete(T),
%% Test delete_all_objects is atomic
- T2 = ets:new(t_delete_all_objects, [public | Opts]),
+ T2 = ets_new(t_delete_all_objects, [public | Opts]),
Self = self(),
Inserters = [spawn_link(fun() -> inserter(T2, 100*1000, 1, Self) end) || _ <- [1,2,3,4]],
[receive {Ipid, running} -> ok end || Ipid <- Inserters],
@@ -1465,6 +1475,25 @@ t_select_replace(Config) when is_list(Config) ->
verify_etsmem(EtsMem).
+%% OTP-15346: Bug caused select_replace of bound key to corrupt static stack
+%% used by ets:next and ets:prev.
+t_select_replace_next_bug(Config) when is_list(Config) ->
+ T = ets:new(k, [ordered_set]),
+ [ets:insert(T, {I, value}) || I <- lists:seq(1,10)],
+ 1 = ets:first(T),
+
+ %% Make sure select_replace does not leave pointer
+ %% to deallocated {2,value} in static stack.
+ MS = [{{2,value}, [], [{{2,"new_value"}}]}],
+ 1 = ets:select_replace(T, MS),
+
+ %% This would crash or give wrong result at least on DEBUG emulator
+ %% where deallocated memory is overwritten.
+ 2 = ets:next(T, 1),
+
+ ets:delete(T).
+
+
%% Test that partly bound keys gives faster matches.
partly_bound(Config) when is_list(Config) ->
case os:type() of
@@ -2351,17 +2380,29 @@ write_concurrency(Config) when is_list(Config) ->
Yes6 = ets_new(foo,[duplicate_bag,protected,{write_concurrency,true}]),
No3 = ets_new(foo,[duplicate_bag,private,{write_concurrency,true}]),
- No4 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]),
- No5 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]),
- No6 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]),
-
- No7 = ets_new(foo,[public,{write_concurrency,false}]),
- No8 = ets_new(foo,[protected,{write_concurrency,false}]),
+ Yes7 = ets_new(foo,[ordered_set,public,{write_concurrency,true}]),
+ Yes8 = ets_new(foo,[ordered_set,protected,{write_concurrency,true}]),
+ Yes9 = ets_new(foo,[ordered_set,{write_concurrency,true}]),
+ Yes10 = ets_new(foo,[{write_concurrency,true},ordered_set,public]),
+ Yes11 = ets_new(foo,[{write_concurrency,true},ordered_set,protected]),
+ Yes12 = ets_new(foo,[set,{write_concurrency,false},
+ {write_concurrency,true},ordered_set,public]),
+ Yes13 = ets_new(foo,[private,public,set,{write_concurrency,false},
+ {write_concurrency,true},ordered_set]),
+ No4 = ets_new(foo,[ordered_set,private,{write_concurrency,true}]),
+ No5 = ets_new(foo,[ordered_set,public,{write_concurrency,false}]),
+ No6 = ets_new(foo,[ordered_set,protected,{write_concurrency,false}]),
+ No7 = ets_new(foo,[ordered_set,private,{write_concurrency,false}]),
+
+ No8 = ets_new(foo,[public,{write_concurrency,false}]),
+ No9 = ets_new(foo,[protected,{write_concurrency,false}]),
YesMem = ets:info(Yes1,memory),
NoHashMem = ets:info(No1,memory),
+ YesTreeMem = ets:info(Yes7,memory),
NoTreeMem = ets:info(No4,memory),
- io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p\n",[YesMem,NoHashMem,NoTreeMem]),
+ io:format("YesMem=~p NoHashMem=~p NoTreeMem=~p YesTreeMem=~p\n",[YesMem,NoHashMem,
+ NoTreeMem,YesTreeMem]),
YesMem = ets:info(Yes2,memory),
YesMem = ets:info(Yes3,memory),
@@ -2370,13 +2411,24 @@ write_concurrency(Config) when is_list(Config) ->
YesMem = ets:info(Yes6,memory),
NoHashMem = ets:info(No2,memory),
NoHashMem = ets:info(No3,memory),
+ YesTreeMem = ets:info(Yes7,memory),
+ YesTreeMem = ets:info(Yes8,memory),
+ YesTreeMem = ets:info(Yes9,memory),
+ YesTreeMem = ets:info(Yes10,memory),
+ YesTreeMem = ets:info(Yes11,memory),
+ YesTreeMem = ets:info(Yes12,memory),
+ YesTreeMem = ets:info(Yes13,memory),
+ NoTreeMem = ets:info(No4,memory),
NoTreeMem = ets:info(No5,memory),
NoTreeMem = ets:info(No6,memory),
- NoHashMem = ets:info(No7,memory),
+ NoTreeMem = ets:info(No7,memory),
NoHashMem = ets:info(No8,memory),
+ NoHashMem = ets:info(No9,memory),
true = YesMem > NoHashMem,
true = YesMem > NoTreeMem,
+ true = YesMem > YesTreeMem,
+ true = YesTreeMem < NoTreeMem,
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency,foo}])),
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,{write_concurrency}])),
@@ -2384,8 +2436,8 @@ write_concurrency(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch ets_new(foo,[public,write_concurrency])),
lists:foreach(fun(T) -> ets:delete(T) end,
- [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6,
- No1,No2,No3,No4,No5,No6,No7,No8]),
+ [Yes1,Yes2,Yes3,Yes4,Yes5,Yes6,Yes7,Yes8,Yes9,Yes10,Yes11,Yes12,Yes13,
+ No1,No2,No3,No4,No5,No6,No7,No8,No9]),
verify_etsmem(EtsMem),
ok.
@@ -3030,41 +3082,43 @@ pick_all_backwards(T) ->
%% Small test case for both set and bag type ets tables.
setbag(Config) when is_list(Config) ->
EtsMem = etsmem(),
- Set = ets_new(set,[set]),
- Bag = ets_new(bag,[bag]),
- Key = {foo,bar},
-
- %% insert some value
- ets:insert(Set,{Key,val1}),
- ets:insert(Bag,{Key,val1}),
-
- %% insert new value for same key again
- ets:insert(Set,{Key,val2}),
- ets:insert(Bag,{Key,val2}),
-
- %% check
- [{Key,val2}] = ets:lookup(Set,Key),
- [{Key,val1},{Key,val2}] = ets:lookup(Bag,Key),
-
- true = ets:delete(Set),
- true = ets:delete(Bag),
+ lists:foreach(fun(SetType) ->
+ Set = ets_new(SetType,[SetType]),
+ Bag = ets_new(bag,[bag]),
+ Key = {foo,bar},
+
+ %% insert some value
+ ets:insert(Set,{Key,val1}),
+ ets:insert(Bag,{Key,val1}),
+
+ %% insert new value for same key again
+ ets:insert(Set,{Key,val2}),
+ ets:insert(Bag,{Key,val2}),
+
+ %% check
+ [{Key,val2}] = ets:lookup(Set,Key),
+ [{Key,val1},{Key,val2}] = ets:lookup(Bag,Key),
+
+ true = ets:delete(Set),
+ true = ets:delete(Bag)
+ end, [set, cat_ord_set,stim_cat_ord_set,ordered_set]),
verify_etsmem(EtsMem).
%% Test case to check proper return values for illegal ets_new() calls.
badnew(Config) when is_list(Config) ->
EtsMem = etsmem(),
- {'EXIT',{badarg,_}} = (catch ets_new(12,[])),
- {'EXIT',{badarg,_}} = (catch ets_new({a,b},[])),
- {'EXIT',{badarg,_}} = (catch ets_new(name,[foo])),
- {'EXIT',{badarg,_}} = (catch ets_new(name,{bag})),
- {'EXIT',{badarg,_}} = (catch ets_new(name,bag)),
+ {'EXIT',{badarg,_}} = (catch ets:new(12,[])),
+ {'EXIT',{badarg,_}} = (catch ets:new({a,b},[])),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,[foo])),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,{bag})),
+ {'EXIT',{badarg,_}} = (catch ets:new(name,bag)),
verify_etsmem(EtsMem).
%% OTP-2314. Test case to check that a non-proper list does not
%% crash the emulator.
verybadnew(Config) when is_list(Config) ->
EtsMem = etsmem(),
- {'EXIT',{badarg,_}} = (catch ets_new(verybad,[set|protected])),
+ {'EXIT',{badarg,_}} = (catch ets:new(verybad,[set|protected])),
verify_etsmem(EtsMem).
%% Small check to see if named tables work.
@@ -3080,11 +3134,13 @@ named(Config) when is_list(Config) ->
%% Test case to check if specified keypos works.
keypos2(Config) when is_list(Config) ->
EtsMem = etsmem(),
- Tab = make_table(foo,
- [set,{keypos,2}],
- [{val,key}, {val2,key}]),
- [{val2,key}] = ets:lookup(Tab,key),
- true = ets:delete(Tab),
+ lists:foreach(fun(SetType) ->
+ Tab = make_table(foo,
+ [SetType,{keypos,2}],
+ [{val,key}, {val2,key}]),
+ [{val2,key}] = ets:lookup(Tab,key),
+ true = ets:delete(Tab)
+ end, [set, cat_ord_set,stim_cat_ord_set,ordered_set]),
verify_etsmem(EtsMem).
%% Privacy check. Check that a named(public/private/protected) table
@@ -3176,7 +3232,7 @@ rotate_tuple(Tuple, N) ->
%% Check lookup in an empty table and lookup of a non-existing key.
empty(Config) when is_list(Config) ->
- repeat_for_opts(fun empty_do/1).
+ repeat_for_opts_all_table_types(fun empty_do/1).
empty_do(Opts) ->
EtsMem = etsmem(),
@@ -3189,7 +3245,7 @@ empty_do(Opts) ->
%% Check proper return values for illegal insert operations.
badinsert(Config) when is_list(Config) ->
- repeat_for_opts(fun badinsert_do/1).
+ repeat_for_opts_all_table_types(fun badinsert_do/1).
badinsert_do(Opts) ->
EtsMem = etsmem(),
@@ -3213,7 +3269,7 @@ badinsert_do(Opts) ->
time_lookup(Config) when is_list(Config) ->
%% just for timing, really
EtsMem = etsmem(),
- Values = repeat_for_opts(fun time_lookup_do/1),
+ Values = repeat_for_opts_all_table_types(fun time_lookup_do/1),
verify_etsmem(EtsMem),
{comment,lists:flatten(io_lib:format(
"~p ets lookups/s",[Values]))}.
@@ -3410,19 +3466,29 @@ delete_tab_do(Opts) ->
%% Check that ets:delete/1 works and that other processes can run.
delete_large_tab(Config) when is_list(Config) ->
- ct:timetrap({minutes,30}), %% valgrind needs a lot
- Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
+ ct:timetrap({minutes,60}), %% valgrind needs a lot
+ KeyRange = 16#ffffff,
+ Data = [{erlang:phash2(I, KeyRange),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
- repeat_for_opts(fun(Opts) -> delete_large_tab_do(Opts,Data) end),
+ repeat_for_opts(fun(Opts) -> delete_large_tab_do(key_range(Opts,KeyRange),
+ Data) end),
verify_etsmem(EtsMem).
delete_large_tab_do(Opts,Data) ->
delete_large_tab_1(foo_hash, Opts, Data, false),
delete_large_tab_1(foo_tree, [ordered_set | Opts], Data, false),
- delete_large_tab_1(foo_hash, Opts, Data, true).
+ delete_large_tab_1(foo_tree, [stim_cat_ord_set | Opts], Data, false),
+ delete_large_tab_1(foo_hash_fix, Opts, Data, true).
delete_large_tab_1(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ delete_large_tab_2(Name, Flags, Data, Fix)
+ end.
+
+delete_large_tab_2(Name, Flags, Data, Fix) ->
Tab = ets_new(Name, Flags),
ets:insert(Tab, Data),
@@ -3481,18 +3547,30 @@ delete_large_tab_1(Name, Flags, Data, Fix) ->
%% Delete a large name table and try to create a new table with
%% the same name in another process.
delete_large_named_table(Config) when is_list(Config) ->
- Data = [{erlang:phash2(I, 16#ffffff),I} || I <- lists:seq(1, 200000)],
+ KeyRange = 16#ffffff,
+ Data = [{erlang:phash2(I, KeyRange),I} || I <- lists:seq(1, 200000)],
EtsMem = etsmem(),
- repeat_for_opts(fun(Opts) -> delete_large_named_table_do(Opts,Data) end),
+ repeat_for_opts(fun(Opts) ->
+ delete_large_named_table_do(key_range(Opts,KeyRange),
+ Data)
+ end),
verify_etsmem(EtsMem),
ok.
delete_large_named_table_do(Opts,Data) ->
delete_large_named_table_1(foo_hash, [named_table | Opts], Data, false),
delete_large_named_table_1(foo_tree, [ordered_set,named_table | Opts], Data, false),
+ delete_large_named_table_1(foo_tree, [stim_cat_ord_set,named_table | Opts], Data, false),
delete_large_named_table_1(foo_hash, [named_table | Opts], Data, true).
delete_large_named_table_1(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ delete_large_named_table_2(Name, Flags, Data, Fix)
+ end.
+
+delete_large_named_table_2(Name, Flags, Data, Fix) ->
Tab = ets_new(Name, Flags),
ets:insert(Tab, Data),
@@ -3516,8 +3594,12 @@ delete_large_named_table_1(Name, Flags, Data, Fix) ->
%% Delete a large table, and kill the process during the delete.
evil_delete(Config) when is_list(Config) ->
- Data = [{I,I*I} || I <- lists:seq(1, 100000)],
- repeat_for_opts(fun(Opts) -> evil_delete_do(Opts,Data) end).
+ KeyRange = 100000,
+ Data = [{I,I*I} || I <- lists:seq(1, KeyRange)],
+ repeat_for_opts(fun(Opts) ->
+ evil_delete_do(key_range(Opts,KeyRange),
+ Data)
+ end).
evil_delete_do(Opts,Data) ->
EtsMem = etsmem(),
@@ -3527,16 +3609,27 @@ evil_delete_do(Opts,Data) ->
verify_etsmem(EtsMem),
evil_delete_owner(foo_tree, [ordered_set | Opts], Data, false),
verify_etsmem(EtsMem),
+ evil_delete_owner(foo_catree, [stim_cat_ord_set | Opts], Data, false),
+ verify_etsmem(EtsMem),
TabA = evil_delete_not_owner(foo_hash, Opts, Data, false),
verify_etsmem(EtsMem),
TabB = evil_delete_not_owner(foo_hash, Opts, Data, true),
verify_etsmem(EtsMem),
TabC = evil_delete_not_owner(foo_tree, [ordered_set | Opts], Data, false),
verify_etsmem(EtsMem),
+ TabD = evil_delete_not_owner(foo_catree, [stim_cat_ord_set | Opts], Data, false),
+ verify_etsmem(EtsMem),
lists:foreach(fun(T) -> undefined = ets:info(T) end,
- [TabA,TabB,TabC]).
+ [TabA,TabB,TabC,TabD]).
evil_delete_not_owner(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ evil_delete_not_owner_1(Name, Flags, Data, Fix)
+ end.
+
+evil_delete_not_owner_1(Name, Flags, Data, Fix) ->
io:format("Not owner: ~p, fix = ~p", [Name,Fix]),
Tab = ets_new(Name, [public|Flags]),
ets:insert(Tab, Data),
@@ -3562,6 +3655,13 @@ evil_delete_not_owner(Name, Flags, Data, Fix) ->
Tab.
evil_delete_owner(Name, Flags, Data, Fix) ->
+ case is_redundant_opts_combo(Flags) of
+ true -> skip;
+ false ->
+ evil_delete_owner_1(Name, Flags, Data, Fix)
+ end.
+
+evil_delete_owner_1(Name, Flags, Data, Fix) ->
Fun = fun() ->
Tab = ets_new(Name, [public|Flags]),
ets:insert(Tab, Data),
@@ -3749,7 +3849,7 @@ verify_rescheduling_exit(Config, ForEachData, Flags, Fix, NOTabs, NOProcs) ->
%% Make sure that slots for ets tables are cleared properly.
table_leak(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> table_leak_1(Opts,20000) end).
+ repeat_for_opts_all_non_stim_table_types(fun(Opts) -> table_leak_1(Opts,20000) end).
table_leak_1(_,0) -> ok;
table_leak_1(Opts,N) ->
@@ -3812,7 +3912,7 @@ match_delete3_do(Opts) ->
%% Test ets:first/1 & ets:next/2.
firstnext(Config) when is_list(Config) ->
- repeat_for_opts(fun firstnext_do/1).
+ repeat_for_opts_all_set_table_types(fun firstnext_do/1).
firstnext_do(Opts) ->
EtsMem = etsmem(),
@@ -3834,15 +3934,20 @@ firstnext_collect(Tab,Key,List) ->
%% Tests ets:first/1 & ets:next/2.
firstnext_concurrent(Config) when is_list(Config) ->
- register(master, self()),
- ets_init(?MODULE, 20),
- [dynamic_go() || _ <- lists:seq(1, 2)],
- receive
- after 5000 -> ok
- end.
+ lists:foreach(
+ fun(TableType) ->
+ register(master, self()),
+ TableName = list_to_atom(atom_to_list(?MODULE) ++ atom_to_list(TableType)),
+ ets_init(TableName, 20, TableType),
+ [dynamic_go(TableName) || _ <- lists:seq(1, 2)],
+ receive
+ after 5000 -> ok
+ end,
+ unregister(master)
+ end, repeat_for_opts_atom2list(ord_set_types)).
-ets_init(Tab, N) ->
- ets_new(Tab, [named_table,public,ordered_set]),
+ets_init(Tab, N, TableType) ->
+ ets_new(Tab, [named_table,public,TableType]),
cycle(Tab, lists:seq(1,N+1)).
cycle(_Tab, [H|T]) when H > length(T)-> ok;
@@ -3850,9 +3955,9 @@ cycle(Tab, L) ->
ets:insert(Tab,list_to_tuple(L)),
cycle(Tab, tl(L)++[hd(L)]).
-dynamic_go() -> my_spawn_link(fun dynamic_init/0).
+dynamic_go(TableName) -> my_spawn_link(fun() -> dynamic_init(TableName) end).
-dynamic_init() -> [dyn_lookup(?MODULE) || _ <- lists:seq(1, 10)].
+dynamic_init(TableName) -> [dyn_lookup(TableName) || _ <- lists:seq(1, 10)].
dyn_lookup(T) -> dyn_lookup(T, ets:first(T)).
@@ -3870,7 +3975,7 @@ dyn_lookup(T, K) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
slot(Config) when is_list(Config) ->
- repeat_for_opts(fun slot_do/1).
+ repeat_for_opts_all_set_table_types(fun slot_do/1).
slot_do(Opts) ->
EtsMem = etsmem(),
@@ -3895,7 +4000,7 @@ slot_loop(Tab,SlotNo,EltsSoFar) ->
match1(Config) when is_list(Config) ->
- repeat_for_opts(fun match1_do/1).
+ repeat_for_opts_all_set_table_types(fun match1_do/1).
match1_do(Opts) ->
EtsMem = etsmem(),
@@ -3958,7 +4063,7 @@ match2_do(Opts) ->
%% Some ets:match_object tests.
match_object(Config) when is_list(Config) ->
- repeat_for_opts(fun match_object_do/1).
+ repeat_for_opts_all_set_table_types(fun match_object_do/1).
match_object_do(Opts) ->
EtsMem = etsmem(),
@@ -4058,23 +4163,16 @@ match_object_do(Opts) ->
%% Tests that db_match_object does not generate a `badarg' when
%% resuming a search with no previous matches.
match_object2(Config) when is_list(Config) ->
- repeat_for_opts(fun match_object2_do/1).
+ repeat_for_opts_all_table_types(fun match_object2_do/1).
match_object2_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foo, [bag, {keypos, 2} | Opts]),
- fill_tab2(Tab, 0, 13005), % match_db_object does 1000
+ KeyRange = 13005,
+ Tab = ets_new(foo, [{keypos, 2} | Opts], KeyRange),
+ fill_tab2(Tab, 0, KeyRange), % match_db_object does 1000
% elements per pass, might
% change in the future.
- case catch ets:match_object(Tab, {hej, '$1'}) of
- {'EXIT', _} ->
- ets:delete(Tab),
- ct:fail("match_object EXIT:ed");
- [] ->
- io:format("Nothing matched.");
- List ->
- io:format("Matched:~p~n",[List])
- end,
+ [] = ets:match_object(Tab, {hej, '$1'}),
ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -4083,18 +4181,21 @@ match_object2_do(Opts) ->
%% OTP-3319. Test tab2list.
tab2list(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- Tab = make_table(foo,
- [ordered_set],
- [{a,b}, {c,b}, {b,b}, {a,c}]),
- [{a,c},{b,b},{c,b}] = ets:tab2list(Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ Tab = make_table(foo,
+ Opts,
+ [{a,b}, {c,b}, {b,b}, {a,c}]),
+ [{a,c},{b,b},{c,b}] = ets:tab2list(Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end).
%% Simple general small test. If this fails, ets is in really bad
%% shape.
misc1(Config) when is_list(Config) ->
- repeat_for_opts(fun misc1_do/1).
+ repeat_for_opts_all_table_types(fun misc1_do/1).
misc1_do(Opts) ->
EtsMem = etsmem(),
@@ -4112,7 +4213,7 @@ misc1_do(Opts) ->
%% Check the safe_fixtable function.
safe_fixtable(Config) when is_list(Config) ->
- repeat_for_opts(fun safe_fixtable_do/1).
+ repeat_for_opts_all_table_types(fun safe_fixtable_do/1).
safe_fixtable_do(Opts) ->
EtsMem = etsmem(),
@@ -4170,10 +4271,42 @@ safe_fixtable_do(Opts) ->
%% Tests ets:info result for required tuples.
info(Config) when is_list(Config) ->
- repeat_for_opts(fun info_do/1).
+ repeat_for_opts_all_table_types(fun info_do/1).
info_do(Opts) ->
EtsMem = etsmem(),
+ TableType = lists:foldl(
+ fun(Item, Curr) ->
+ case Item of
+ set -> set;
+ ordered_set -> ordered_set;
+ cat_ord_set -> ordered_set;
+ stim_cat_ord_set -> ordered_set;
+ bag -> bag;
+ duplicate_bag -> duplicate_bag;
+ _ -> Curr
+ end
+ end, set, Opts),
+ PublicOrCurr =
+ fun(Curr) ->
+ case lists:member({write_concurrency, false}, Opts) or
+ lists:member(private, Opts) or
+ lists:member(protected, Opts) of
+ true -> Curr;
+ false -> public
+ end
+ end,
+ Protection = lists:foldl(
+ fun(Item, Curr) ->
+ case Item of
+ public -> public;
+ protected -> protected;
+ private -> private;
+ cat_ord_set -> PublicOrCurr(Curr); %% Special items
+ stim_cat_ord_set -> PublicOrCurr(Curr);
+ _ -> Curr
+ end
+ end, protected, Opts),
MeMyselfI=self(),
ThisNode=node(),
Tab = ets_new(foobar, [{keypos, 2} | Opts]),
@@ -4187,9 +4320,9 @@ info_do(Opts) ->
{value, {size, 0}} = lists:keysearch(size, 1, Res),
{value, {node, ThisNode}} = lists:keysearch(node, 1, Res),
{value, {named_table, false}} = lists:keysearch(named_table, 1, Res),
- {value, {type, set}} = lists:keysearch(type, 1, Res),
+ {value, {type, TableType}} = lists:keysearch(type, 1, Res),
{value, {keypos, 2}} = lists:keysearch(keypos, 1, Res),
- {value, {protection, protected}} =
+ {value, {protection, Protection}} =
lists:keysearch(protection, 1, Res),
{value, {id, Tab}} = lists:keysearch(id, 1, Res),
true = ets:delete(Tab),
@@ -4234,20 +4367,29 @@ dups_do(Opts) ->
%% Test the ets:tab2file function on an empty ets table.
tab2file(Config) when is_list(Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"tab2file_case"]),
- tab2file_do(FName, []),
- tab2file_do(FName, [{sync,true}]),
- tab2file_do(FName, [{sync,false}]),
- {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [{sync,yes}])),
- {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [sync])),
+ tab2file_do(FName, [], set),
+ tab2file_do(FName, [], ordered_set),
+ tab2file_do(FName, [], cat_ord_set),
+ tab2file_do(FName, [], stim_cat_ord_set),
+ tab2file_do(FName, [{sync,true}], set),
+ tab2file_do(FName, [{sync,false}], set),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [{sync,yes}], set)),
+ {'EXIT',{{badmatch,{error,_}},_}} = (catch tab2file_do(FName, [sync], set)),
ok.
-tab2file_do(FName, Opts) ->
+tab2file_do(FName, Opts, TableType) ->
%% Write an empty ets table to a file, read back and check properties.
- Tab = ets_new(ets_SUITE_foo_tab, [named_table, set, public,
+ Tab = ets_new(ets_SUITE_foo_tab, [named_table, TableType, public,
{keypos, 2},
compressed,
{write_concurrency,true},
{read_concurrency,true}]),
+ ActualTableType =
+ case TableType of
+ cat_ord_set -> ordered_set;
+ stim_cat_ord_set -> ordered_set;
+ _ -> TableType
+ end,
catch file:delete(FName),
Res = ets:tab2file(Tab, FName, Opts),
true = ets:delete(Tab),
@@ -4258,7 +4400,7 @@ tab2file_do(FName, Opts) ->
public = ets:info(Tab2, protection),
true = ets:info(Tab2, named_table),
2 = ets:info(Tab2, keypos),
- set = ets:info(Tab2, type),
+ ActualTableType = ets:info(Tab2, type),
true = ets:info(Tab2, compressed),
Smp = erlang:system_info(smp_support),
Smp = ets:info(Tab2, read_concurrency),
@@ -4271,14 +4413,15 @@ tab2file_do(FName, Opts) ->
tab2file2(Config) when is_list(Config) ->
repeat_for_opts(fun(Opts) ->
tab2file2_do(Opts, Config)
- end, [[set,bag],compressed]).
+ end, [[stim_cat_ord_set,cat_ord_set,set,bag],compressed]).
tab2file2_do(Opts, Config) ->
EtsMem = etsmem(),
- Tab = ets_new(ets_SUITE_foo_tab, [named_table, private,
- {keypos, 2} | Opts]),
+ KeyRange = 10000,
+ Tab = ets_new(ets_SUITE_foo_tab, [named_table, private, {keypos, 2} | Opts],
+ KeyRange),
FName = filename:join([proplists:get_value(priv_dir, Config),"tab2file2_case"]),
- ok = fill_tab2(Tab, 0, 10000), % Fill up the table (grucho mucho!)
+ ok = fill_tab2(Tab, 0, KeyRange), % Fill up the table (grucho mucho!)
Len = length(ets:tab2list(Tab)),
Mem = ets:info(Tab, memory),
Type = ets:info(Tab, type),
@@ -4332,13 +4475,14 @@ fill_tab2(Tab, Val, Num) ->
%% Test verification of tables with object count extended_info.
tabfile_ext1(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> tabfile_ext1_do(Opts, Config) end).
+ repeat_for_opts_all_set_table_types(fun(Opts) -> tabfile_ext1_do(Opts, Config) end).
tabfile_ext1_do(Opts,Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"nisse.dat"]),
FName2 = filename:join([proplists:get_value(priv_dir, Config),"countflip.dat"]),
- L = lists:seq(1,10),
- T = ets_new(x,Opts),
+ KeyRange = 10,
+ L = lists:seq(1,KeyRange),
+ T = ets_new(x,Opts,KeyRange),
Name = make_ref(),
[ets:insert(T,{X,integer_to_list(X)}) || X <- L],
ok = ets:tab2file(T,FName,[{extended_info,[object_count]}]),
@@ -4370,13 +4514,14 @@ tabfile_ext1_do(Opts,Config) ->
%% Test verification of tables with md5sum extended_info.
tabfile_ext2(Config) when is_list(Config) ->
- repeat_for_opts(fun(Opts) -> tabfile_ext2_do(Opts,Config) end).
+ repeat_for_opts_all_set_table_types(fun(Opts) -> tabfile_ext2_do(Opts,Config) end).
tabfile_ext2_do(Opts,Config) ->
FName = filename:join([proplists:get_value(priv_dir, Config),"olle.dat"]),
FName2 = filename:join([proplists:get_value(priv_dir, Config),"bitflip.dat"]),
- L = lists:seq(1,10),
- T = ets_new(x,Opts),
+ KeyRange = 10,
+ L = lists:seq(1, KeyRange),
+ T = ets_new(x, Opts, KeyRange),
Name = make_ref(),
[ets:insert(T,{X,integer_to_list(X)}) || X <- L],
ok = ets:tab2file(T,FName,[{extended_info,[md5sum]}]),
@@ -4407,71 +4552,77 @@ tabfile_ext2_do(Opts,Config) ->
%% Test verification of (named) tables without extended info.
tabfile_ext3(Config) when is_list(Config) ->
- FName = filename:join([proplists:get_value(priv_dir, Config),"namn.dat"]),
- FName2 = filename:join([proplists:get_value(priv_dir, Config),"ncountflip.dat"]),
- L = lists:seq(1,10),
- Name = make_ref(),
- ?MODULE = ets_new(?MODULE,[named_table]),
- [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L],
- ets:tab2file(?MODULE,FName),
- {error,cannot_create_table} = ets:file2tab(FName),
- true = ets:delete(?MODULE),
- {ok,?MODULE} = ets:file2tab(FName),
- true = ets:delete(?MODULE),
- disk_log:open([{name,Name},{file,FName}]),
- {_,[H2|T2]} = disk_log:chunk(Name,start),
- disk_log:close(Name),
- NewT2=lists:keydelete(8,1,T2),
- file:delete(FName2),
- disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
- disk_log:log_terms(Name,[H2|NewT2]),
- disk_log:close(Name),
- 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
- true = ets:delete(?MODULE),
- {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
- {'EXIT',_} = (catch ets:delete(?MODULE)),
- {ok,_} = ets:tabfile_info(FName2),
- {ok,_} = ets:tabfile_info(FName),
- file:delete(FName),
- file:delete(FName2),
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ FName = filename:join([proplists:get_value(priv_dir, Config),"namn.dat"]),
+ FName2 = filename:join([proplists:get_value(priv_dir, Config),"ncountflip.dat"]),
+ L = lists:seq(1,10),
+ Name = make_ref(),
+ ?MODULE = ets_new(?MODULE,[named_table|Opts]),
+ [ets:insert(?MODULE,{X,integer_to_list(X)}) || X <- L],
+ ets:tab2file(?MODULE,FName),
+ {error,cannot_create_table} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ {ok,?MODULE} = ets:file2tab(FName),
+ true = ets:delete(?MODULE),
+ disk_log:open([{name,Name},{file,FName}]),
+ {_,[H2|T2]} = disk_log:chunk(Name,start),
+ disk_log:close(Name),
+ NewT2=lists:keydelete(8,1,T2),
+ file:delete(FName2),
+ disk_log:open([{name,Name},{file,FName2},{mode,read_write}]),
+ disk_log:log_terms(Name,[H2|NewT2]),
+ disk_log:close(Name),
+ 9 = length(ets:tab2list(element(2,ets:file2tab(FName2)))),
+ true = ets:delete(?MODULE),
+ {error,invalid_object_count} = ets:file2tab(FName2,[{verify,true}]),
+ {'EXIT',_} = (catch ets:delete(?MODULE)),
+ {ok,_} = ets:tabfile_info(FName2),
+ {ok,_} = ets:tabfile_info(FName),
+ file:delete(FName),
+ file:delete(FName2)
+ end),
ok.
%% Tests verification of large table with md5 sum.
tabfile_ext4(Config) when is_list(Config) ->
- FName = filename:join([proplists:get_value(priv_dir, Config),"bauta.dat"]),
- LL = lists:seq(1,10000),
- TL = ets_new(x,[]),
- Name2 = make_ref(),
- [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
- ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
- {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
- {mode, read_only}]),
- {C,[_|_]} = disk_log:chunk(Name2,start),
- {_,[_|_]} = disk_log:chunk(Name2,C),
- disk_log:close(Name2),
- true = lists:sort(ets:tab2list(TL)) =:=
- lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
- Res = [begin
- {ok,FD} = file:open(FName,[binary,read,write]),
- {ok, Bin} = file:pread(FD,0,1000),
- <<B1:N/binary,Ch:8,B2/binary>> = Bin,
- Ch2 = (Ch + 1) rem 255,
- Bin2 = <<B1/binary,Ch2:8,B2/binary>>,
- ok = file:pwrite(FD,0,Bin2),
- ok = file:close(FD),
- X = case ets:file2tab(FName) of
- {ok,TL2} ->
- true = lists:sort(ets:tab2list(TL)) =/=
- lists:sort(ets:tab2list(TL2));
- _ ->
- totally_broken
- end,
- {error,Y} = ets:file2tab(FName,[{verify,true}]),
- ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
- {X,Y}
- end || N <- lists:seq(500,600)],
- io:format("~p~n",[Res]),
- file:delete(FName),
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ FName = filename:join([proplists:get_value(priv_dir, Config),"bauta.dat"]),
+ LL = lists:seq(1,10000),
+ TL = ets_new(x,Opts),
+ Name2 = make_ref(),
+ [ets:insert(TL,{X,integer_to_list(X)}) || X <- LL],
+ ok = ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {ok, Name2} = disk_log:open([{name, Name2}, {file, FName},
+ {mode, read_only}]),
+ {C,[_|_]} = disk_log:chunk(Name2,start),
+ {_,[_|_]} = disk_log:chunk(Name2,C),
+ disk_log:close(Name2),
+ true = lists:sort(ets:tab2list(TL)) =:=
+ lists:sort(ets:tab2list(element(2,ets:file2tab(FName)))),
+ Res = [begin
+ {ok,FD} = file:open(FName,[binary,read,write]),
+ {ok, Bin} = file:pread(FD,0,1000),
+ <<B1:N/binary,Ch:8,B2/binary>> = Bin,
+ Ch2 = (Ch + 1) rem 255,
+ Bin2 = <<B1/binary,Ch2:8,B2/binary>>,
+ ok = file:pwrite(FD,0,Bin2),
+ ok = file:close(FD),
+ X = case ets:file2tab(FName) of
+ {ok,TL2} ->
+ true = lists:sort(ets:tab2list(TL)) =/=
+ lists:sort(ets:tab2list(TL2));
+ _ ->
+ totally_broken
+ end,
+ {error,Y} = ets:file2tab(FName,[{verify,true}]),
+ ets:tab2file(TL,FName,[{extended_info,[md5sum]}]),
+ {X,Y}
+ end || N <- lists:seq(500,600)],
+ io:format("~p~n",[Res]),
+ file:delete(FName)
+ end),
ok.
%% Test that no disk_log is left open when file has been corrupted.
@@ -4535,13 +4686,14 @@ make_sub_binary(List, Num) when is_list(List) ->
%% Perform multiple lookups for every key in a large table.
heavy_lookup(Config) when is_list(Config) ->
- repeat_for_opts(fun heavy_lookup_do/1).
+ repeat_for_opts_all_set_table_types(fun heavy_lookup_do/1).
heavy_lookup_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, 7000),
- _ = [do_lookup(Tab, 6999) || _ <- lists:seq(1, 50)],
+ KeyRange = 7000,
+ Tab = ets_new(foobar_table, [{keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
+ _ = [do_lookup(Tab, KeyRange-1) || _ <- lists:seq(1, 50)],
true = ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -4558,15 +4710,16 @@ do_lookup(Tab, N) ->
%% Perform multiple lookups for every element in a large table.
heavy_lookup_element(Config) when is_list(Config) ->
- repeat_for_opts(fun heavy_lookup_element_do/1).
+ repeat_for_opts_all_set_table_types(fun heavy_lookup_element_do/1).
heavy_lookup_element_do(Opts) ->
EtsMem = etsmem(),
- Tab = ets_new(foobar_table, [set, protected, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, 7000),
+ KeyRange = 7000,
+ Tab = ets_new(foobar_table, [{keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
%% lookup ALL elements 50 times
Laps = 50 div syrup_factor(),
- _ = [do_lookup_element(Tab, 6999, 1) || _ <- lists:seq(1, Laps)],
+ _ = [do_lookup_element(Tab, KeyRange-1, 1) || _ <- lists:seq(1, Laps)],
true = ets:delete(Tab),
verify_etsmem(EtsMem).
@@ -4585,15 +4738,15 @@ do_lookup_element(Tab, N, M) ->
heavy_concurrent(Config) when is_list(Config) ->
- ct:timetrap({minutes,30}), %% valgrind needs a lot of time
- repeat_for_opts(fun do_heavy_concurrent/1).
+ ct:timetrap({minutes,120}), %% valgrind needs a lot of time
+ repeat_for_opts_all_set_table_types(fun do_heavy_concurrent/1).
do_heavy_concurrent(Opts) ->
- Size = 10000,
+ KeyRange = 10000,
Laps = 10000 div syrup_factor(),
EtsMem = etsmem(),
- Tab = ets_new(blupp, [set, public, {keypos, 2} | Opts]),
- ok = fill_tab2(Tab, 0, Size),
+ Tab = ets_new(blupp, [public, {keypos, 2} | Opts], KeyRange),
+ ok = fill_tab2(Tab, 0, KeyRange),
Procs = lists:map(
fun (N) ->
my_spawn_link(
@@ -4626,48 +4779,68 @@ do_heavy_concurrent_proc(Tab, N, Offs) ->
fold_empty(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- Tab = make_table(a, [], []),
- [] = ets:foldl(fun(_X) -> exit(hej) end, [], Tab),
- [] = ets:foldr(fun(_X) -> exit(hej) end, [], Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ Tab = make_table(a, Opts, []),
+ [] = ets:foldl(fun(_X) -> exit(hej) end, [], Tab),
+ [] = ets:foldr(fun(_X) -> exit(hej) end, [], Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldl(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [bag], L),
- LS = lists:sort(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:sort(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldr(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [bag], L),
- LS = lists:sort(ets:foldr(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:sort(ets:foldr(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldl_ordered(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [ordered_set], L),
- LS = lists:reverse(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = lists:reverse(ets:foldl(fun(E,A) -> [E|A] end, [], Tab)),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
foldr_ordered(Config) when is_list(Config) ->
- EtsMem = etsmem(),
- L = [{a,1}, {c,3}, {b,2}],
- LS = lists:sort(L),
- Tab = make_table(a, [ordered_set], L),
- LS = ets:foldr(fun(E,A) -> [E|A] end, [], Tab),
- true = ets:delete(Tab),
- verify_etsmem(EtsMem).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+ L = [{a,1}, {c,3}, {b,2}],
+ LS = lists:sort(L),
+ Tab = make_table(a, Opts, L),
+ LS = ets:foldr(fun(E,A) -> [E|A] end, [], Tab),
+ true = ets:delete(Tab),
+ verify_etsmem(EtsMem)
+ end),
+ ok.
%% Test ets:member BIF.
member(Config) when is_list(Config) ->
@@ -4852,6 +5025,7 @@ filltabint(Tab,0) ->
filltabint(Tab,N) ->
ets:insert(Tab,{N,integer_to_list(N)}),
filltabint(Tab,N-1).
+
filltabint2(Tab,0) ->
Tab;
filltabint2(Tab,N) ->
@@ -5066,27 +5240,31 @@ gen_dets_filename(Config,N) ->
"testdets_" ++ integer_to_list(N) ++ ".dets").
otp_6842_select_1000(Config) when is_list(Config) ->
- Tab = ets_new(xxx,[ordered_set]),
- [ets:insert(Tab,{X,X}) || X <- lists:seq(1,10000)],
- AllTrue = lists:duplicate(10,true),
- AllTrue =
- [ length(
- element(1,
- ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
- X*1000 || X <- lists:seq(1,10) ],
- Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
- [2000,2000,2000,2000,2000],
- [3000,3000,3000,1000],
- [4000,4000,2000],
- [5000,5000],
- [6000,4000],
- [7000,3000],
- [8000,2000],
- [9000,1000],
- [10000]],
- AllTrue = [ check_seq(Tab, ets:select(Tab,[{'_',[],['$_']}],hd(L)),L) ||
- L <- Sequences ],
- ets:delete(Tab),
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ KeyRange = 10000,
+ Tab = ets_new(xxx, Opts, KeyRange),
+ [ets:insert(Tab,{X,X}) || X <- lists:seq(1,KeyRange)],
+ AllTrue = lists:duplicate(10,true),
+ AllTrue =
+ [ length(
+ element(1,
+ ets:select(Tab,[{'_',[],['$_']}],X*1000))) =:=
+ X*1000 || X <- lists:seq(1,10) ],
+ Sequences = [[1000,1000,1000,1000,1000,1000,1000,1000,1000,1000],
+ [2000,2000,2000,2000,2000],
+ [3000,3000,3000,1000],
+ [4000,4000,2000],
+ [5000,5000],
+ [6000,4000],
+ [7000,3000],
+ [8000,2000],
+ [9000,1000],
+ [10000]],
+ AllTrue = [ check_seq(Tab, ets:select(Tab,[{'_',[],['$_']}],hd(L)),L) ||
+ L <- Sequences ],
+ ets:delete(Tab)
+ end),
ok.
check_seq(_,'$end_of_table',[]) ->
@@ -5098,17 +5276,21 @@ check_seq(A,B,C) ->
false.
otp_6338(Config) when is_list(Config) ->
- L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,
- 98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,
- 0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,
- 105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,
- 0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,
- 101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,
- 118,106>>),
- T = ets_new(xxx,[ordered_set]),
- lists:foreach(fun(X) -> ets:insert(T,X) end,L),
- [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
- ets:delete(T).
+ repeat_for_opts_all_ord_set_table_types(
+ fun(Opts) ->
+ L = binary_to_term(<<131,108,0,0,0,2,104,2,108,0,0,0,2,103,100,0,19,112,112,
+ 98,49,95,98,115,49,50,64,98,108,97,100,101,95,48,95,53,
+ 0,0,33,50,0,0,0,4,1,98,0,0,23,226,106,100,0,4,101,120,
+ 105,116,104,2,108,0,0,0,2,104,2,100,0,3,115,98,109,100,
+ 0,19,112,112,98,50,95,98,115,49,50,64,98,108,97,100,
+ 101,95,48,95,56,98,0,0,18,231,106,100,0,4,114,101,99,
+ 118,106>>),
+ T = ets_new(xxx,Opts),
+ lists:foreach(fun(X) -> ets:insert(T,X) end,L),
+ [[4839,recv]] = ets:match(T,{[{sbm,ppb2_bs12@blade_0_8},'$1'],'$2'}),
+ ets:delete(T)
+ end),
+ ok.
%% Elements could come in the wrong order in a bag if a rehash occurred.
otp_5340(Config) when is_list(Config) ->
@@ -5178,7 +5360,7 @@ otp_7665_act(Tab,Min,Max,DelNr) ->
%% Whitebox testing of meta name table hashing.
meta_wb(Config) when is_list(Config) ->
EtsMem = etsmem(),
- repeat_for_opts(fun meta_wb_do/1),
+ repeat_for_opts_all_non_stim_table_types(fun meta_wb_do/1),
verify_etsmem(EtsMem).
@@ -5247,13 +5429,16 @@ colliding_names(Name) ->
%% OTP_6913: Grow and shrink.
grow_shrink(Config) when is_list(Config) ->
- EtsMem = etsmem(),
-
- Set = ets_new(a, [set]),
- grow_shrink_0(0, 3071, 3000, 5000, Set),
- ets:delete(Set),
-
- verify_etsmem(EtsMem).
+ repeat_for_all_set_table_types(
+ fun(Opts) ->
+ EtsMem = etsmem(),
+
+ Set = ets_new(a, Opts, 5000),
+ grow_shrink_0(0, 3071, 3000, 5000, Set),
+ ets:delete(Set),
+
+ verify_etsmem(EtsMem)
+ end).
grow_shrink_0(N, _, _, Max, _) when N >= Max ->
ok;
@@ -5277,7 +5462,7 @@ grow_shrink_3(N, ShrinkTo, T) ->
true = ets:delete(T, N),
grow_shrink_3(N-1, ShrinkTo, T).
-%% Grow a table that still contains pseudo-deleted objects.
+%% Grow a hash table that still contains pseudo-deleted objects.
grow_pseudo_deleted(Config) when is_list(Config) ->
only_if_smp(fun() -> grow_pseudo_deleted_do() end).
@@ -5330,7 +5515,7 @@ grow_pseudo_deleted_do(Type) ->
ets:delete(T),
process_flag(scheduler,0).
-%% Shrink a table that still contains pseudo-deleted objects.
+%% Shrink a hash table that still contains pseudo-deleted objects.
shrink_pseudo_deleted(Config) when is_list(Config) ->
only_if_smp(fun()->shrink_pseudo_deleted_do() end).
@@ -5450,10 +5635,16 @@ meta_newdel_named(Config) when is_list(Config) ->
%% Concurrent insert's on same table.
smp_insert(Config) when is_list(Config) ->
- ets_new(smp_insert,[named_table,public,{write_concurrency,true}]),
+ repeat_for_opts(fun smp_insert_do/1,
+ [[set,ordered_set,stim_cat_ord_set]]).
+
+smp_insert_do(Opts) ->
+ KeyRange = 10000,
+ ets_new(smp_insert,[named_table,public,{write_concurrency,true}|Opts],
+ KeyRange),
InitF = fun(_) -> ok end,
- ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(10000)})
- end,
+ ExecF = fun(_) -> true = ets:insert(smp_insert,{rand:uniform(KeyRange)})
+ end,
FiniF = fun(_) -> ok end,
run_smp_workers(InitF,ExecF,FiniF,100000),
verify_table_load(smp_insert),
@@ -5461,7 +5652,7 @@ smp_insert(Config) when is_list(Config) ->
%% Concurrent deletes on same fixated table.
smp_fixed_delete(Config) when is_list(Config) ->
- only_if_smp(fun()->smp_fixed_delete_do() end).
+ only_if_smp(fun() -> smp_fixed_delete_do() end).
smp_fixed_delete_do() ->
T = ets_new(foo,[public,{write_concurrency,true}]),
@@ -5472,25 +5663,73 @@ smp_fixed_delete_do() ->
Buckets = num_of_buckets(T),
InitF = fun([ProcN,NumOfProcs|_]) -> {ProcN,NumOfProcs} end,
ExecF = fun({Key,_}) when Key > NumOfObjs ->
- [end_of_work];
- ({Key,Increment}) ->
- true = ets:delete(T,Key),
- {Key+Increment,Increment}
- end,
+ [end_of_work];
+ ({Key,Increment}) ->
+ true = ets:delete(T,Key),
+ {Key+Increment,Increment}
+ end,
FiniF = fun(_) -> ok end,
run_sched_workers(InitF,ExecF,FiniF,NumOfObjs),
0 = ets:info(T,size),
true = ets:info(T,fixed),
Buckets = num_of_buckets(T),
- NumOfObjs = get_kept_objects(T),
+ case ets:info(T,type) of
+ set -> NumOfObjs = get_kept_objects(T);
+ _ -> ok
+ end,
ets:safe_fixtable(T,false),
%% Will fail as unfix does not shrink the table:
%%Mem = ets:info(T,memory),
%%verify_table_load(T),
ets:delete(T).
+%% ERL-720
+%% Provoke race between ets:delete and table unfix (by select_count)
+%% that caused ets_misc memory counter to indicate false leak.
+delete_unfix_race(Config) when is_list(Config) ->
+ EtsMem = etsmem(),
+ Table = ets:new(t,[set,public,{write_concurrency,true}]),
+ InsertOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:insert(Table, {rand:uniform(10)}),
+ true
+ end
+ end,
+ DeleteOp =
+ fun() ->
+ receive stop ->
+ false
+ after 0 ->
+ ets:delete(Table, rand:uniform(10)),
+ true
+ end
+ end,
+ SelectOp =
+ fun() ->
+ ets:select_count(Table, ets:fun2ms(fun(X) -> true end))
+ end,
+ Main = self(),
+ Ins = spawn(fun()-> repeat_while(InsertOp), Main ! self() end),
+ Del = spawn(fun()-> repeat_while(DeleteOp), Main ! self() end),
+ spawn(fun()->
+ repeat(SelectOp, 10000),
+ Del ! stop,
+ Ins ! stop
+ end),
+ [receive Pid -> ok end || Pid <- [Ins,Del]],
+ ets:delete(Table),
+ verify_etsmem(EtsMem).
+
num_of_buckets(T) ->
- element(1,ets:info(T,stats)).
+ case ets:info(T,type) of
+ set -> element(1,ets:info(T,stats));
+ bag -> element(1,ets:info(T,stats));
+ duplicate_bag -> element(1,ets:info(T,stats));
+ _ -> ok
+ end.
%% Fixate hash table while other process is busy doing unfix.
smp_unfix_fix(Config) when is_list(Config) ->
@@ -5655,106 +5894,126 @@ otp_8166_zombie_creator(T,Deleted) ->
verify_table_load(T) ->
- Stats = ets:info(T,stats),
- {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
- ok = if
- AvgLen > 1.2 ->
- io:format("Table overloaded: Stats=~p\n~p\n",
- [Stats, ets:info(T)]),
- false;
-
- Buckets>256, AvgLen < 0.47 ->
- io:format("Table underloaded: Stats=~p\n~p\n",
- [Stats, ets:info(T)]),
- false;
-
- StdDev > ExpSD*2 ->
- io:format("Too large standard deviation (poor hashing?),"
- " stats=~p\n~p\n",[Stats, ets:info(T)]),
- false;
-
- true ->
- io:format("Stats = ~p\n",[Stats]),
- ok
- end.
+ case ets:info(T,type) of
+ ordered_set -> ok;
+ _ ->
+ Stats = ets:info(T,stats),
+ {Buckets,AvgLen,StdDev,ExpSD,_MinLen,_MaxLen,_} = Stats,
+ ok = if
+ AvgLen > 1.2 ->
+ io:format("Table overloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ Buckets>256, AvgLen < 0.47 ->
+ io:format("Table underloaded: Stats=~p\n~p\n",
+ [Stats, ets:info(T)]),
+ false;
+
+ StdDev > ExpSD*2 ->
+ io:format("Too large standard deviation (poor hashing?),"
+ " stats=~p\n~p\n",[Stats, ets:info(T)]),
+ false;
+
+ true ->
+ io:format("Stats = ~p\n",[Stats]),
+ ok
+ end
+ end.
%% ets:select on a tree with NIL key object.
otp_8732(Config) when is_list(Config) ->
- Tab = ets_new(noname,[ordered_set]),
- filltabstr(Tab,999),
- ets:insert(Tab,{[],"nasty NIL object"}),
- [] = ets:match(Tab,{'_',nomatch}), %% Will hang if bug not fixed
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ KeyRange = 999,
+ KeyFun = fun(K) -> integer_to_list(K) end,
+ Tab = ets_new(noname,Opts, KeyRange, KeyFun),
+ filltabstr(Tab, KeyRange),
+ ets:insert(Tab,{[],"nasty NIL object"}),
+ [] = ets:match(Tab,{'_',nomatch}) %% Will hang if bug not fixed
+ end),
ok.
%% Run concurrent select_delete (and inserts) on same table.
smp_select_delete(Config) when is_list(Config) ->
- T = ets_new(smp_select_delete,[named_table,public,{write_concurrency,true}]),
- Mod = 17,
- Zeros = erlang:make_tuple(Mod,0),
- InitF = fun(_) -> Zeros end,
- ExecF = fun(Diffs0) ->
- case rand:uniform(20) of
- 1 ->
- Mod = 17,
- Eq = rand:uniform(Mod) - 1,
- Deleted = ets:select_delete(T,
- [{{'_', '$1'},
- [{'=:=', {'rem', '$1', Mod}, Eq}],
- [true]}]),
- Diffs1 = setelement(Eq+1, Diffs0,
- element(Eq+1,Diffs0) - Deleted),
- Diffs1;
- _ ->
- Key = rand:uniform(10000),
- Eq = Key rem Mod,
- case ets:insert_new(T,{Key,Key}) of
- true ->
- Diffs1 = setelement(Eq+1, Diffs0,
- element(Eq+1,Diffs0)+1),
- Diffs1;
- false -> Diffs0
- end
- end
- end,
- FiniF = fun(Result) -> Result end,
- Results = run_sched_workers(InitF,ExecF,FiniF,20000),
- TotCnts = lists:foldl(fun(Diffs, Sum) -> add_lists(Sum,tuple_to_list(Diffs)) end,
- lists:duplicate(Mod, 0), Results),
- io:format("TotCnts = ~p\n",[TotCnts]),
- LeftInTab = lists:foldl(fun(N,Sum) -> Sum+N end,
- 0, TotCnts),
- io:format("LeftInTab = ~p\n",[LeftInTab]),
- LeftInTab = ets:info(T,size),
- lists:foldl(fun(Cnt,Eq) ->
- WasCnt = ets:select_count(T,
- [{{'_', '$1'},
- [{'=:=', {'rem', '$1', Mod}, Eq}],
- [true]}]),
- io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
- Cnt = WasCnt,
- Eq+1
- end,
- 0, TotCnts),
- %% May fail as select_delete does not shrink table (enough)
- %%verify_table_load(T),
- LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
- 0 = ets:info(T,size),
- false = ets:info(T,fixed),
- ets:delete(T).
+ repeat_for_opts(fun smp_select_delete_do/1,
+ [[set,ordered_set,stim_cat_ord_set],
+ read_concurrency, compressed]).
+
+smp_select_delete_do(Opts) ->
+ KeyRange = 10000,
+ begin % indentation
+ T = ets_new(smp_select_delete,[named_table,public,{write_concurrency,true}|Opts],
+ KeyRange),
+ Mod = 17,
+ Zeros = erlang:make_tuple(Mod,0),
+ InitF = fun(_) -> Zeros end,
+ ExecF = fun(Diffs0) ->
+ case rand:uniform(20) of
+ 1 ->
+ Mod = 17,
+ Eq = rand:uniform(Mod) - 1,
+ Deleted = ets:select_delete(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0) - Deleted),
+ Diffs1;
+ _ ->
+ Key = rand:uniform(KeyRange),
+ Eq = Key rem Mod,
+ case ets:insert_new(T,{Key,Key}) of
+ true ->
+ Diffs1 = setelement(Eq+1, Diffs0,
+ element(Eq+1,Diffs0)+1),
+ Diffs1;
+ false -> Diffs0
+ end
+ end
+ end,
+ FiniF = fun(Result) -> Result end,
+ Results = run_sched_workers(InitF,ExecF,FiniF,20000),
+ TotCnts = lists:foldl(fun(Diffs, Sum) -> add_lists(Sum,tuple_to_list(Diffs)) end,
+ lists:duplicate(Mod, 0), Results),
+ io:format("TotCnts = ~p\n",[TotCnts]),
+ LeftInTab = lists:foldl(fun(N,Sum) -> Sum+N end,
+ 0, TotCnts),
+ io:format("LeftInTab = ~p\n",[LeftInTab]),
+ LeftInTab = ets:info(T,size),
+ lists:foldl(fun(Cnt,Eq) ->
+ WasCnt = ets:select_count(T,
+ [{{'_', '$1'},
+ [{'=:=', {'rem', '$1', Mod}, Eq}],
+ [true]}]),
+ io:format("~p: ~p =?= ~p\n",[Eq,Cnt,WasCnt]),
+ Cnt = WasCnt,
+ Eq+1
+ end,
+ 0, TotCnts),
+ %% May fail as select_delete does not shrink table (enough)
+ %%verify_table_load(T),
+ LeftInTab = ets:select_delete(T, [{{'$1','$1'}, [], [true]}]),
+ 0 = ets:info(T,size),
+ false = ets:info(T,fixed),
+ ets:delete(T)
+ end, % indentation
+ ok.
smp_select_replace(Config) when is_list(Config) ->
repeat_for_opts(fun smp_select_replace_do/1,
- [[set,ordered_set,duplicate_bag]]).
+ [[set,ordered_set,stim_cat_ord_set,duplicate_bag]]).
smp_select_replace_do(Opts) ->
+ KeyRange = 20,
T = ets_new(smp_select_replace,
- [public, {write_concurrency, true} | Opts]),
- ObjCount = 20,
+ [public, {write_concurrency, true} | Opts],
+ KeyRange),
InitF = fun (_) -> 0 end,
ExecF = fun (Cnt0) ->
- CounterId = rand:uniform(ObjCount),
+ CounterId = rand:uniform(KeyRange),
Match = [{{'$1', '$2'},
[{'=:=', '$1', CounterId}],
[{{'$1', {'+', '$2', 1}}}]}],
@@ -5778,15 +6037,133 @@ smp_select_replace_do(Opts) ->
FinalCounts = ets:select(T, [{{'_', '$1'}, [], ['$1']}]),
Total = lists:sum(FinalCounts),
Total = lists:sum(Results),
- ObjCount = ets:select_delete(T, [{{'_', '_'}, [], [true]}]),
+ KeyRange = ets:select_delete(T, [{{'_', '_'}, [], [true]}]),
0 = ets:info(T, size),
true = ets:delete(T),
ok.
+%% Iterate ordered_set with write_concurrency
+%% and make sure we hit all "stable" long lived keys
+%% while "volatile" objects are randomly inserted and deleted.
+smp_ordered_iteration(Config) when is_list(Config) ->
+ repeat_for_opts(fun smp_ordered_iteration_do/1,
+ [[cat_ord_set,stim_cat_ord_set]]).
+
+
+smp_ordered_iteration_do(Opts) ->
+ KeyRange = 1000,
+ KeyFun = fun(K, Type) ->
+ {K div 10, K rem 10, Type}
+ end,
+ StimKeyFun = fun(K) ->
+ KeyFun(K, element(rand:uniform(3),
+ {stable, other, volatile}))
+ end,
+ T = ets_new(smp_ordered_iteration, [public, {write_concurrency,true} | Opts],
+ KeyRange, StimKeyFun),
+ NStable = KeyRange div 4,
+ prefill_table(T, KeyRange, NStable, fun(K) -> {KeyFun(K, stable), 0} end),
+ NStable = ets:info(T, size),
+ NVolatile = KeyRange div 2,
+ prefill_table(T, KeyRange, NVolatile, fun(K) -> {KeyFun(K, volatile), 0} end),
+
+ InitF = fun (_) -> #{} end,
+ ExecF = fun (Counters) ->
+ K = rand:uniform(KeyRange),
+ Key = KeyFun(K, volatile),
+ Acc = case rand:uniform(22) of
+ R when R =< 10 ->
+ ets:insert(T, {Key}),
+ incr_counter(insert, Counters);
+ R when R =< 15 ->
+ ets:delete(T, Key),
+ incr_counter(delete, Counters);
+ R when R =< 19 ->
+ %% Delete bound key
+ ets:select_delete(T, [{{Key, '_'}, [], [true]}]),
+ incr_counter(select_delete_bk, Counters);
+ R when R =< 20 ->
+ %% Delete partially bound key
+ ets:select_delete(T, [{{{K div 10, '_', volatile}, '_'}, [], [true]}]),
+ incr_counter(select_delete_pbk, Counters);
+ R when R =< 21 ->
+ %% Replace bound key
+ ets:select_replace(T, [{{Key, '$1'}, [],
+ [{{{const,Key}, {'+','$1',1}}}]}]),
+ incr_counter(select_replace_bk, Counters);
+ _ ->
+ %% Replace partially bound key
+ ets:select_replace(T, [{{{K div 10, '_', volatile}, '$1'}, [],
+ [{{{element,1,'$_'}, {'+','$1',1}}}]}]),
+ incr_counter(select_replace_pbk, Counters)
+ end,
+ receive stop ->
+ [end_of_work | Acc]
+ after 0 ->
+ Acc
+ end
+ end,
+ FiniF = fun (Acc) -> Acc end,
+ Pids = run_sched_workers(InitF, ExecF, FiniF, infinite),
+ timer:send_after(1000, stop),
+ Rounds = fun Loop(N) ->
+ NStable = ets:select_count(T, [{{{'_', '_', stable}, '_'}, [], [true]}]),
+ NStable = count_stable(T, next, ets:first(T), 0),
+ NStable = count_stable(T, prev, ets:last(T), 0),
+ NStable = length(ets:select(T, [{{{'_', '_', stable}, '_'}, [], [true]}])),
+ NStable = length(ets:select_reverse(T, [{{{'_', '_', stable}, '_'}, [], [true]}])),
+ NStable = ets_select_chunks_count(T, [{{{'_', '_', stable}, '_'}, [], [true]}],
+ rand:uniform(5)),
+ receive stop -> N
+ after 0 -> Loop(N+1)
+ end
+ end (1),
+ [P ! stop || P <- Pids],
+ Results = wait_pids(Pids),
+ io:format("Ops = ~p\n", [maps_sum(Results)]),
+ io:format("Diff = ~p\n", [ets:info(T,size) - NStable - NVolatile]),
+ io:format("Stats = ~p\n", [ets:info(T,stats)]),
+ io:format("Rounds = ~p\n", [Rounds]),
+ true = ets:delete(T),
+ ok.
+
+incr_counter(Name, Counters) ->
+ Counters#{Name => maps:get(Name, Counters, 0) + 1}.
+
+count_stable(T, Next, {_, _, stable}=Key, N) ->
+ count_stable(T, Next, ets:Next(T, Key), N+1);
+count_stable(T, Next, {_, _, volatile}=Key, N) ->
+ count_stable(T, Next, ets:Next(T, Key), N);
+count_stable(_, _, '$end_of_table', N) ->
+ N.
+
+ets_select_chunks_count(T, MS, Chunk) ->
+ ets_select_chunks_count(ets:select(T, MS, Chunk), 0).
+
+ets_select_chunks_count('$end_of_table', N) ->
+ N;
+ets_select_chunks_count({List, Continuation}, N) ->
+ ets_select_chunks_count(ets:select(Continuation),
+ length(List) + N).
+
+maps_sum([Ma | Tail]) when is_map(Ma) ->
+ maps_sum([lists:sort(maps:to_list(Ma)) | Tail]);
+maps_sum([La, Mb | Tail]) ->
+ Lab = lists:zipwith(fun({K,Va}, {K,Vb}) -> {K,Va+Vb} end,
+ La,
+ lists:sort(maps:to_list(Mb))),
+ maps_sum([Lab | Tail]);
+maps_sum([L]) ->
+ L.
+
+
+
+
%% Test different types.
types(Config) when is_list(Config) ->
init_externals(),
- repeat_for_opts(fun types_do/1, [[set,ordered_set],compressed]).
+ repeat_for_opts(fun types_do/1, [repeat_for_opts_atom2list(set_types),
+ compressed]).
types_do(Opts) ->
EtsMem = etsmem(),
@@ -5813,7 +6190,7 @@ types_do(Opts) ->
%% OTP-9932: Memory overwrite when inserting large integers in compressed bag.
%% Will crash with segv on 64-bit opt if not fixed.
otp_9932(Config) when is_list(Config) ->
- T = ets:new(xxx, [bag, compressed]),
+ T = ets_new(xxx, [bag, compressed]),
Fun = fun(N) ->
Key = {1316110174588445 bsl N,1316110174588583 bsl N},
S = {Key, Key},
@@ -5829,48 +6206,56 @@ otp_9932(Config) when is_list(Config) ->
%% vm-deadlock caused by race between ets:delete and others on
%% write_concurrency table.
otp_9423(Config) when is_list(Config) ->
- InitF = fun(_) -> {0,0} end,
- ExecF = fun({S,F}) ->
- receive
- stop ->
- io:format("~p got stop\n", [self()]),
- [end_of_work | {"Succeded=",S,"Failed=",F}]
- after 0 ->
- %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]),
- try ets:lookup(otp_9423, key) of
- [] -> {S+1,F}
- catch
- error:badarg -> {S,F+1}
- end
- end
- end,
- FiniF = fun(R) -> R end,
- case run_smp_workers(InitF, ExecF, FiniF, infinite, 1) of
- Pids when is_list(Pids) ->
- %%[P ! start || P <- Pids],
- repeat(fun() -> ets:new(otp_9423, [named_table, public, {write_concurrency,true}]),
- ets:delete(otp_9423)
- end, 10000),
- [P ! stop || P <- Pids],
- wait_pids(Pids),
- ok;
+ repeat_for_all_non_stim_set_table_types(
+ fun(Opts) ->
+ InitF = fun(_) -> {0,0} end,
+ ExecF = fun({S,F}) ->
+ receive
+ stop ->
+ io:format("~p got stop\n", [self()]),
+ [end_of_work | {"Succeded=",S,"Failed=",F}]
+ after 0 ->
+ %%io:format("~p (~p) doing lookup\n", [self(), {S,F}]),
+ try ets:lookup(otp_9423, key) of
+ [] -> {S+1,F}
+ catch
+ error:badarg -> {S,F+1}
+ end
+ end
+ end,
+ FiniF = fun(R) -> R end,
+ case run_smp_workers(InitF, ExecF, FiniF, infinite, 1) of
+ Pids when is_list(Pids) ->
+ %%[P ! start || P <- Pids],
+ repeat(fun() -> ets_new(otp_9423, [named_table, public,
+ {write_concurrency,true}|Opts]),
+ ets:delete(otp_9423)
+ end, 10000),
+ [P ! stop || P <- Pids],
+ wait_pids(Pids),
+ ok;
+
+ Skipped -> Skipped
+ end
+ end).
- Skipped -> Skipped
- end.
%% Corrupted binary in compressed table
otp_10182(Config) when is_list(Config) ->
- Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>,
- Key = {test, Bin},
- Value = base64:decode(Bin),
- In = {Key,Value},
- Db = ets:new(undefined, [set, protected, {read_concurrency, true}, compressed]),
- ets:insert(Db, In),
- [Out] = ets:lookup(Db, Key),
- io:format("In : ~p\nOut: ~p\n", [In,Out]),
- ets:delete(Db),
- In = Out.
+ repeat_for_opts_all_table_types(
+ fun(Opts) ->
+ Bin = <<"aHR0cDovL2hvb3RzdWl0ZS5jb20vYy9wcm8tYWRyb2xsLWFi">>,
+ Key = {test, Bin},
+ Value = base64:decode(Bin),
+ In = {Key,Value},
+ Db = ets_new(undefined, Opts),
+ ets:insert(Db, In),
+ [Out] = ets:lookup(Db, Key),
+ io:format("In : ~p\nOut: ~p\n", [In,Out]),
+ ets:delete(Db),
+ In = Out
+ end).
%% Test that ets:all include/exclude tables that we know are created/deleted
ets_all(Config) when is_list(Config) ->
@@ -5961,19 +6346,23 @@ take(Config) when is_list(Config) ->
ets:insert(T1, {{'not',<<"immediate">>},ok}),
[{{'not',<<"immediate">>},ok}] = ets:take(T1, {'not',<<"immediate">>}),
%% Same with ordered tables.
- T2 = ets_new(b, [ordered_set]),
- [] = ets:take(T2, foo),
- ets:insert(T2, {foo,bar}),
- [] = ets:take(T2, bar),
- [{foo,bar}] = ets:take(T2, foo),
- [] = ets:tab2list(T2),
- ets:insert(T2, {{'not',<<"immediate">>},ok}),
- [{{'not',<<"immediate">>},ok}] = ets:take(T2, {'not',<<"immediate">>}),
- %% Arithmetically-equal keys.
- ets:insert(T2, [{1.0,float},{2,integer}]),
- [{1.0,float}] = ets:take(T2, 1),
- [{2,integer}] = ets:take(T2, 2.0),
- [] = ets:tab2list(T2),
+ repeat_for_all_ord_set_table_types(
+ fun(Opts) ->
+ T2 = ets_new(b, Opts),
+ [] = ets:take(T2, foo),
+ ets:insert(T2, {foo,bar}),
+ [] = ets:take(T2, bar),
+ [{foo,bar}] = ets:take(T2, foo),
+ [] = ets:tab2list(T2),
+ ets:insert(T2, {{'not',<<"immediate">>},ok}),
+ [{{'not',<<"immediate">>},ok}] = ets:take(T2, {'not',<<"immediate">>}),
+ %% Arithmetically-equal keys.
+ ets:insert(T2, [{1.0,float},{2,integer}]),
+ [{1.0,float}] = ets:take(T2, 1),
+ [{2,integer}] = ets:take(T2, 2.0),
+ [] = ets:tab2list(T2),
+ ets:delete(T2)
+ end),
%% Same with bag.
T3 = ets_new(c, [bag]),
ets:insert(T3, [{1,1},{1,2},{3,3}]),
@@ -5981,7 +6370,6 @@ take(Config) when is_list(Config) ->
[{3,3}] = ets:take(T3, 3),
[] = ets:tab2list(T3),
ets:delete(T1),
- ets:delete(T2),
ets:delete(T3),
ok.
@@ -6016,9 +6404,372 @@ whereis_table(Config) when is_list(Config) ->
ok.
-%%
-%% Utility functions:
-%%
+
+%% The following work functions are used by
+%% throughput_benchmark/4. They are declared on the top level beacuse
+%% declaring them as function local funs cause a scalability issue.
+get_op([{_,O}], _RandNum) ->
+ O;
+get_op([{Prob,O}|Rest], RandNum) ->
+ case RandNum < Prob of
+ true -> O;
+ false -> get_op(Rest, RandNum)
+ end.
+do_op(Table, ProbHelpTab, Range, Operations) ->
+ RandNum = rand:uniform(),
+ Op = get_op(ProbHelpTab, RandNum),
+ #{ Op := TheOp} = Operations,
+ TheOp(Table, Range).
+do_work(WorksDoneSoFar, Table, ProbHelpTab, Range, Operations) ->
+ receive
+ stop -> WorksDoneSoFar
+ after
+ 0 -> do_op(Table, ProbHelpTab, Range, Operations),
+ do_work(WorksDoneSoFar + 1, Table, ProbHelpTab, Range, Operations)
+ end.
+
+prefill_table(T, KeyRange, Num, ObjFun) ->
+ Seed = rand:uniform(KeyRange),
+ %%io:format("prefill_table: Seed = ~p\n", [Seed]),
+ RState = unique_rand_start(KeyRange, Seed),
+ prefill_table_loop(T, RState, Num, ObjFun).
+
+prefill_table_loop(_, _, 0, _) ->
+ ok;
+prefill_table_loop(T, RS0, N, ObjFun) ->
+ {Key, RS1} = unique_rand_next(RS0),
+ ets:insert(T, ObjFun(Key)),
+ prefill_table_loop(T, RS1, N-1, ObjFun).
+
+throughput_benchmark() ->
+ throughput_benchmark(false, not_set, not_set).
+
+throughput_benchmark(TestMode, BenchmarkRunMs, RecoverTimeMs) ->
+ NrOfSchedulers = erlang:system_info(schedulers),
+ %% Definitions of operations that are supported by the benchmark
+ NextSeqOp =
+ fun (T, KeyRange, SeqSize) ->
+ Start = rand:uniform(KeyRange),
+ Last =
+ lists:foldl(
+ fun(_, Prev) ->
+ case Prev of
+ '$end_of_table'-> ok;
+ _ ->
+ try ets:next(T, Prev) of
+ Normal -> Normal
+ catch
+ error:badarg ->
+ % sets (not ordered_sets) cannot handle when the argument
+ % to next is not in the set
+ rand:uniform(KeyRange)
+ end
+ end
+ end,
+ Start,
+ lists:seq(1, SeqSize)),
+ case Last =:= -1 of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+ end,
+ PartialSelectOp =
+ fun (T, KeyRange, SeqSize) ->
+ Start = rand:uniform(KeyRange),
+ Last = Start + SeqSize,
+ case -1 =:= ets:select_count(T,
+ ets:fun2ms(fun({X}) when X > Start andalso X =< Last -> true end)) of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+
+ end,
+ %% Mapping benchmark operation names to their corresponding functions that do them
+ Operations =
+ #{insert =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:insert(T, {Num})
+ end,
+ delete =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:delete(T, Num)
+ end,
+ lookup =>
+ fun(T,KeyRange) ->
+ Num = rand:uniform(KeyRange),
+ ets:lookup(T, Num)
+ end,
+ nextseq10 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,10) end,
+ nextseq100 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,100) end,
+ nextseq1000 =>
+ fun(T,KeyRange) -> NextSeqOp(T,KeyRange,1000) end,
+ selectAll =>
+ fun(T,_KeyRange) ->
+ case -1 =:= ets:select_count(T, ets:fun2ms(fun(X) -> true end)) of
+ true -> io:format("Will never be printed");
+ false -> ok
+ end
+ end,
+ partial_select1000 =>
+ fun(T,KeyRange) -> PartialSelectOp(T,KeyRange,1000) end
+ },
+ %% Helper functions
+ CalculateThreadCounts = fun Calculate([Count|Rest]) ->
+ case Count > NrOfSchedulers of
+ true -> lists:reverse(Rest);
+ false -> Calculate([Count*2,Count|Rest])
+ end
+ end,
+ CalculateOpsProbHelpTab =
+ fun Calculate([{_, OpName}], _) ->
+ [{1.0, OpName}];
+ Calculate([{OpPropability, OpName}|Res], Current) ->
+ NewCurrent = Current + OpPropability,
+ [{NewCurrent, OpName}| Calculate(Res, NewCurrent)]
+ end,
+ RenderScenario =
+ fun R([], StringSoFar) ->
+ StringSoFar;
+ R([{Fraction, Operation}], StringSoFar) ->
+ io_lib:format("~s ~f% ~p",[StringSoFar, Fraction * 100.0, Operation]);
+ R([{Fraction, Operation}|Rest], StringSoFar) ->
+ R(Rest,
+ io_lib:format("~s ~f% ~p, ",[StringSoFar, Fraction * 100.0, Operation]))
+ end,
+ SafeFixTableIfRequired =
+ fun(Table, Scenario, On) ->
+ case set =:= ets:info(Table, type) of
+ true ->
+ HasNotRequiringOp =
+ lists:search(
+ fun({_,nextseq10}) -> true;
+ ({_,nextseq100}) -> true;
+ ({_,nextseq1000}) -> true;
+ (_) -> false
+ end, Scenario),
+ case HasNotRequiringOp of
+ false -> ok;
+ _ -> ets:safe_fixtable(Table, On)
+ end;
+ false -> ok
+ end
+ end,
+ %% Function that runs a benchmark instance and returns the number
+ %% of operations that were performed
+ RunBenchmark =
+ fun(NrOfProcs, TableConfig, Scenario,
+ Range, Duration, RecoverTime) ->
+ ProbHelpTab = CalculateOpsProbHelpTab(Scenario, 0),
+ Table = ets:new(t, TableConfig),
+ Nobj = Range div 2,
+ prefill_table(Table, Range, Nobj, fun(K) -> {K} end),
+ Nobj = ets:info(Table, size),
+ SafeFixTableIfRequired(Table, Scenario, true),
+ ParentPid = self(),
+ ChildPids =
+ lists:map(
+ fun(_N) ->
+ spawn(fun() ->
+ receive start -> ok end,
+ WorksDone =
+ do_work(0, Table, ProbHelpTab, Range, Operations),
+ ParentPid ! WorksDone
+ end)
+ end, lists:seq(1, NrOfProcs)),
+ lists:foreach(fun(Pid) -> Pid ! start end, ChildPids),
+ timer:sleep(Duration),
+ lists:foreach(fun(Pid) -> Pid ! stop end, ChildPids),
+ TotalWorksDone = lists:foldl(
+ fun(_, Sum) ->
+ receive
+ Count -> Sum + Count
+ end
+ end, 0, ChildPids),
+ SafeFixTableIfRequired(Table, Scenario, false),
+ ets:delete(Table),
+ timer:sleep(RecoverTime),
+ TotalWorksDone
+ end,
+ %%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%% Benchmark Configuration %%%%%%%%%%%%%%%%%%%%%%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%
+ %% Change the following variables to configure the benchmark runs
+ ThreadCounts =
+ case TestMode of
+ true -> [1, NrOfSchedulers];
+ false -> CalculateThreadCounts([1])
+ end,
+ KeyRanges = % Sizes of the key ranges
+ case TestMode of
+ true -> [50000];
+ false -> [1000000]
+ end,
+ Duration =
+ case BenchmarkRunMs of % Duration of a benchmark run in milliseconds
+ not_set -> 30000;
+ _ -> BenchmarkRunMs
+ end,
+ TimeMsToSleepAfterEachBenchmarkRun =
+ case RecoverTimeMs of
+ not_set -> 1000;
+ _ -> RecoverTimeMs
+ end,
+ TableTypes = % The table types that will be benchmarked
+ [
+ [ordered_set, public],
+ [ordered_set, public, {write_concurrency, true}],
+ [ordered_set, public, {read_concurrency, true}],
+ [ordered_set, public, {write_concurrency, true}, {read_concurrency, true}],
+ [set, public],
+ [set, public, {write_concurrency, true}],
+ [set, public, {read_concurrency, true}],
+ [set, public, {write_concurrency, true}, {read_concurrency, true}]
+ ],
+ Scenarios = % Benchmark scenarios (the fractions should add up to approximately 1.0)
+ [
+ [
+ {0.5, insert},
+ {0.5, delete}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.8, lookup}
+ ],
+ [
+ {0.01, insert},
+ {0.01, delete},
+ {0.98, lookup}
+ ],
+ [
+ {1.0, lookup}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq10}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq100}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.4, lookup},
+ {0.4, nextseq1000}
+ ],
+ [
+ {1.0, nextseq1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.7999, lookup},
+ {0.0001, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.799999, lookup},
+ {0.000001, selectAll}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.79, lookup},
+ {0.01, partial_select1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.7999, lookup},
+ {0.0001, partial_select1000}
+ ],
+ [
+ {0.1, insert},
+ {0.1, delete},
+ {0.799999, lookup},
+ {0.000001, partial_select1000}
+ ]
+ ],
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %%%% End of Benchmark Configuration %%%%%%%%%%%%%%%%
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ %% Prepare for memory check
+ EtsMem = case TestMode of
+ true -> etsmem();
+ false -> ok
+ end,
+ %% Run the benchmark
+ io:format("# Each instance of the benchmark runs for ~w seconds:~n", [Duration/1000]),
+ io:format("# The result of a benchmark instance is presented as a number representing~n"),
+ io:format("# the number of operations performed per second:~n~n~n"),
+ io:format("# To plot graphs for the results below:~n"),
+ io:format("# 1. Open \"$ERL_TOP/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html\" in a web browser~n"),
+ io:format("# 2. Copy the lines between \"#BENCHMARK STARTED$\" and \"#BENCHMARK ENDED$\" below~n"),
+ io:format("# 3. Paste the lines copied in step 2 to the text box in the browser window opened in~n"),
+ io:format("# step 1 and press the Render button~n~n"),
+ io:format("#BENCHMARK STARTED$~n"),
+ %% The following loop runs all benchmark scenarios and prints the results (i.e, operations/second)
+ lists:foreach(
+ fun(KeyRange) ->
+ lists:foreach(
+ fun(Scenario) ->
+ io:format("Scenario: ~s | Key Range Size: ~w$~n",
+ [RenderScenario(Scenario, ""),
+ KeyRange]),
+ lists:foreach(
+ fun(ThreadCount) ->
+ io:format("; ~w",[ThreadCount])
+ end,
+ ThreadCounts),
+ io:format("$~n",[]),
+ lists:foreach(
+ fun(TableType) ->
+ io:format("~w ",[TableType]),
+ lists:foreach(
+ fun(ThreadCount) ->
+ Result = RunBenchmark(ThreadCount,
+ TableType,
+ Scenario,
+ KeyRange,
+ Duration,
+ TimeMsToSleepAfterEachBenchmarkRun),
+ io:format("; ~f",[Result/(Duration/1000.0)])
+ end,
+ ThreadCounts),
+ io:format("$~n",[])
+ end,
+ TableTypes)
+ end,
+ Scenarios)
+ end,
+ KeyRanges),
+ io:format("~n#BENCHMARK ENDED$~n~n"),
+ case TestMode of
+ true -> verify_etsmem(EtsMem);
+ false -> ok
+ end.
+
+test_throughput_benchmark(Config) when is_list(Config) ->
+ throughput_benchmark(true, 100, 0).
+
add_lists(L1,L2) ->
add_lists(L1,L2,[]).
@@ -6079,8 +6830,11 @@ wait_pids(Pids, Acc) ->
{Pid,Result} ->
true = lists:member(Pid,Pids),
Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p from ~p, still waiting for ~p\n",[Result,Pid,Others]),
+ %%io:format("wait_pid got ~p from ~p\n",[Result,Pid]),
wait_pids(Others,[Result | Acc])
+ after 60*1000 ->
+ io:format("Still waiting for workers ~p\n",[Pids]),
+ wait_pids(Pids, Acc)
end.
@@ -6104,19 +6858,25 @@ wait_for_memory_deallocations() ->
wait_for_memory_deallocations()
end.
-
etsmem() ->
- wait_for_memory_deallocations(),
+ % The following is done twice to avoid an inconsistent memory
+ % "snapshot" (see verify_etsmem/2).
+ lists:foldl(
+ fun(_,_) ->
+ wait_for_memory_deallocations(),
- AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
- ets:info(T,memory),ets:info(T,type)}
- end, ets:all()),
+ AllTabs = lists:map(fun(T) -> {T,ets:info(T,name),ets:info(T,size),
+ ets:info(T,memory),ets:info(T,type)}
+ end, ets:all()),
- EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
- ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
+ EtsAllocSize = erts_debug:alloc_blocks_size(ets_alloc),
+ ErlangMemoryEts = try erlang:memory(ets) catch error:notsup -> notsup end,
- Mem = {ErlangMemoryEts, EtsAllocSize},
- {Mem, AllTabs}.
+ Mem = {ErlangMemoryEts, EtsAllocSize},
+ {Mem, AllTabs}
+ end,
+ not_used,
+ lists:seq(1,2)).
verify_etsmem(MI) ->
wait_for_test_procs(),
@@ -6137,15 +6897,15 @@ verify_etsmem({MemInfo,AllTabs}, Try) ->
end;
{MemInfo2, AllTabs2} ->
- io:format("Expected: ~p", [MemInfo]),
- io:format("Actual: ~p", [MemInfo2]),
- io:format("Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
- io:format("Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
+ io:format("#Expected: ~p", [MemInfo]),
+ io:format("#Actual: ~p", [MemInfo2]),
+ io:format("#Changed tables before: ~p\n",[AllTabs -- AllTabs2]),
+ io:format("#Changed tables after: ~p\n", [AllTabs2 -- AllTabs]),
case Try < 2 of
true ->
- io:format("\nThis discrepancy could be caused by an "
+ io:format("\n#This discrepancy could be caused by an "
"inconsistent memory \"snapshot\""
- "\nTry again...\n", []),
+ "\n#Try again...\n", []),
verify_etsmem({MemInfo, AllTabs}, Try+1);
false ->
ct:fail("Failed memory check")
@@ -6619,22 +7379,49 @@ make_unaligned_sub_binary(List) ->
repeat_for_opts(F) ->
repeat_for_opts(F, [write_concurrency, read_concurrency, compressed]).
+repeat_for_opts_all_table_types(F) ->
+ repeat_for_opts(F, [all_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_opts_all_non_stim_table_types(F) ->
+ repeat_for_opts(F, [all_non_stim_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_opts_all_set_table_types(F) ->
+ repeat_for_opts(F, [set_types, write_concurrency, read_concurrency, compressed]).
+
+repeat_for_all_set_table_types(F) ->
+ repeat_for_opts(F, [set_types]).
+
+repeat_for_all_ord_set_table_types(F) ->
+ repeat_for_opts(F, [ord_set_types]).
+
+repeat_for_all_non_stim_set_table_types(F) ->
+ repeat_for_opts(F, [all_non_stim_set_types]).
+
+repeat_for_opts_all_ord_set_table_types(F) ->
+ repeat_for_opts(F, [ord_set_types, write_concurrency, read_concurrency, compressed]).
+
repeat_for_opts(F, OptGenList) when is_function(F, 1) ->
repeat_for_opts(F, OptGenList, []).
repeat_for_opts(F, [], Acc) ->
lists:foldl(fun(Opts, RV_Acc) ->
OptList = lists:filter(fun(E) -> E =/= void end, Opts),
- io:format("Calling with options ~p\n",[OptList]),
- RV = F(OptList),
- case RV_Acc of
- {comment,_} -> RV_Acc;
- _ -> case RV of
- {comment,_} -> RV;
- _ -> [RV | RV_Acc]
- end
- end
- end, [], Acc);
+ case is_redundant_opts_combo(OptList) of
+ true ->
+ %%io:format("Ignoring redundant options ~p\n",[OptList]),
+ ok;
+ false ->
+ io:format("Calling with options ~p\n",[OptList]),
+ RV = F(OptList),
+ case RV_Acc of
+ {comment,_} -> RV_Acc;
+ _ -> case RV of
+ {comment,_} -> RV;
+ _ -> [RV | RV_Acc]
+ end
+ end
+ end
+ end, [], Acc);
repeat_for_opts(F, [OptList | Tail], []) when is_list(OptList) ->
repeat_for_opts(F, Tail, [[Opt] || Opt <- OptList]);
repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
@@ -6642,14 +7429,136 @@ repeat_for_opts(F, [OptList | Tail], AccList) when is_list(OptList) ->
repeat_for_opts(F, [Atom | Tail], AccList) when is_atom(Atom) ->
repeat_for_opts(F, [repeat_for_opts_atom2list(Atom) | Tail ], AccList).
-repeat_for_opts_atom2list(all_types) -> [set,ordered_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(set_types) -> [set,ordered_set,stim_cat_ord_set,cat_ord_set];
+repeat_for_opts_atom2list(ord_set_types) -> [ordered_set,stim_cat_ord_set,cat_ord_set];
+repeat_for_opts_atom2list(all_types) -> [set,ordered_set,stim_cat_ord_set,cat_ord_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(all_non_stim_types) -> [set,ordered_set,cat_ord_set,bag,duplicate_bag];
+repeat_for_opts_atom2list(all_non_stim_set_types) -> [set,ordered_set,cat_ord_set];
repeat_for_opts_atom2list(write_concurrency) -> [{write_concurrency,false},{write_concurrency,true}];
repeat_for_opts_atom2list(read_concurrency) -> [{read_concurrency,false},{read_concurrency,true}];
repeat_for_opts_atom2list(compressed) -> [compressed,void].
-ets_new(Name, Opts) ->
- %%ets:new(Name, [compressed | Opts]).
- ets:new(Name, Opts).
+is_redundant_opts_combo(Opts) ->
+ (lists:member(stim_cat_ord_set, Opts) orelse
+ lists:member(cat_ord_set, Opts))
+ andalso
+ (lists:member({write_concurrency, false}, Opts) orelse
+ lists:member(private, Opts) orelse
+ lists:member(protected, Opts)).
+
+%% Add fake table option with info about key range.
+%% Will be consumed by ets_new and used for stim_cat_ord_set.
+key_range(Opts, KeyRange) ->
+ [{key_range, KeyRange} | Opts].
+
+key_range_fun(Opts, KeyRange, KeyFun) ->
+ [{key_range, KeyRange}, {key_fun, KeyFun} | Opts].
+
+ets_new(Name, Opts0) ->
+ {KeyRange, Opts1} = case lists:keytake(key_range, 1, Opts0) of
+ {value, {key_range, KR}, Rest1} ->
+ {KR, Rest1};
+ false ->
+ {1000*1000, Opts0}
+ end,
+ ets_new(Name, Opts1, KeyRange).
+
+ets_new(Name, Opts1, KeyRange) ->
+ {KeyFun, Opts2} = case lists:keytake(key_fun, 1, Opts1) of
+ {value, {key_fun, KF}, Rest2} ->
+ {KF, Rest2};
+ false ->
+ {fun id/1, Opts1}
+ end,
+ ets_new(Name, Opts2, KeyRange, KeyFun).
+
+ets_new(Name, Opts0, KeyRange, KeyFun) ->
+ {CATree, Stimulate, RevOpts} =
+ lists:foldl(fun(cat_ord_set, {false, false, Lacc}) ->
+ {true, false, [ordered_set | Lacc]};
+ (stim_cat_ord_set, {false, false, Lacc}) ->
+ {true, true, [ordered_set | Lacc]};
+ (Other, {CAT, STIM, Lacc}) ->
+ {CAT, STIM, [Other | Lacc]}
+ end,
+ {false, false, []},
+ Opts0),
+ Opts = lists:reverse(RevOpts),
+ EtsNewHelper =
+ fun (UseOpts) ->
+ case get(ets_new_opts) of
+ UseOpts ->
+ silence; %% suppress identical table opts spam
+ _ ->
+ put(ets_new_opts, UseOpts),
+ io:format("ets:new(~p, ~p)~n", [Name, UseOpts])
+ end,
+ ets:new(Name, UseOpts)
+ end,
+ case CATree andalso
+ (not lists:member({write_concurrency, false}, Opts)) andalso
+ (not lists:member(private, Opts)) andalso
+ (not lists:member(protected, Opts)) of
+ true ->
+ NewOpts1 =
+ case lists:member({write_concurrency, true}, Opts) of
+ true -> Opts;
+ false -> [{write_concurrency, true}|Opts]
+ end,
+ NewOpts2 =
+ case lists:member(public, NewOpts1) of
+ true -> NewOpts1;
+ false -> [public|NewOpts1]
+ end,
+ T = EtsNewHelper(NewOpts2),
+ case Stimulate of
+ false -> ok;
+ true -> stimulate_contention(T, KeyRange, KeyFun)
+ end,
+ T;
+ false ->
+ EtsNewHelper(Opts)
+ end.
+
+% The purpose of this function is to stimulate fine grained locking in
+% tables of types ordered_set with the write_concurrency options
+% turned on. The erts_debug feature 'ets_force_split' is used to easier
+% generate a routing tree with fine grained locking without having to
+% provoke lots of actual lock contentions.
+stimulate_contention(Tid, KeyRange, KeyFun) ->
+ T = case Tid of
+ A when is_atom(A) -> ets:whereis(A);
+ _ -> Tid
+ end,
+ erts_debug:set_internal_state(ets_force_split, {T, true}),
+ Num = case KeyRange > 50 of
+ true -> 50;
+ false -> KeyRange
+ end,
+ Seed = rand:uniform(KeyRange),
+ %%io:format("prefill_table: Seed = ~p\n", [Seed]),
+ RState = unique_rand_start(KeyRange, Seed),
+ stim_inserter_loop(T, RState, Num, KeyFun),
+ Num = ets:info(T, size),
+ ets:match_delete(T, {'$1','$1','$1'}),
+ 0 = ets:info(T, size),
+ erts_debug:set_internal_state(ets_force_split, {T, false}),
+ case ets:info(T,stats) of
+ {0, _, _} ->
+ io:format("No routing nodes in table?\n"
+ "Debug feature 'ets_force_split' does not seem to work.\n", []),
+ ct:fail("No ets_force_split?");
+ Stats ->
+ io:format("stimulated ordered_set: ~p\n", [Stats])
+ end.
+
+stim_inserter_loop(_, _, 0, _) ->
+ ok;
+stim_inserter_loop(T, RS0, N, KeyFun) ->
+ {K, RS1} = unique_rand_next(RS0),
+ Key = KeyFun(K),
+ ets:insert(T, {Key, Key, Key}),
+ stim_inserter_loop(T, RS1, N-1, KeyFun).
do_tc(Do, Report) ->
T1 = erlang:monotonic_time(),
@@ -6663,3 +7572,50 @@ syrup_factor() ->
valgrind -> 20;
_ -> 1
end.
+
+
+%%
+%% This is a pseudo random number generator for UNIQUE integers.
+%% All integers between 1 and Max will be generated before it repeat itself.
+%% It's a variant of this one using quadratic residues by Jeff Preshing:
+%% http://preshing.com/20121224/how-to-generate-a-sequence-of-unique-random-integers/
+%%
+unique_rand_start(Max, Seed) ->
+ L = lists:dropwhile(fun(P) -> P < Max end,
+ primes_3mod4()),
+ [P | _] = case L of
+ [] ->
+ error("Random range too large");
+ _ ->
+ L
+ end,
+ 3 = P rem 4,
+ {0, {Max, P, Seed}}.
+
+unique_rand_next({N, {Max, P, Seed}=Const}) ->
+ case dquad(P, N, Seed) + 1 of
+ RND when RND > Max -> % Too large, skip
+ unique_rand_next({N+1, Const});
+ RND ->
+ {RND, {N+1, Const}}
+ end.
+
+%% A one-to-one relation between all integers 0 =< X < Prime
+%% if Prime rem 4 == 3.
+quad(Prime, X) ->
+ Rem = X*X rem Prime,
+ case 2*X < Prime of
+ true ->
+ Rem;
+ false ->
+ Prime - Rem
+ end.
+
+dquad(Prime, X, Seed) ->
+ quad(Prime, (quad(Prime, X) + Seed) rem Prime).
+
+%% Primes where P rem 4 == 3.
+primes_3mod4() ->
+ [103, 211, 503, 1019, 2003, 5003, 10007, 20011, 50023,
+ 100003, 200003, 500083, 1000003, 2000003, 5000011,
+ 10000019, 20000003, 50000047, 100000007].
diff --git a/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html
new file mode 100644
index 0000000000..a2c61aa938
--- /dev/null
+++ b/lib/stdlib/test/ets_SUITE_data/visualize_throughput.html
@@ -0,0 +1,253 @@
+<!doctype html>
+<html lang="en">
+
+<!-- %% -->
+<!-- %% %CopyrightBegin% -->
+<!-- %% -->
+<!-- %% Copyright Ericsson AB and Kjell Winblad 1996-2018. All Rights Reserved. -->
+<!-- %% -->
+<!-- %% Licensed under the Apache License, Version 2.0 (the "License"); -->
+<!-- %% you may not use this file except in compliance with the License. -->
+<!-- %% You may obtain a copy of the License at -->
+<!-- %% -->
+<!-- %% http://www.apache.org/licenses/LICENSE-2.0 -->
+<!-- %% -->
+<!-- %% Unless required by applicable law or agreed to in writing, software -->
+<!-- %% distributed under the License is distributed on an "AS IS" BASIS, -->
+<!-- %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -->
+<!-- %% See the License for the specific language governing permissions and -->
+<!-- %% limitations under the License. -->
+<!-- %% -->
+<!-- %% %CopyrightEnd% -->
+<!-- %% -->
+<!-- %% Author: Kjell Winblad -->
+<!-- %% -->
+
+ <head>
+ <meta charset="utf-8">
+ <title>ETS Benchmark Result Viewer</title>
+ </head>
+
+ <body>
+ <div id="insertPlaceholder"></div>
+ <h1>ETS Benchmark Result Viewer</h1>
+ <p>
+ This page generates graphs from data produced by the ETS benchmark which is defined in the function <code>ets_SUITE:throughput_benchmark/0</code> (see "<code>$ERL_TOP/lib/stdlib/test/ets_SUITE.erl</code>").
+ </p>
+ <p>
+ Note that one can paste results from several benchmark runs into the field below. Results from the same scenario but from different benchmark runs will be relabeled and ploted in the same graph automatically. This makes comparisons of different ETS versions easy.
+ </p>
+ <p>
+ Note also that that lines can be hidden by clicking on the corresponding label.
+ </p>
+ Paste the generated data in the field below and press the Render button:
+ <br>
+ <textarea id="dataField" rows="4" cols="50"></textarea>
+ <br>
+ <input type="checkbox" id="barPlot"> Bar Plot
+ <br>
+ <input type="checkbox" id="sameSpacing" checked> Same X Spacing Between Points
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public]" checked> Show <code>[ordered_set,public]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{write_concurrency,true}]" checked> Show <code>[ordered_set,public,{write_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{read_concurrency,true}]" checked> Show <code>[ordered_set,public,{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[ordered_set,public,{write_concurrency,true},{read_concurrency,true}]" checked> Show <code>[ordered_set,public,{write_concurrency,true},{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public]"> Show <code>[set,public]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{write_concurrency,true}]"> Show <code>[set,public,{write_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{read_concurrency,true}]"> Show <code>[set,public,{read_concurrency,true}]</code>
+ <br>
+ <input type="checkbox" class="showCheck" value="[set,public,{write_concurrency,true},{read_concurrency,true}]"> Show <code>[set,public,{write_concurrency,true},{read_concurrency,true}]</code>
+ <br>
+ <button id="renderButton" type="button">Render</button>
+
+ <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
+ integrity="sha256-3edrmyuQ0w65f8gfBsqowzjJe2iM6n0nKciPUp8y+7E="
+ crossorigin="anonymous"></script>
+ <script>
+ var loading = false;
+ function toggleLoadingScreen(){
+ if(loading){
+ $("#loading").remove();
+ loading = false;
+ }else{
+ $('<div id="loading">'+
+ '<span style="position: fixed; top: 50%;left: 50%;color: white;"><b>Loading...</b></span>'+
+ '</div>')
+ .css({position: "fixed",
+ top: 0,
+ left: 0,
+ width: "100%",
+ height: "100%",
+ 'background-color': "#000",
+ filter:"alpha(opacity=50)",
+ '-moz-opacity':"0.5",
+ '-khtml-opacity': "0.5",
+ opacity: "0.5",
+ 'z-index': "10000"})
+ .appendTo(document.body);
+ loading = true;
+
+ }
+ }
+ //Start loading screen before downloading plotly which is quite large
+ toggleLoadingScreen();
+ </script>
+ <script src="https://cdn.plot.ly/plotly-1.5.0.min.js"></script>
+ <script>
+ String.prototype.replaceAll = function(search, replacement) {
+ var target = this;
+ return target.split(search).join(replacement);
+ };
+ String.prototype.myTrim = function() {
+ var target = this;
+ return target.replace(/^\s+|\s+$/g, '');
+ };
+ function plotGraph(lines, sameSpacing, barPlot, prefix) {
+ var xvals = null;
+ var data = [];
+ while(lines.length > 0 &&
+ (lines[0].myTrim() == "" ||
+ lines[0].myTrim().indexOf(";") !== -1)){
+ var line = lines.shift().myTrim();
+ if(line == "" || line.startsWith("#")){
+ continue;
+ } else if(line.startsWith(";")) {
+ xvals = line.split(";")
+ xvals.shift(); // Remove first
+ xvals = $.map(xvals, function (i){
+ if(sameSpacing){
+ return "_"+i.myTrim();
+ }else{
+ return parseInt(i.myTrim(), 10);
+ }
+ });
+ }else{
+ line = line.split(";")
+ var label = prefix + line.shift().myTrim();
+ var yvals = $.map(line, function (i){
+ return parseFloat(i.myTrim(), 10);
+ });
+ var trace = {
+ x: xvals,
+ y: yvals,
+ mode: 'lines+markers',
+ name: label
+ };
+ if(barPlot){
+ trace['type'] = "bar";
+ }
+ data.push(trace);
+ }
+
+ }
+ return data;
+ }
+ function plotGraphs(){
+ var insertPlaceholder = $("#insertPlaceholder");
+ var sameSpacing = $('#sameSpacing').is(":checked");
+ var barPlot = $('#barPlot').is(":checked");
+ var lines = $("#dataField").val();
+ $('.showCheck').each(function() {
+ var item = $(this);
+ if(!item.is(":checked")){
+ lines = lines.replaceAll(item.val(), "#"+item.val())
+ }
+ });
+ lines = lines.split("$");
+ var nrOfGraphs = 0;
+ var scenarioDataMap = {};
+ var scenarioNrOfVersionsMap = {};
+ var scenarioList = [];
+ while(lines.length > 0){
+ var line = lines.shift().myTrim();
+ if(line == ""){
+ continue;
+ } else if(line.startsWith("Scenario:")) {
+ nrOfGraphs = nrOfGraphs + 1;
+ var name = line;
+ if(scenarioDataMap[name] === undefined){
+ scenarioDataMap[name] = [];
+ scenarioNrOfVersionsMap[name] = 0;
+ scenarioList.push(line);
+ }
+ scenarioNrOfVersionsMap[name] = scenarioNrOfVersionsMap[name] + 1;
+ var prefix = undefined;
+ if(scenarioNrOfVersionsMap[name] === 1){
+ prefix = "";
+ }else{
+ prefix = "Ver: " + scenarioNrOfVersionsMap[name] + " ";
+ }
+ scenarioDataMap[name] =
+ scenarioDataMap[name].concat(
+ plotGraph(lines, sameSpacing, barPlot, prefix));
+ }
+ }
+ $.each(scenarioList,
+ function( index, name ) {
+ var nrOfGraphs = index + 1;
+ var data = scenarioDataMap[name];
+ $( "<div class='added' id='graph"+nrOfGraphs+"'>")
+ .insertBefore( insertPlaceholder );
+ $( "<button type='button' class='added' id='fullscreenButton"+nrOfGraphs+"'>Fill screen</button>")
+ .insertBefore( insertPlaceholder );
+ $( "<span class='added'><br><hr><br></span>")
+ .insertBefore( insertPlaceholder );
+ var layout = {
+ title:name,
+ xaxis: {
+ title: '# of Processes'
+ },
+ yaxis: {
+ title: 'Operations/Second'
+ }
+
+ };
+
+ $("#fullscreenButton"+nrOfGraphs).click(
+ function(){
+ $('#graph'+nrOfGraphs).replaceWith(
+ $("<div class='added' id='graph"+nrOfGraphs+"'>"));
+ layout = $.extend({}, layout, {
+ width:$(window).width()-40,
+ height:$(window).height()-40
+ });
+ Plotly.newPlot('graph'+nrOfGraphs, data, layout);
+ });
+ Plotly.newPlot('graph'+nrOfGraphs, data, layout);
+
+ });
+
+
+ }
+ $(document).ready(function(){
+ $('#renderButton').click(
+ function(){
+ toggleLoadingScreen();
+ setTimeout(function(){
+ try {
+ $( ".added" ).remove();
+ plotGraphs();
+ toggleLoadingScreen();
+ } catch(e){
+ toggleLoadingScreen();
+ console.log(e);
+ alert("Error happened when parsing data.\n" +
+ "See console for more info");
+ }
+ }, 10);
+ });
+ setTimeout(function(){
+ $( ".added" ).remove();
+ plotGraphs();
+ toggleLoadingScreen();
+ }, 10);
+ });
+ </script>
+ </body>
+</html>
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index 41ee3246f5..a8264e5a84 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -124,8 +124,10 @@ start2(Config) when is_list(Config) ->
{ok, Pid0} = gen_fsm:start(gen_fsm_SUITE, [], []),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
+ MRef = monitor(process,Pid0),
shutdown_stopped =
gen_fsm:sync_send_all_state_event(Pid0, stop_shutdown),
+ receive {'DOWN',MRef,_,_,shutdown} -> ok end,
{'EXIT', {noproc,_}} =
(catch gen_fsm:sync_send_event(Pid0, hej)),
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index 053233df9b..017939fdd6 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -121,7 +121,8 @@ end_per_testcase(_CaseName, Config) ->
start1(Config) ->
%%OldFl = process_flag(trap_exit, true),
- {ok,Pid0} = gen_statem:start_link(?MODULE, start_arg(Config, []), []),
+ {ok,Pid0} =
+ gen_statem:start_link(?MODULE, start_arg(Config, []), [{debug,[trace]}]),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
stop_it(Pid0),
@@ -135,7 +136,8 @@ start1(Config) ->
%% anonymous w. shutdown
start2(Config) ->
%% Dont link when shutdown
- {ok,Pid0} = gen_statem:start(?MODULE, start_arg(Config, []), []),
+ {ok,Pid0} =
+ gen_statem:start(?MODULE, start_arg(Config, []), []),
ok = do_func_test(Pid0),
ok = do_sync_func_test(Pid0),
stopped = gen_statem:call(Pid0, {stop,shutdown}),
@@ -641,51 +643,72 @@ state_enter(_Config) ->
end,
start =>
fun (enter, Prev, N) ->
- Self ! {enter,start,Prev,N},
+ Self ! {N,enter,start,Prev},
{keep_state,N + 1};
(internal, Prev, N) ->
- Self ! {internal,start,Prev,N},
+ Self ! {N,internal,start,Prev},
{keep_state,N + 1};
+ (timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {timeout,M}}};
({call,From}, repeat, N) ->
{repeat_state,N + 1,
- [{reply,From,{repeat,start,N}}]};
+ [{reply,From,{N,repeat,start}}]};
({call,From}, echo, N) ->
{next_state,wait,N + 1,
- {reply,From,{echo,start,N}}};
+ [{reply,From,{N,echo,start}},{timeout,0,N}]};
({call,From}, {stop,Reason}, N) ->
{stop_and_reply,Reason,
- [{reply,From,{stop,N}}],N + 1}
+ [{reply,From,{N,stop}}],N + 1}
end,
wait =>
fun (enter, Prev, N) when N < 5 ->
{repeat_state,N + 1,
- {reply,{Self,N},{enter,Prev}}};
+ [{reply,{Self,N},{enter,Prev}},
+ {timeout,0,N},
+ {state_timeout,0,N}]};
(enter, Prev, N) ->
- Self ! {enter,wait,Prev,N},
- {keep_state,N + 1};
+ Self ! {N,enter,wait,Prev},
+ {keep_state,N + 1,
+ [{timeout,0,N},
+ {state_timeout,0,N}]};
+ (timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {timeout,M}}};
+ (state_timeout, M, N) ->
+ {keep_state, N + 1,
+ {reply, {Self,N}, {state_timeout,M}}};
({call,From}, repeat, N) ->
{repeat_state_and_data,
- [{reply,From,{repeat,wait,N}}]};
+ [{reply,From,{N,repeat,wait}},
+ {timeout,0,N}]};
({call,From}, echo, N) ->
{next_state,start,N + 1,
[{next_event,internal,wait},
- {reply,From,{echo,wait,N}}]}
+ {reply,From,{N,echo,wait}}]}
end},
{ok,STM} =
gen_statem:start_link(
- ?MODULE, {map_statem,Machine,[state_enter]}, []),
-
- [{enter,start,start,1}] = flush(),
- {echo,start,2} = gen_statem:call(STM, echo),
- [{3,{enter,start}},{4,{enter,start}},{enter,wait,start,5}] = flush(),
- {wait,[6|_]} = sys:get_state(STM),
- {repeat,wait,6} = gen_statem:call(STM, repeat),
- [{enter,wait,wait,6}] = flush(),
- {echo,wait,7} = gen_statem:call(STM, echo),
- [{enter,start,wait,8},{internal,start,wait,9}] = flush(),
- {repeat,start,10} = gen_statem:call(STM, repeat),
- [{enter,start,start,11}] = flush(),
- {stop,12} = gen_statem:call(STM, {stop,bye}),
+ ?MODULE, {map_statem,Machine,[state_enter]}, [{debug,[trace]}]),
+
+ [{1,enter,start,start}] = flush(),
+ {2,echo,start} = gen_statem:call(STM, echo),
+ [{3,{enter,start}},
+ {4,{enter,start}},
+ {5,enter,wait,start},
+ {6,{timeout,5}},
+ {7,{state_timeout,5}}] = flush(),
+ {wait,[8|_]} = sys:get_state(STM),
+ {8,repeat,wait} = gen_statem:call(STM, repeat),
+ [{8,enter,wait,wait},
+ {9,{timeout,8}},
+ {10,{state_timeout,8}}] = flush(),
+ {11,echo,wait} = gen_statem:call(STM, echo),
+ [{12,enter,start,wait},
+ {13,internal,start,wait}] = flush(),
+ {14,repeat,start} = gen_statem:call(STM, repeat),
+ [{15,enter,start,start}] = flush(),
+ {16,stop} = gen_statem:call(STM, {stop,bye}),
[{'EXIT',STM,bye}] = flush(),
{noproc,_} =
diff --git a/lib/stdlib/test/io_SUITE.erl b/lib/stdlib/test/io_SUITE.erl
index 79cee54335..f097552e8c 100644
--- a/lib/stdlib/test/io_SUITE.erl
+++ b/lib/stdlib/test/io_SUITE.erl
@@ -31,7 +31,7 @@
otp_10836/1, io_lib_width_too_small/1,
io_with_huge_message_queue/1, format_string/1,
maps/1, coverage/1, otp_14178_unicode_atoms/1, otp_14175/1,
- otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1,
+ otp_14285/1, limit_term/1, otp_14983/1, otp_15103/1, otp_15076/1,
otp_15159/1]).
-export([pretty/2, trf/3]).
@@ -64,7 +64,7 @@ all() ->
io_lib_print_binary_depth_one, otp_10302, otp_10755, otp_10836,
io_lib_width_too_small, io_with_huge_message_queue,
format_string, maps, coverage, otp_14178_unicode_atoms, otp_14175,
- otp_14285, limit_term, otp_14983, otp_15103, otp_15159].
+ otp_14285, limit_term, otp_14983, otp_15103, otp_15076, otp_15159].
%% Error cases for output.
error_1(Config) when is_list(Config) ->
@@ -2639,3 +2639,11 @@ otp_15159(_Config) ->
"[atom]" =
lists:flatten(io_lib:format("~p", [[atom]], [{chars_limit,5}])),
ok.
+
+otp_15076(_Config) ->
+ {'EXIT', {badarg, _}} = (catch io_lib:format("~c", [a])),
+ L = io_lib:scan_format("~c", [a]),
+ {"~c", [a]} = io_lib:unscan_format(L),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L)),
+ {'EXIT', {badarg, _}} = (catch io_lib:build_text(L, [])),
+ ok.
diff --git a/lib/stdlib/test/lists_SUITE.erl b/lib/stdlib/test/lists_SUITE.erl
index 837ab4e97e..af94fc79bc 100644
--- a/lib/stdlib/test/lists_SUITE.erl
+++ b/lib/stdlib/test/lists_SUITE.erl
@@ -1679,7 +1679,7 @@ make_fun() ->
receive {Pid, Fun} -> Fun end.
make_fun(Pid) ->
- Pid ! {self(), fun make_fun/1}.
+ Pid ! {self(), fun (X) -> {X, Pid} end}.
fun_pid(Fun) ->
erlang:fun_info(Fun, pid).
diff --git a/lib/stdlib/test/rand_SUITE.erl b/lib/stdlib/test/rand_SUITE.erl
index d753d929f5..7685c17967 100644
--- a/lib/stdlib/test/rand_SUITE.erl
+++ b/lib/stdlib/test/rand_SUITE.erl
@@ -21,24 +21,7 @@
-compile({nowarn_deprecated_function,[{random,seed,1},
{random,uniform_s,1},
{random,uniform_s,2}]}).
-
--export([all/0, suite/0, groups/0, group/1]).
-
--export([interval_int/1, interval_float/1, seed/1,
- api_eq/1, reference/1,
- basic_stats_uniform_1/1, basic_stats_uniform_2/1,
- basic_stats_standard_normal/1,
- basic_stats_normal/1,
- stats_standard_normal_box_muller/1,
- stats_standard_normal_box_muller_2/1,
- stats_standard_normal/1,
- uniform_real_conv/1,
- plugin/1, measure/1,
- reference_jump_state/1, reference_jump_procdict/1]).
-
--export([test/0, gen/1]).
-
--export([uniform_real_gen/1, uniform_gen/2]).
+-compile([export_all, nowarn_export_all]).
-include_lib("common_test/include/ct.hrl").
@@ -56,7 +39,8 @@ all() ->
{group, distr_stats},
uniform_real_conv,
plugin, measure,
- {group, reference_jump}
+ {group, reference_jump},
+ short_jump
].
groups() ->
@@ -95,7 +79,7 @@ test() ->
end, Tests).
algs() ->
- [exrop, exsp, exs1024s, exs64, exsplus, exs1024].
+ [exsss, exrop, exsp, exs1024s, exs64, exsplus, exs1024, exro928ss].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -125,7 +109,7 @@ seed_1(Alg) ->
S0 = get(rand_seed),
S0 = rand:seed_s(Alg, {0, 0, 0}),
%% Check that process_dict should not be used for seed_s functionality
- _ = rand:seed_s(Alg, {1, 0, 0}),
+ _ = rand:seed_s(Alg, 4711),
S0 = get(rand_seed),
%% Test export
ES0 = rand:export_seed(),
@@ -262,31 +246,43 @@ reference(Config) when is_list(Config) ->
ok.
reference_1(Alg) ->
- Refval = reference_val(Alg),
- Testval = gen(Alg),
- case Refval =:= Testval of
- true -> ok;
- false when Refval =:= not_implemented ->
- exit({not_implemented,Alg});
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- exit(wrong_value)
+ Refval = reference_val(Alg),
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen(Alg) of
+ Refval ->
+ io:format("Ok: ~p~n",[Alg]),
+ ok;
+ Testval ->
+ io:format("Failed: ~p~n",[Alg]),
+ io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
+ io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ show_wrong(Refval, Testval),
+ exit(wrong_value)
+ end
end.
+show_wrong([], []) ->
+ ok;
+show_wrong([H|T1], [H|T2]) ->
+ show_wrong(T1, T2);
+show_wrong([H1|_], [H2|_]) ->
+ io:format("Wrong ~p ~p~n",[H1,H2]).
+
+
gen(Algo) ->
State =
- case Algo of
- exs64 -> %% Printed with orig 'C' code and this seed
- rand:seed_s({exs64, 12345678});
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
+ if
+ Algo =:= exs64 -> %% Printed with orig 'C' code and this seed
+ rand:seed_s(exs64, [12345678]);
+ Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
%% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
+ rand:seed_s(Algo, [12345678,12345678]);
+ Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
%% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, {lists:duplicate(16, 12345678), []}});
- _ ->
+ rand:seed_s(Algo, lists:duplicate(16, 12345678));
+ true ->
rand:seed(Algo, {100, 200, 300})
end,
Max = range(State),
@@ -442,7 +438,7 @@ stats_standard_normal_box_muller(Config) when is_list(Config) ->
([S|Z]) ->
{Z, [S]}
end,
- State = [rand:seed(exrop)],
+ State = [rand:seed(exsss)],
stats_standard_normal(NormalS, State, 3)
catch error:_ ->
{skip, "math:erfc/1 not supported"}
@@ -467,7 +463,7 @@ stats_standard_normal_box_muller_2(Config) when is_list(Config) ->
([S|Z]) ->
{Z, [S]}
end,
- State = [rand:seed(exrop)],
+ State = [rand:seed(exsss)],
stats_standard_normal(NormalS, State, 3)
catch error:_ ->
{skip, "math:erfc/1 not supported"}
@@ -475,10 +471,11 @@ stats_standard_normal_box_muller_2(Config) when is_list(Config) ->
stats_standard_normal(Config) when is_list(Config) ->
+ Retries = 7,
try math:erfc(1.0) of
_ ->
stats_standard_normal(
- fun rand:normal_s/1, rand:seed_s(exrop), 3)
+ fun rand:normal_s/1, rand:seed_s(exsss), Retries)
catch error:_ ->
{skip, "math:erfc/1 not supported"}
end.
@@ -852,7 +849,8 @@ do_measure(_Config) ->
Algs =
algs() ++
try crypto:strong_rand_bytes(1) of
- <<_>> -> [crypto64, crypto_cache, crypto]
+ <<_>> ->
+ [crypto64, crypto_cache, crypto_aes, crypto]
catch
error:low_entropy -> [];
error:undef -> []
@@ -1073,7 +1071,7 @@ do_measure(_Config) ->
end,
State)
end,
- exrop, TMarkNormalFloat),
+ exsss, TMarkNormalFloat),
ok.
-define(LOOP_MEASURE, (?LOOP div 5)).
@@ -1101,6 +1099,10 @@ measure_1(RangeFun, Fun, Alg, TMark) ->
{rand, crypto:rand_seed_alg(crypto_cache)};
crypto ->
{rand, crypto:rand_seed_s()};
+ crypto_aes ->
+ {rand,
+ crypto:rand_seed_alg(
+ crypto_aes, crypto:strong_rand_bytes(256))};
random ->
{random, random:seed(os:timestamp()), get(random_seed)};
_ ->
@@ -1116,7 +1118,7 @@ measure_1(RangeFun, Fun, Alg, TMark) ->
_ -> (Time * 100 + 50) div TMark
end,
io:format(
- "~.12w: ~p ns ~p% [16#~.16b]~n",
+ "~.20w: ~p ns ~p% [16#~.16b]~n",
[Alg, (Time * 1000 + 500) div ?LOOP_MEASURE,
Percent, Range]),
Parent ! {self(), Time},
@@ -1141,104 +1143,156 @@ reference_jump_state(Config) when is_list(Config) ->
ok.
reference_jump_1(Alg) ->
- Refval = reference_jump_val(Alg),
- Testval = gen_jump_1(Alg),
- case Refval =:= Testval of
- true -> ok;
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- io:format("Vals ~p ~p~n",[Refval, Testval]),
- exit(wrong_value)
+ Refval = reference_jump_val(Alg),
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen_jump_1(Alg) of
+ Refval -> ok;
+ Testval ->
+ io:format(
+ "Failed: ~p~n",[Alg]),
+ io:format(
+ "Length ~p ~p~n",
+ [length(Refval), length(Testval)]),
+ io:format(
+ "Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ io:format(
+ "Vals ~p ~p~n",[Refval, Testval]),
+ exit(wrong_value)
+ end
end.
gen_jump_1(Algo) ->
- State =
- case Algo of
- exs64 -> %% Test exception of not_implemented notice
- try rand:jump(rand:seed_s(exs64))
- catch
- error:not_implemented -> not_implemented
- end;
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
- %% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
- %% Printed with orig 'C' code and this seed
- rand:seed_s({Algo, {lists:duplicate(16, 12345678), []}});
- _ -> % unimplemented
- not_implemented
- end,
- case State of
- not_implemented -> [not_implemented];
- _ ->
- Max = range(State),
- gen_jump_1(?LOOP_JUMP, State, Max, [])
+ case Algo of
+ exs64 -> %% Test exception of not_implemented notice
+ try rand:jump(rand:seed_s(exs64))
+ catch
+ error:not_implemented -> [error_not_implemented]
+ end;
+ _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_2(
+ rand:seed_s(Algo, [12345678,12345678]));
+ _ when Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_2(
+ rand:seed_s(Algo, lists:duplicate(16, 12345678)))
end.
-gen_jump_1(N, State0, Max, Acc) when N > 0 ->
+gen_jump_2(State) ->
+ Max = range(State),
+ gen_jump_3(?LOOP_JUMP, State, Max, []).
+
+gen_jump_3(N, State0, Max, Acc) when N > 0 ->
{_, State1} = rand:uniform_s(Max, State0),
{Random, State2} = rand:uniform_s(Max, rand:jump(State1)),
case N rem (?LOOP_JUMP div 100) of
- 0 -> gen_jump_1(N-1, State2, Max, [Random|Acc]);
- _ -> gen_jump_1(N-1, State2, Max, Acc)
+ 0 -> gen_jump_3(N-1, State2, Max, [Random|Acc]);
+ _ -> gen_jump_3(N-1, State2, Max, Acc)
end;
-gen_jump_1(_, _, _, Acc) -> lists:reverse(Acc).
+gen_jump_3(_, _, _, Acc) -> lists:reverse(Acc).
%% Check if each algorithm generates the proper jump sequence
%% with the internal state in the process dictionary.
reference_jump_procdict(Config) when is_list(Config) ->
- [reference_jump_0(Alg) || Alg <- algs()],
+ [reference_jump_p1(Alg) || Alg <- algs()],
ok.
-reference_jump_0(Alg) ->
+reference_jump_p1(Alg) ->
Refval = reference_jump_val(Alg),
- Testval = gen_jump_0(Alg),
- case Refval =:= Testval of
- true -> ok;
- false ->
- io:format("Failed: ~p~n",[Alg]),
- io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
- io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
- exit(wrong_value)
+ if
+ Refval =:= not_implemented -> Refval;
+ true ->
+ case gen_jump_p1(Alg) of
+ Refval -> ok;
+ Testval ->
+ io:format("Failed: ~p~n",[Alg]),
+ io:format("Length ~p ~p~n",[length(Refval), length(Testval)]),
+ io:format("Head ~p ~p~n",[hd(Refval), hd(Testval)]),
+ exit(wrong_value)
+ end
end.
-gen_jump_0(Algo) ->
- Seed = case Algo of
- exs64 -> %% Test exception of not_implemented notice
- try
- _ = rand:seed(exs64),
- rand:jump()
- catch
- error:not_implemented -> not_implemented
- end;
- _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop ->
- %% Printed with orig 'C' code and this seed
- rand:seed({Algo, [12345678|12345678]});
- _ when Algo =:= exs1024; Algo =:= exs1024s ->
- %% Printed with orig 'C' code and this seed
- rand:seed({Algo, {lists:duplicate(16, 12345678), []}});
- _ -> % unimplemented
- not_implemented
- end,
- case Seed of
- not_implemented -> [not_implemented];
- _ ->
- Max = range(Seed),
- gen_jump_0(?LOOP_JUMP, Max, [])
+gen_jump_p1(Algo) ->
+ case Algo of
+ exs64 -> %% Test exception of not_implemented notice
+ try
+ _ = rand:seed(exs64),
+ rand:jump()
+ catch
+ error:not_implemented -> [error_not_implemented]
+ end;
+ _ when Algo =:= exsplus; Algo =:= exsp; Algo =:= exrop; Algo =:= exsss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_p2(
+ rand:seed(Algo, [12345678,12345678]));
+ _ when Algo =:= exs1024; Algo =:= exs1024s; Algo =:= exro928ss ->
+ %% Printed with orig 'C' code and this seed
+ gen_jump_p2(
+ rand:seed(Algo, lists:duplicate(16, 12345678)))
end.
-gen_jump_0(N, Max, Acc) when N > 0 ->
+gen_jump_p2(Seed) ->
+ Max = range(Seed),
+ gen_jump_p3(?LOOP_JUMP, Max, []).
+
+gen_jump_p3(N, Max, Acc) when N > 0 ->
_ = rand:uniform(Max),
_ = rand:jump(),
Random = rand:uniform(Max),
case N rem (?LOOP_JUMP div 100) of
- 0 -> gen_jump_0(N-1, Max, [Random|Acc]);
- _ -> gen_jump_0(N-1, Max, Acc)
+ 0 -> gen_jump_p3(N-1, Max, [Random|Acc]);
+ _ -> gen_jump_p3(N-1, Max, Acc)
end;
-gen_jump_0(_, _, Acc) -> lists:reverse(Acc).
+gen_jump_p3(_, _, Acc) -> lists:reverse(Acc).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+short_jump(Config) when is_list(Config) ->
+ Seed = erlang:system_time(),
+ short_jump(
+ rand:seed_s(exro928ss, Seed),
+ fun ({Alg,AlgState}) ->
+ {Alg,rand:exro928_jump_2pow20(AlgState)}
+ end),
+ short_jump(
+ crypto:rand_seed_alg_s(crypto_aes, integer_to_list(Seed)),
+ fun ({Alg,AlgState}) ->
+ {Alg,crypto:rand_plugin_aes_jump_2pow20(AlgState)}
+ end),
+ ok.
+
+short_jump({#{bits := Bits},_} = State_0, Jump2Pow20) ->
+ Range = 1 bsl Bits,
+ State_1 = repeat(7, Range, State_0),
+ %%
+ State_2a = repeat(1 bsl 20, Range, State_1),
+ State_2b = Jump2Pow20(State_1),
+ check(17, Range, State_2a, State_2b),
+ %%
+ {_,State_3a} = rand:uniform_s(Range, State_2a),
+ State_4a = Jump2Pow20(State_3a),
+ State_4b = repeat((1 bsl 20) + 1, Range, State_2b),
+ check(17, Range, State_4a, State_4b).
+
+repeat(0, _Range, State) ->
+ State;
+repeat(N, Range, State) ->
+ {_, NewState} = rand:uniform_s(Range, State),
+ repeat(N - 1, Range, NewState).
+
+check(0, _Range, _StateA, _StateB) ->
+ ok;
+check(N, Range, StateA, StateB) ->
+ {V,NewStateA} = rand:uniform_s(Range, StateA),
+ case rand:uniform_s(Range, StateB) of
+ {V,NewStateB} ->
+ check(N - 1, Range, NewStateA, NewStateB);
+ {Wrong,_} ->
+ ct:fail({Wrong,neq,V,for,N})
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Data
@@ -1323,6 +1377,34 @@ reference_val(exsplus) ->
16#3dd493b8012970f,16#be13bed1e00e5c,16#ceef033b74ae10,16#3da38c6a50abe03,
16#15cbd1a421c7a8c,16#22794e3ec6ef3b1,16#26154d26e7ea99f,16#3a66681359a6ab6];
+reference_val(exsss) ->
+ [16#108e8d5b01,16#33b72092117209a,16#224d4d2961a2d0a,16#2c4c81aac3da48d,
+ 16#2f4bc39bfc36f3a,16#41826d4c4d243a,16#19871b8bb4e23ee,16#3e2112cdf9384b1,
+ 16#69801943bf91ab,16#2de1a603c31ec45,16#a90ca1991b831e,16#51ca29571a69a7,
+ 16#93ce3e511906cf,16#93ebc5768aef75,16#2412f284b902ae7,16#1ac10e758410c52,
+ 16#3f32494560368f6,16#39a5e82dcf0de95,16#3f4b14d59cc6a21,16#3174668db0b36ae,
+ 16#1449812fb8bd54e,16#eaca1f8ece51e1,16#2564b2545fd23c1,16#3cf3a2d2217e0d7,
+ 16#226f4164ba1d054,16#10dac9ae207ceef,16#17f2c4b2d40fcb9,16#1c1b282d386fdcb,
+ 16#a264f450ba2912,16#2a0a1dd67e52666,16#2be84eb835cb1e1,16#2a1cd9aa16ccc37,
+ 16#7dd5e8c2b3f490,16#254a3db4976c05b,16#2a0a67971ec1e63,16#13a0cbf7c0eed8a,
+ 16#3192d7edc0a20bc,16#2705ad756292e84,16#3ec429a18119c81,16#25944b38baa975b,
+ 16#291dcc43e3256f4,16#30d10b759237db,16#c1522a652058a,16#8ef1e9378381e6,
+ 16#1f442f33c2439f4,16#186087710a73818,16#12887f94b2b8387,16#3e42e8b1f3c9b4b,
+ 16#e462859d55f9d8,16#2356ae85be908de,16#15e96a927b3bc52,16#35c6dc52511ce46,
+ 16#7bc0624ce66e01,16#33ab7d95b738322,16#26f01effc182aa0,16#1b66ae7eaafea88,
+ 16#278f3dc14943b90,16#22178bc8d8faf28,16#396c37d53c11985,16#5e0d79d0b10f18,
+ 16#1be3de3b5675ec,16#d4db298f1f4b50,16#2da6cb99bb5c7b1,16#130b2dc17d03be8,
+ 16#f1847e7e059e9f,16#2da6591788326e7,16#222e4a18c24211c,16#949213ca49baab,
+ 16#b5129fec56f6a2,16#30f25f1e926f43e,16#1ddd8d04445fb4d,16#15995b542514150,
+ 16#1595fe879296296,16#e2f237a488453b,16#23e5cd2d6047890,16#3a5dc88fc954666,
+ 16#89bca9969b103,16#5e6893cd35dc63,16#1fed534feeeef5a,16#26f40e2147ee558,
+ 16#30c131a00625837,16#2618a7e617422e9,16#23630b297e45e7,16#1143b17502f3219,
+ 16#15607dac41168da,16#2886bdc314b3fb8,16#465d1cc1536546,16#30b09123e3a02e4,
+ 16#245a375f810be52,16#6a1b0792376a03,16#221425f59f2470f,16#867ce16dfac81c,
+ 16#9c62d95fae9b58,16#380381db1394426,16#34908dedc01c324,16#1f0ff517089b561,
+ 16#1571366dd873d32,16#3ee353dc56e192,16#15a1dee8d889b11,16#41036ad76d9888
+ ];
+
reference_val(exsp) ->
reference_val(exsplus);
reference_val(exs1024s) ->
@@ -1389,7 +1471,50 @@ reference_val(exrop) ->
250789092615679985,78848633178610658,72059442721196128,
98223942961505519,191144652663779840,
102425686803727694,89058927716079076,80721467542933080,
- 8462479817391645,2774921106204163].
+ 8462479817391645,2774921106204163];
+
+reference_val(exro928ss) ->
+%% Same as for exrop, but this state init:
+%% for (n = 0; n < 16; n++) {
+%% s[n] = 12345678;
+ [16#000000108e8d5b01,16#03604028f2769dff,16#007f92f60bc7170c,
+ 16#035ea81a9898a5e2,16#0104c90c5a0c8178,16#0313514025cca717,
+ 16#03c5506b2a2e98cf,16#0098a5405961552e,16#004ad29eabb785a0,
+ 16#033ea8ec4efb8058,16#00b21545e62bef1c,16#0333fc5320703482,
+ 16#02c3c650e51a8d47,16#03a3b7fc848c9cda,16#03775adea6cddff5,
+ 16#01ae5499c9049973,16#03d3c90e5504e16b,16#0383cd6b6cb852e6,
+ 16#009c8d0996ef543a,16#0059cf671371af60,16#03dfd68ed980b719,
+ 16#0290f2a0acf2c5b0,16#029061df18d63b55,16#02e702ea4b45137b,
+ 16#029a0ccca604d848,16#01664c7cd31f0fa6,16#00dced83e60ccddc,
+ 16#008764d2c9a05f3e,16#02b9ca5f6a80c4ba,16#02daf93d2c566750,
+ 16#0147d326ead18ace,16#014b452efc19297f,16#0242d3f7a7237eca,
+ 16#0141bb68c2abce39,16#02d798e1230baf45,16#0216bf8f25c1ec2d,
+ 16#003a43ea733f1e1f,16#036c75390db736f3,16#028cca5f5f48c6f9,
+ 16#0186e4a17174d6cf,16#02152679dfa4c25c,16#01429b9f15e3b9d6,
+ 16#0134a61411d22bb0,16#01593f7d970d1c94,16#0205a7d8a305490f,
+ 16#01dd092272595a9c,16#0028c95208aad2d4,16#016347c25cc24162,
+ 16#025306acfb891309,16#0207a07e2bebef2f,16#024ee78d86ff5288,
+ 16#030b53192db97613,16#03f765cb9e98e611,16#025ec35a1e237377,
+ 16#03d81fd73102ef6f,16#0242dc8fea9a68b2,16#00abb876c1d4ea1b,
+ 16#00871ffd2b7e45fb,16#03593ff73c9be08d,16#00b96b2b8aca3688,
+ 16#0174aba957b7cf7b,16#012b7a5d4cf4a5b7,16#032a5260f2123db8,
+ 16#00f9374d88ee0080,16#030df39bec2ad657,16#00dce0cb81d006c4,
+ 16#038213b806303c76,16#03940aafdbfabf84,16#0398dbb26aeba037,
+ 16#01eb28d61951587f,16#00fed3d2aacfeef4,16#03499587547d6e40,
+ 16#01b192fe6e979e3c,16#00e974bf5f0a26d0,16#012ed94f76459c83,
+ 16#02d76859e7a82587,16#00d1d2c7b791f51b,16#03988058017a031b,
+ 16#00bbcf4b59d8e86d,16#015ed8b73a1b767c,16#0277283ea6a5ee74,
+ 16#002211460dd6d422,16#001ad62761ee9fbd,16#037311b44518b067,
+ 16#02b5ed61bf70904e,16#011862a05c1929fa,16#014be68683c3bab4,
+ 16#025c29aa5c508b07,16#00895c6106f97378,16#026ce91a3d671c7f,
+ 16#02591f4c74784293,16#02f0ed2a70bc1853,16#00a2762ff614bfbc,
+ 16#008f4e354f0c20d4,16#038b66fb587ed430,16#00636296e188de89,
+ 16#0278fadd143e74f5,16#029697ccf1b3a4c2,16#011eccb273404458,
+ 16#03f204064a9fe0c0];
+
+reference_val(_) ->
+ not_implemented.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1420,6 +1545,33 @@ reference_jump_val(exsplus) ->
12504080415362731, 45083100453836317, 270968267812126657, 93505647407734103,
252852934678537969, 258758309277167202, 74250882143432077, 141629095984552833];
+reference_jump_val(exsss) ->
+ [16#304ae783d40db2b,16#1dfb196b3a5600a,16#2a24116effc6a0d,16#1f138d68c56725,
+ 16#9360a445e2f989,16#32ed8080390e242,16#294ca85a270cff6,16#1418e6296a88bf,
+ 16#114fae3dc578ba7,16#479c42c760eb72,16#334a40655df22d6,16#e7a85dd4d37d72,
+ 16#181db16c8925c77,16#1b8a5a8afd16cbd,16#329107bf9777a39,16#2fc915c08535e42,
+ 16#16696d142c6078,16#2e2a2601c919448,16#2246150d1000568,16#26109007cb3dd44,
+ 16#3761360723e3175,16#169abd352db74de,16#1c97d520983684f,16#12455f0adee8c66,
+ 16#46719cff00622d,16#1fc92792ed4e437,16#18e2edae21affb5,16#3a67fa9e3e7d46e,
+ 16#1313fdc2728aa74,16#1c1a2b577581db8,16#db49357ea196b1,16#10e219a21d93fc7,
+ 16#3c43abede083666,16#3eef5055a58bbf9,16#1975056f95d90e3,16#3916c133ab16d87,
+ 16#2bc0bea891c26f1,16#391e4b369fc6b36,16#183f83155a359f6,16#1d9f137e9d2e488,
+ 16#ef084de5f4cd3c,16#36a9cf7e29e55d3,16#19eca704e0409a7,16#1bdb99902896c69,
+ 16#21777e2ad128203,16#5d0369ec0563e4,16#36db40b863bd74a,16#33feb71b7515159,
+ 16#208d923ce26f257,16#3841b32891c082d,16#2748f224c2ba226,16#2fcd93b2daf79bb,
+ 16#2c8e6cacad58ec4,16#39850131a1a85f,16#134648d6eea624d,16#2e102e197d5725c,
+ 16#12ac280fa744758,16#1c18266c7442d16,16#22b5f91b15fe17e,16#316740ca870f7c8,
+ 16#720ed4836c426,16#1aac0f738d04f8c,16#34fcd2a647b462c,16#3d430ac755114a3,
+ 16#3692e3670fdf2a,16#265279ab0fc0a15,16#10bd883dee80945,16#10e7843413175e4,
+ 16#b291deba08cee2,16#3915a8234caf11,16#34b911b96707dbd,16#ae63fcda15fde6,
+ 16#b13b9091e82e41,16#29de1b6d70dc04f,16#23fbcbc409617e8,16#1389a0738061066,
+ 16#360f39af790f5d1,16#f436da2a7d12f5,16#2d06ba8da21e08,16#3601a6492b887d,
+ 16#2b2590b8c6cc186,16#f8d613b6904464,16#e5456786e46b78,16#201b8b1f96ed80c,
+ 16#1b75b86d9b843f2,16#2e8bfaa7243a630,16#125ff068a78c3b4,16#3875a28c48bd26e,
+ 16#f09a06941fc9d7,16#107c4de8ca77744,16#357c34144bb9ed6,16#3ccc55d3ebb3378,
+ 16#28db7cea7d3fdee,16#3197fd0b49f6370,16#11af6fedb708ea6,16#2bde0382e37469e,
+ 16#10666171abddb3f,16#1a8876c1f4e78a8,16#169c0efd4422043,16#1501c49abf0440f];
+
reference_jump_val(exs1024) ->
[2655961906500790629, 17003395417078685063, 10466831598958356428, 7603399148503548021,
1650550950190587188, 12294992315080723704, 15743995773860389219, 5492181000145247327,
@@ -1451,7 +1603,7 @@ reference_jump_val(exsp) ->
reference_jump_val(exsplus);
reference_jump_val(exs1024s) ->
reference_jump_val(exs1024);
-reference_jump_val(exs64) -> [not_implemented];
+reference_jump_val(exs64) -> [error_not_implemented];
reference_jump_val(exrop) ->
%% #include <stdint.h>
%% #include <stdio.h>
@@ -1516,7 +1668,50 @@ reference_jump_val(exrop) ->
250227633882474729,171181147785250210,55437891969696407,
241227318715885854,77323084015890802,
1663590009695191,234064400749487599,222983191707424780,
- 254956809144783896,203898972156838252].
+ 254956809144783896,203898972156838252];
+
+reference_jump_val(exro928ss) ->
+%% Same as for exrop, but this state init:
+%% for (n = 0; n < 16; n++) {
+%% s[n] = 12345678;
+ [16#031ee449e53b6689,16#001afeee12813137,16#005e2172711df36b,
+ 16#02850aea3a595d36,16#0029705187e891c7,16#001794badd489667,
+ 16#00ab621be15be56c,16#024b663a6924786b,16#03cab70b8ab854bf,
+ 16#01daa37601285320,16#02db955a53c40e89,16#01fbef51d5c65891,
+ 16#02fecf4116ed5f77,16#0349c2057246ac5d,16#01217f257c4fa148,
+ 16#0367ee84d020697d,16#01d5cf647fe23335,16#020941838adfb750,
+ 16#02c2da26b1d7b3e5,16#00d1583d34cea6c0,16#038be9cb5b527f50,
+ 16#00bfa93c1d7f4864,16#03778912a4f56b14,16#037fcabc483fa5c5,
+ 16#00a3c9de6aaf5fc7,16#03600b883b2f2b42,16#03797a99ffddfdfb,
+ 16#0189fead429945b7,16#0103ac90cd912508,16#03e3d872fd950d64,
+ 16#0214fc3e77dc2f02,16#02a084f4f0e580ca,16#035d2fe72266a7f3,
+ 16#02887c49ae7e41a4,16#0011dc026af83c51,16#02d28bfd32c2c517,
+ 16#022e4165c33ad4f3,16#01f053cf0687b052,16#035315e6e53c8918,
+ 16#01255312da07b572,16#0237f1da11ec9221,16#02faf2e282fb1fb1,
+ 16#0227423ec1787ebc,16#011fa5eb1505571c,16#0275ff9eaaa1abdd,
+ 16#03e2d032c3981cb4,16#0181bb32d51d3072,16#01b1d3939b9f16ec,
+ 16#0259f09f55d1112f,16#0396464a2767e428,16#039777c0368bdb9e,
+ 16#0320925f35f36c5f,16#02a35289e0af1248,16#02e80bd4bc72254b,
+ 16#00a8b11af1674d68,16#027735036100a69e,16#03c8c268ded7f254,
+ 16#03de80aa57c65217,16#00f2247754d24000,16#005582a42b467f89,
+ 16#0031906569729477,16#00fd523f2ca4fefe,16#00ad223113d1e336,
+ 16#0238ddf026cbfca9,16#028b98211cfed876,16#0354353ebcc0de9a,
+ 16#009ee370c1e154f4,16#033131af3b8a7f88,16#032291baa45801e3,
+ 16#00941fc2b45eb217,16#035d6a61fa101647,16#03fdb51f736f1bbc,
+ 16#0232f7b98539faa0,16#0311b35319e3a61e,16#0048356b17860eb5,
+ 16#01a205b2554ce71e,16#03f873ea136e29d6,16#003c67d5c3df5ffd,
+ 16#00cd19e7a8641648,16#0149a8c54e4ba45e,16#0329498d134d2f6a,
+ 16#03b69421ae65ee2b,16#01a8d20b59447429,16#006b2292571032a2,
+ 16#00c193b17da22ba5,16#01faa7ab62181249,16#00acd401cd596a00,
+ 16#005b5086c3531402,16#0259113d5d3d058d,16#00bef3f3ce4a43b2,
+ 16#014837a4070b893c,16#00460a26ac2eeec1,16#026219a8b8c63d7e,
+ 16#03c7b8ed032cf5a6,16#004da912a1fff131,16#0297de3716215741,
+ 16#0079fb9b4c715466,16#00a73bad4ae5a356,16#0072e606c0d4ab86,
+ 16#02374382d5f9bd2e];
+
+reference_jump_val(_) ->
+ not_implemented.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt b/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt
new file mode 100644
index 0000000000..150f37fcfa
--- /dev/null
+++ b/lib/stdlib/test/rand_Xoroshiro928ss_dev.txt
@@ -0,0 +1,343 @@
+%CopyrightBegin%
+
+Copyright Ericsson AB 2015-2017. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+%CopyrightEnd%
+
+
+Memorable facts from designing the Xoroshiro928** generator
+===========================================================
+AKA: exro928ss in the rand module
+
+Author: Raimo Niskanen, for the Erlang/OTP team @ Ericsson.
+
+Reference URL: http://vigna.di.unimi.it/ftp/papers/ScrambledLinear.pdf
+i.e the Xoroshiro1024 generator with ** scrambler:
+
+ int p;
+ uint64_t s[16];
+
+ const int q = p;
+ const uint64_t s0 = s[p = (p + 1) & 15];
+
+ uint64_t s15 = s[q];
+
+ const uint64_t result_starstar = rotl(s0 * S, R) * T;
+
+ s15 ^= s0;
+ s[q] = rotl(s0, A) ^ s15 ^ (s15 << B);
+ s[p] = rotl(s15, C);
+
+Where {S, R, T} = {5, 7, 9} as recommended in the paper.
+
+We want to scale down to 58 bit words (16 of them)
+so we get a generator with period 2^928 - 1.
+
+{A, B, C} were deduced as follows
+---------------------------------
+
+First, to find which triplets that give a full period generator
+one have to factor 2^928 - 1.
+
+https://www.alpertron.com.ar/ECM.HTM actually could do that
+and gave the result:
+
+ Value
+ 2^928 - 1
+
+ 2269 007733 883335 972287 082669 296112 915239 349672 942191 252221 331572
+ 442536 403137 824056 312817 862695 551072 066953 619064 625508 194663
+ 368599 769448 406663 254670 871573 830845 597595 897613 333042 429214
+ 224697 474472 410882 236254 024057 110212 260250 671521 235807 709272
+ 244389 361641 091086 035023 229622 419455 (280 digits) = 3 × 5 × 17 × 59 ×
+ 233 × 257 × 929 × 1103 × 2089 × 5569 × 8353 × 59393 × 65537 × 3 033169 ×
+ 39 594977 × 107 367629 × 536 903681 × 748 264961 × 2245 984577 × 239
+ 686663 718401 × 15 929619 591127 520827 829953 × 82280 195167 144119
+ 832390 568177 × 6033 312171 721035 031651 315652 130497 (34 digits) × 18
+ 774318 450142 955120 650303 957350 521748 903233 (44 digits) × 15 694604
+ 006012 505869 851221 169365 594050 637743 819041 (50 digits)
+
+Sebastiano Vigna from that calculated all full period triplets, at the
+end of this document, and the ones with the highest degree were:
+
+ 23-25-12 411
+ 36-2-35 411
+ 55-5-54 411
+ 14-19-11 415
+ 34-37-5 415
+ 37-3-56 415
+ 55-11-54 417
+ 30-3-41 419
+ 11-45-50 423
+ 50-19-47 423
+ 52-27-13 427
+ 54-9-25 433
+ 56-43-35 433
+ 44-9-45 441
+
+All these candidates were tested with TestU01-1.2.3:
+
+ http://simul.iro.umontreal.ca/testu01/tu01.html
+
+A plugin was created with parameters for {A, B, C} and, since
+TestU01 is a 32-bit test tool, with parameters to reverse
+the generated bits or not, and to take the 32 highest or lowest
+bits from the reversed or non-reversed 58 bit output.
+
+The generators were seeded with a SplitMix64 generator like the
+one used for seeding this generator in the rand module,
+taking the 58 lowest bits and wasting all zero values.
+
+3 runs were made with all candidates and all four bit selection variants.
+For these runs the seeder was initialized with 12345678, 876543212345678
+and 1234567890.
+
+After all these runs the candidate with the highest degree: 44-9-45
+had not gotten any suspicious p-value at all. All the other
+got p-values around 5.0e-4 worst 9.8e-6 suggesting only random
+failures, so they would probably have worked about as well.
+
+Finally 44-9-45 was run through PractRand-0.93:
+
+ http://pracrand.sourceforge.net/
+
+Again, all 4 bit selection variants of 32 bits were run.
+Random failures with p-values around e-3..e-4 for the "smaller"
+tests, but for 8, 16 and 32 TB tests no anomalies were found
+(with the internal seeder masked to 58 bits):
+
+ Xoroshiro928High seed: 0x3178ec5d
+ Xoroshiro928Low seed: 0xa9a04fb9
+ Xoroshiro928ReverseHigh seed: 0xfa0bdbab
+ Xoroshiro928ReverseLow seed: 0xada51705
+
+
+Then, S. Vigna calculated the 2^512 jump coefficient as well
+as a 2^20 jump coefficient (for testing purposes) for 44-9-45.
+
+2^512:
+ { 0x44085302f77130ca, 0xba05381fdfd14902, 0x10a1de1d7d6813d2,
+ 0xb83fe51a1eb3be19, 0xa81b0090567fd9f0, 0x5ac26d5d20f9b49f,
+ 0x4ddd98ee4be41e01, 0x0657e19f00d4b358, 0xf02f778573cf0f0a,
+ 0xb45a3a8a3cef3cc0, 0x6e62a33cc2323831, 0xbcb3b7c4cc049c53,
+ 0x83f240c6007e76ce, 0xe19f5fc1a1504acd, 0x00000000b10773cb }
+
+2^20:
+ { 0xbdb966a3daf905e6, 0x644807a56270cf78, 0xda90f4a806c17e9e,
+ 0x4a426866bfad3c77, 0xaf699c306d8e7566, 0x8ebc73c700b8b091,
+ 0xc081a7bf148531fb, 0xdc4d3af15f8a4dfd, 0x90627c014098f4b6,
+ 0x06df2eb1feaf0fb6, 0x5bdeb1a5a90f2e6b, 0xa480c5878c3549bd,
+ 0xff45ef33c82f3d48, 0xa30bebc15fefcc78, 0x00000000cb3d181c }
+
+Standard jump function pseudocode:
+
+ Jump constant j = 0xb10773cb...44085302f77130ca
+ Generator state: s
+ New generator state: t = 0
+ foreach bit in j, low to high:
+ if the bit is one:
+ t ^= s
+ next s
+ s = t
+
+
+The complete list of full period constants
+------------------------------------------
+
+29-48-54 27 x^928 + x^874 + x^870 + x^840 + x^814 + x^784 + x^759 + x^750 + x^724 + x^720 + x^634 + x^630 + x^600 + x^574 + x^544 + x^519 + x^510 + x^484 + x^480 + x^390 + x^360 + x^270 + x^240 + x^150 + x^120 + x^30 + 1
+
+29-18-56 65 x^928 + x^870 + x^850 + x^840 + x^832 + x^821 + x^802 + x^791 + x^761 + x^750 + x^734 + x^731 + x^720 + x^712 + x^701 + x^686 + x^674 + x^671 + x^663 + x^641 + x^630 + x^611 + x^610 + x^603 + x^600 + x^596 + x^577 + x^566 + x^547 + x^524 + x^517 + x^510 + x^487 + x^480 + x^476 + x^464 + x^457 + x^446 + x^427 + x^423 + x^397 + x^390 + x^367 + x^363 + x^360 + x^356 + x^352 + x^341 + x^326 + x^322 + x^311 + x^281 + x^270 + x^251 + x^240 + x^236 + x^232 + x^221 + x^191 + x^161 + x^150 + x^131 + x^120 + x^30 + 1
+
+29-32-36 81 x^928 + x^874 + x^870 + x^840 + x^820 + x^819 + x^794 + x^790 + x^770 + x^765 + x^764 + x^760 + x^754 + x^750 + x^740 + x^739 + x^735 + x^734 + x^730 + x^709 + x^704 + x^674 + x^670 + x^665 + x^660 + x^650 + x^649 + x^635 + x^634 + x^619 + x^614 + x^605 + x^595 + x^585 + x^584 + x^579 + x^564 + x^555 + x^545 + x^540 + x^524 + x^515 + x^514 + x^495 + x^490 + x^485 + x^460 + x^455 + x^435 + x^425 + x^400 + x^395 + x^375 + x^370 + x^365 + x^340 + x^315 + x^310 + x^305 + x^300 + x^290 + x^285 + x^275 + x^260 + x^250 + x^245 + x^240 + x^215 + x^190 + x^180 + x^170 + x^150 + x^130 + x^120 + x^115 + x^105 + x^100 + x^75 + x^40 + x^30 + 1
+
+39-10-20 105 x^928 + x^898 + x^870 + x^841 + x^840 + x^808 + x^783 + x^782 + x^781 + x^780 + x^778 + x^754 + x^752 + x^724 + x^721 + x^720 + x^696 + x^692 + x^688 + x^667 + x^666 + x^661 + x^660 + x^658 + x^638 + x^636 + x^632 + x^609 + x^607 + x^606 + x^605 + x^604 + x^601 + x^600 + x^580 + x^578 + x^576 + x^572 + x^568 + x^549 + x^548 + x^541 + x^540 + x^538 + x^516 + x^512 + x^489 + x^485 + x^484 + x^481 + x^480 + x^456 + x^452 + x^448 + x^429 + x^428 + x^421 + x^420 + x^418 + x^400 + x^398 + x^396 + x^392 + x^368 + x^365 + x^364 + x^336 + x^328 + x^319 + x^318 + x^315 + x^314 + x^298 + x^286 + x^278 + x^276 + x^274 + x^255 + x^254 + x^249 + x^245 + x^228 + x^226 + x^220 + x^208 + x^199 + x^198 + x^189 + x^188 + x^178 + x^168 + x^166 + x^160 + x^129 + x^128 + x^108 + x^100 + x^88 + x^79 + x^78 + x^69 + x^68 + x^58 + x^40 + 1
+
+4-4-9 149 x^928 + x^898 + x^886 + x^870 + x^856 + x^826 + x^823 + x^808 + x^796 + x^793 + x^784 + x^778 + x^772 + x^766 + x^760 + x^754 + x^751 + x^742 + x^736 + x^734 + x^724 + x^713 + x^709 + x^706 + x^703 + x^694 + x^691 + x^688 + x^676 + x^674 + x^673 + x^664 + x^662 + x^658 + x^653 + x^641 + x^640 + x^634 + x^632 + x^631 + x^620 + x^614 + x^611 + x^608 + x^604 + x^602 + x^599 + x^590 + x^583 + x^581 + x^578 + x^574 + x^572 + x^571 + x^569 + x^568 + x^561 + x^554 + x^553 + x^551 + x^544 + x^542 + x^540 + x^538 + x^532 + x^531 + x^518 + x^514 + x^512 + x^502 + x^498 + x^489 + x^488 + x^484 + x^482 + x^480 + x^479 + x^468 + x^463 + x^456 + x^454 + x^452 + x^449 + x^448 + x^438 + x^433 + x^429 + x^424 + x^422 + x^420 + x^418 + x^408 + x^406 + x^401 + x^396 + x^394 + x^392 + x^380 + x^378 + x^376 + x^371 + x^367 + x^364 + x^362 + x^360 + x^350 + x^348 + x^346 + x^341 + x^334 + x^332 + x^328 + x^318 + x^311 + x^307 + x^304 + x^302 + x^300 + x^298 + x^288 + x^274 + x^272 + x^254 + x^249 + x^242 + x^240 + x^233 + x^212 + x^208 + x^189 + x^180 + x^178 + x^166 + x^152 + x^143 + x^136 + x^127 + x^122 + x^120 + x^113 + x^106 + x^88 + x^83 + x^81 + x^67 + x^58 + x^51 + x^14 + 1
+
+44-44-45 157 x^928 + x^898 + x^870 + x^850 + x^830 + x^820 + x^808 + x^800 + x^790 + x^782 + x^778 + x^777 + x^760 + x^757 + x^752 + x^747 + x^742 + x^727 + x^702 + x^694 + x^689 + x^688 + x^679 + x^674 + x^659 + x^658 + x^657 + x^644 + x^642 + x^637 + x^634 + x^627 + x^619 + x^612 + x^607 + x^606 + x^601 + x^596 + x^594 + x^591 + x^590 + x^584 + x^576 + x^568 + x^566 + x^561 + x^560 + x^556 + x^554 + x^546 + x^541 + x^539 + x^538 + x^518 + x^516 + x^511 + x^509 + x^503 + x^502 + x^499 + x^496 + x^488 + x^476 + x^471 + x^468 + x^466 + x^464 + x^448 + x^446 + x^441 + x^436 + x^421 + x^420 + x^415 + x^411 + x^408 + x^404 + x^400 + x^388 + x^383 + x^381 + x^379 + x^376 + x^363 + x^358 + x^356 + x^354 + x^346 + x^344 + x^340 + x^333 + x^330 + x^328 + x^325 + x^316 + x^312 + x^307 + x^305 + x^302 + x^284 + x^282 + x^277 + x^270 + x^268 + x^267 + x^256 + x^252 + x^249 + x^245 + x^244 + x^239 + x^238 + x^236 + x^231 + x^228 + x^226 + x^224 + x^222 + x^215 + x^208 + x^207 + x^205 + x^203 + x^201 + x^199 + x^196 + x^194 + x^192 + x^189 + x^185 + x^184 + x^182 + x^180 + x^175 + x^171 + x^168 + x^166 + x^162 + x^161 + x^155 + x^152 + x^150 + x^141 + x^134 + x^132 + x^131 + x^127 + x^122 + x^111 + x^104 + x^92 + x^90 + x^83 + x^81 + x^58 + x^37 + 1
+
+40-40-7 167 x^928 + x^898 + x^870 + x^866 + x^838 + x^836 + x^807 + x^806 + x^804 + x^778 + x^777 + x^774 + x^745 + x^744 + x^742 + x^718 + x^714 + x^713 + x^712 + x^687 + x^658 + x^657 + x^656 + x^655 + x^654 + x^626 + x^620 + x^619 + x^598 + x^596 + x^592 + x^591 + x^589 + x^566 + x^564 + x^563 + x^562 + x^560 + x^558 + x^538 + x^534 + x^530 + x^529 + x^504 + x^503 + x^502 + x^500 + x^499 + x^498 + x^496 + x^478 + x^474 + x^470 + x^469 + x^443 + x^442 + x^441 + x^439 + x^438 + x^436 + x^434 + x^432 + x^418 + x^416 + x^414 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^386 + x^383 + x^380 + x^374 + x^373 + x^372 + x^370 + x^356 + x^350 + x^349 + x^348 + x^347 + x^346 + x^345 + x^340 + x^328 + x^326 + x^324 + x^323 + x^321 + x^316 + x^314 + x^308 + x^298 + x^296 + x^294 + x^289 + x^285 + x^283 + x^282 + x^281 + x^280 + x^278 + x^263 + x^262 + x^259 + x^257 + x^255 + x^251 + x^249 + x^248 + x^246 + x^233 + x^232 + x^229 + x^220 + x^218 + x^217 + x^216 + x^208 + x^202 + x^201 + x^199 + x^195 + x^190 + x^188 + x^187 + x^186 + x^178 + x^172 + x^169 + x^167 + x^162 + x^161 + x^159 + x^158 + x^157 + x^146 + x^142 + x^139 + x^135 + x^125 + x^123 + x^116 + x^112 + x^107 + x^105 + x^94 + x^93 + x^88 + x^86 + x^84 + x^82 + x^75 + x^73 + x^69 + x^64 + x^58 + x^56 + x^54 + x^52 + x^43 + x^41 + x^39 + x^32 + 1
+
+47-47-18 217 x^928 + x^898 + x^871 + x^870 + x^843 + x^842 + x^841 + x^813 + x^812 + x^811 + x^808 + x^787 + x^786 + x^785 + x^783 + x^781 + x^778 + x^759 + x^757 + x^754 + x^753 + x^751 + x^729 + x^727 + x^726 + x^723 + x^721 + x^701 + x^700 + x^699 + x^697 + x^693 + x^691 + x^688 + x^673 + x^672 + x^670 + x^667 + x^663 + x^661 + x^658 + x^647 + x^644 + x^641 + x^637 + x^633 + x^631 + x^618 + x^617 + x^614 + x^613 + x^612 + x^611 + x^610 + x^607 + x^603 + x^601 + x^586 + x^585 + x^582 + x^581 + x^580 + x^577 + x^573 + x^571 + x^568 + x^562 + x^560 + x^556 + x^555 + x^554 + x^553 + x^551 + x^547 + x^543 + x^541 + x^538 + x^532 + x^530 + x^528 + x^524 + x^522 + x^521 + x^517 + x^513 + x^511 + x^506 + x^504 + x^502 + x^500 + x^497 + x^495 + x^491 + x^487 + x^483 + x^481 + x^478 + x^474 + x^472 + x^467 + x^466 + x^465 + x^461 + x^457 + x^453 + x^451 + x^444 + x^438 + x^437 + x^436 + x^435 + x^431 + x^427 + x^423 + x^412 + x^408 + x^407 + x^405 + x^401 + x^397 + x^390 + x^384 + x^377 + x^375 + x^371 + x^367 + x^366 + x^365 + x^363 + x^362 + x^360 + x^358 + x^356 + x^352 + x^350 + x^347 + x^345 + x^341 + x^337 + x^336 + x^334 + x^332 + x^324 + x^317 + x^315 + x^311 + x^307 + x^306 + x^305 + x^304 + x^302 + x^300 + x^298 + x^296 + x^287 + x^285 + x^281 + x^279 + x^277 + x^276 + x^274 + x^268 + x^266 + x^257 + x^255 + x^247 + x^244 + x^242 + x^240 + x^238 + x^234 + x^227 + x^221 + x^219 + x^216 + x^214 + x^206 + x^197 + x^195 + x^193 + x^182 + x^176 + x^161 + x^156 + x^152 + x^146 + x^139 + x^133 + x^116 + x^111 + x^109 + x^107 + x^96 + x^94 + x^92 + x^90 + x^88 + x^85 + x^81 + x^79 + x^77 + x^73 + x^66 + x^64 + x^62 + x^60 + x^53 + x^51 + x^47 + x^45 + x^36 + x^34 + x^32 + x^19 + x^17 + x^15 + 1
+
+31-52-54 249 x^928 + x^898 + x^872 + x^870 + x^842 + x^841 + x^838 + x^836 + x^812 + x^810 + x^782 + x^781 + x^779 + x^778 + x^774 + x^753 + x^752 + x^750 + x^748 + x^723 + x^722 + x^721 + x^719 + x^717 + x^714 + x^712 + x^694 + x^690 + x^689 + x^688 + x^686 + x^684 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^653 + x^652 + x^650 + x^634 + x^633 + x^631 + x^630 + x^629 + x^628 + x^622 + x^604 + x^599 + x^597 + x^596 + x^593 + x^592 + x^590 + x^588 + x^570 + x^567 + x^566 + x^562 + x^560 + x^536 + x^534 + x^533 + x^531 + x^530 + x^526 + x^513 + x^512 + x^510 + x^509 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^498 + x^483 + x^482 + x^481 + x^479 + x^478 + x^476 + x^466 + x^464 + x^454 + x^445 + x^438 + x^424 + x^423 + x^422 + x^421 + x^419 + x^418 + x^411 + x^404 + x^402 + x^394 + x^393 + x^392 + x^391 + x^390 + x^387 + x^386 + x^383 + x^380 + x^379 + x^378 + x^377 + x^376 + x^374 + x^364 + x^362 + x^361 + x^359 + x^357 + x^356 + x^355 + x^354 + x^351 + x^349 + x^348 + x^347 + x^345 + x^342 + x^340 + x^332 + x^330 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^321 + x^319 + x^318 + x^316 + x^314 + x^312 + x^302 + x^301 + x^300 + x^296 + x^295 + x^294 + x^291 + x^289 + x^287 + x^286 + x^283 + x^278 + x^266 + x^265 + x^264 + x^263 + x^262 + x^260 + x^259 + x^255 + x^250 + x^234 + x^232 + x^229 + x^227 + x^226 + x^225 + x^222 + x^218 + x^216 + x^208 + x^204 + x^200 + x^198 + x^197 + x^195 + x^194 + x^193 + x^190 + x^188 + x^178 + x^174 + x^173 + x^172 + x^171 + x^170 + x^169 + x^168 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^157 + x^156 + x^154 + x^142 + x^141 + x^139 + x^138 + x^135 + x^131 + x^128 + x^126 + x^116 + x^112 + x^110 + x^107 + x^106 + x^105 + x^104 + x^102 + x^100 + x^98 + x^96 + x^95 + x^94 + x^92 + x^88 + x^80 + x^79 + x^76 + x^74 + x^73 + x^71 + x^70 + x^69 + x^66 + x^65 + x^64 + x^56 + x^54 + x^48 + x^46 + x^45 + x^43 + x^38 + x^35 + x^33 + x^30 + 1
+
+57-54-32 249 x^928 + x^898 + x^870 + x^855 + x^848 + x^834 + x^826 + x^825 + x^808 + x^806 + x^805 + x^804 + x^798 + x^796 + x^788 + x^778 + x^776 + x^775 + x^766 + x^763 + x^756 + x^752 + x^745 + x^742 + x^736 + x^735 + x^734 + x^731 + x^715 + x^714 + x^713 + x^705 + x^703 + x^694 + x^688 + x^684 + x^682 + x^671 + x^660 + x^658 + x^652 + x^642 + x^641 + x^639 + x^634 + x^630 + x^621 + x^620 + x^616 + x^612 + x^609 + x^604 + x^602 + x^593 + x^591 + x^584 + x^579 + x^570 + x^568 + x^566 + x^565 + x^562 + x^558 + x^554 + x^550 + x^544 + x^536 + x^535 + x^533 + x^530 + x^529 + x^528 + x^524 + x^522 + x^517 + x^512 + x^505 + x^496 + x^494 + x^492 + x^491 + x^489 + x^480 + x^478 + x^475 + x^471 + x^464 + x^461 + x^454 + x^452 + x^450 + x^446 + x^445 + x^441 + x^438 + x^437 + x^436 + x^434 + x^430 + x^429 + x^427 + x^425 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^409 + x^402 + x^397 + x^394 + x^392 + x^388 + x^386 + x^384 + x^377 + x^375 + x^371 + x^368 + x^367 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^356 + x^353 + x^351 + x^346 + x^342 + x^341 + x^338 + x^335 + x^333 + x^330 + x^328 + x^326 + x^325 + x^317 + x^307 + x^304 + x^300 + x^296 + x^295 + x^293 + x^292 + x^288 + x^286 + x^285 + x^284 + x^283 + x^278 + x^277 + x^276 + x^273 + x^271 + x^270 + x^262 + x^261 + x^255 + x^253 + x^249 + x^248 + x^246 + x^245 + x^240 + x^236 + x^232 + x^231 + x^227 + x^224 + x^223 + x^221 + x^220 + x^217 + x^216 + x^212 + x^208 + x^205 + x^204 + x^198 + x^196 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^178 + x^176 + x^175 + x^171 + x^169 + x^165 + x^160 + x^159 + x^158 + x^154 + x^152 + x^150 + x^148 + x^146 + x^144 + x^141 + x^134 + x^132 + x^131 + x^129 + x^127 + x^125 + x^123 + x^120 + x^118 + x^114 + x^113 + x^111 + x^106 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^97 + x^95 + x^93 + x^88 + x^85 + x^77 + x^67 + x^62 + x^60 + x^55 + x^54 + x^53 + x^52 + x^51 + x^50 + x^48 + x^46 + x^40 + x^37 + x^33 + x^28 + x^27 + x^24 + 1
+
+1-38-28 251 x^928 + x^898 + x^870 + x^866 + x^836 + x^834 + x^832 + x^818 + x^808 + x^806 + x^804 + x^797 + x^788 + x^778 + x^776 + x^770 + x^767 + x^765 + x^738 + x^736 + x^733 + x^724 + x^717 + x^708 + x^706 + x^703 + x^701 + x^690 + x^688 + x^685 + x^678 + x^677 + x^676 + x^674 + x^672 + x^664 + x^658 + x^656 + x^652 + x^647 + x^645 + x^640 + x^626 + x^624 + x^621 + x^620 + x^616 + x^610 + x^608 + x^604 + x^600 + x^594 + x^593 + x^592 + x^590 + x^580 + x^578 + x^576 + x^575 + x^574 + x^572 + x^568 + x^566 + x^565 + x^564 + x^562 + x^560 + x^558 + x^552 + x^550 + x^549 + x^548 + x^544 + x^541 + x^538 + x^536 + x^533 + x^532 + x^529 + x^526 + x^522 + x^520 + x^519 + x^517 + x^514 + x^513 + x^509 + x^508 + x^504 + x^501 + x^494 + x^493 + x^484 + x^482 + x^469 + x^468 + x^466 + x^461 + x^453 + x^452 + x^448 + x^447 + x^436 + x^428 + x^424 + x^422 + x^420 + x^416 + x^414 + x^413 + x^412 + x^409 + x^408 + x^406 + x^405 + x^404 + x^400 + x^399 + x^397 + x^393 + x^391 + x^388 + x^385 + x^382 + x^381 + x^376 + x^374 + x^372 + x^370 + x^368 + x^366 + x^365 + x^360 + x^350 + x^349 + x^344 + x^341 + x^340 + x^336 + x^335 + x^334 + x^333 + x^332 + x^328 + x^326 + x^322 + x^319 + x^318 + x^308 + x^304 + x^300 + x^298 + x^293 + x^292 + x^290 + x^289 + x^287 + x^284 + x^281 + x^279 + x^278 + x^272 + x^271 + x^269 + x^264 + x^263 + x^261 + x^256 + x^254 + x^253 + x^250 + x^240 + x^238 + x^234 + x^229 + x^228 + x^226 + x^223 + x^221 + x^218 + x^213 + x^210 + x^208 + x^204 + x^198 + x^197 + x^196 + x^194 + x^191 + x^188 + x^186 + x^180 + x^176 + x^174 + x^172 + x^170 + x^169 + x^167 + x^165 + x^161 + x^159 + x^157 + x^153 + x^150 + x^149 + x^148 + x^145 + x^136 + x^135 + x^134 + x^133 + x^132 + x^130 + x^128 + x^127 + x^125 + x^122 + x^120 + x^118 + x^113 + x^110 + x^109 + x^108 + x^100 + x^96 + x^94 + x^92 + x^90 + x^88 + x^86 + x^85 + x^84 + x^81 + x^80 + x^72 + x^70 + x^66 + x^58 + x^53 + x^45 + x^36 + x^34 + x^32 + x^30 + x^24 + x^20 + x^16 + x^12 + x^8 + x^2 + 1
+
+47-57-20 279 x^928 + x^898 + x^880 + x^870 + x^864 + x^851 + x^850 + x^846 + x^830 + x^821 + x^820 + x^817 + x^812 + x^808 + x^807 + x^804 + x^796 + x^790 + x^783 + x^782 + x^777 + x^773 + x^762 + x^757 + x^753 + x^744 + x^743 + x^739 + x^731 + x^728 + x^714 + x^713 + x^710 + x^709 + x^705 + x^701 + x^694 + x^692 + x^688 + x^684 + x^683 + x^675 + x^672 + x^671 + x^668 + x^662 + x^660 + x^654 + x^653 + x^646 + x^642 + x^641 + x^637 + x^626 + x^624 + x^623 + x^608 + x^607 + x^603 + x^598 + x^593 + x^592 + x^590 + x^585 + x^578 + x^577 + x^574 + x^573 + x^572 + x^569 + x^568 + x^567 + x^563 + x^559 + x^558 + x^555 + x^551 + x^548 + x^547 + x^542 + x^539 + x^538 + x^537 + x^536 + x^535 + x^532 + x^530 + x^529 + x^525 + x^524 + x^521 + x^518 + x^517 + x^506 + x^505 + x^501 + x^496 + x^491 + x^490 + x^487 + x^471 + x^467 + x^462 + x^456 + x^452 + x^448 + x^446 + x^441 + x^440 + x^437 + x^433 + x^428 + x^420 + x^412 + x^411 + x^404 + x^403 + x^402 + x^401 + x^399 + x^398 + x^396 + x^394 + x^381 + x^378 + x^376 + x^371 + x^370 + x^366 + x^365 + x^360 + x^355 + x^354 + x^351 + x^348 + x^346 + x^344 + x^342 + x^340 + x^339 + x^337 + x^335 + x^333 + x^331 + x^330 + x^329 + x^328 + x^327 + x^320 + x^318 + x^313 + x^307 + x^299 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^291 + x^283 + x^282 + x^281 + x^280 + x^279 + x^277 + x^276 + x^266 + x^265 + x^264 + x^263 + x^262 + x^261 + x^259 + x^258 + x^257 + x^256 + x^251 + x^248 + x^247 + x^242 + x^240 + x^235 + x^234 + x^233 + x^231 + x^230 + x^229 + x^227 + x^225 + x^224 + x^219 + x^214 + x^212 + x^210 + x^206 + x^204 + x^203 + x^200 + x^196 + x^195 + x^194 + x^192 + x^191 + x^190 + x^188 + x^185 + x^182 + x^178 + x^176 + x^173 + x^159 + x^158 + x^157 + x^156 + x^151 + x^146 + x^144 + x^143 + x^142 + x^140 + x^138 + x^136 + x^131 + x^130 + x^128 + x^127 + x^126 + x^123 + x^122 + x^118 + x^117 + x^115 + x^114 + x^113 + x^108 + x^105 + x^99 + x^98 + x^94 + x^90 + x^88 + x^87 + x^86 + x^84 + x^82 + x^81 + x^80 + x^79 + x^78 + x^75 + x^74 + x^72 + x^71 + x^70 + x^65 + x^64 + x^58 + x^57 + x^56 + x^55 + x^52 + x^50 + x^48 + x^47 + x^46 + x^45 + x^42 + x^39 + x^26 + x^24 + x^23 + x^22 + x^20 + x^18 + x^15 + x^8 + x^4 + 1
+
+3-16-56 281 x^928 + x^898 + x^882 + x^870 + x^836 + x^820 + x^816 + x^808 + x^803 + x^802 + x^799 + x^778 + x^773 + x^770 + x^762 + x^757 + x^754 + x^753 + x^750 + x^737 + x^733 + x^720 + x^717 + x^713 + x^700 + x^688 + x^683 + x^680 + x^679 + x^674 + x^660 + x^658 + x^656 + x^654 + x^653 + x^650 + x^646 + x^644 + x^641 + x^640 + x^637 + x^634 + x^633 + x^623 + x^618 + x^617 + x^616 + x^613 + x^597 + x^590 + x^585 + x^584 + x^581 + x^577 + x^574 + x^572 + x^563 + x^562 + x^560 + x^555 + x^554 + x^553 + x^551 + x^547 + x^544 + x^537 + x^536 + x^533 + x^525 + x^521 + x^520 + x^519 + x^517 + x^515 + x^513 + x^510 + x^508 + x^505 + x^502 + x^501 + x^498 + x^493 + x^490 + x^485 + x^480 + x^477 + x^476 + x^475 + x^472 + x^469 + x^461 + x^458 + x^453 + x^449 + x^448 + x^445 + x^444 + x^442 + x^435 + x^433 + x^432 + x^431 + x^426 + x^425 + x^422 + x^420 + x^418 + x^412 + x^411 + x^409 + x^405 + x^403 + x^401 + x^400 + x^397 + x^393 + x^385 + x^381 + x^368 + x^366 + x^365 + x^362 + x^361 + x^359 + x^356 + x^353 + x^350 + x^346 + x^341 + x^338 + x^335 + x^334 + x^333 + x^332 + x^328 + x^326 + x^325 + x^323 + x^322 + x^320 + x^319 + x^317 + x^316 + x^315 + x^313 + x^312 + x^310 + x^309 + x^307 + x^305 + x^300 + x^295 + x^293 + x^291 + x^290 + x^289 + x^288 + x^286 + x^285 + x^282 + x^277 + x^274 + x^273 + x^266 + x^265 + x^263 + x^261 + x^259 + x^255 + x^253 + x^251 + x^248 + x^247 + x^246 + x^242 + x^241 + x^239 + x^234 + x^233 + x^232 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^222 + x^218 + x^217 + x^215 + x^212 + x^210 + x^208 + x^206 + x^205 + x^203 + x^201 + x^200 + x^194 + x^193 + x^191 + x^189 + x^183 + x^181 + x^180 + x^178 + x^177 + x^176 + x^174 + x^172 + x^171 + x^169 + x^167 + x^166 + x^163 + x^162 + x^159 + x^157 + x^155 + x^151 + x^150 + x^149 + x^147 + x^140 + x^139 + x^138 + x^137 + x^136 + x^134 + x^131 + x^128 + x^127 + x^126 + x^121 + x^119 + x^118 + x^117 + x^111 + x^106 + x^104 + x^102 + x^101 + x^99 + x^98 + x^91 + x^90 + x^88 + x^86 + x^85 + x^81 + x^79 + x^75 + x^74 + x^73 + x^72 + x^71 + x^69 + x^68 + x^65 + x^64 + x^63 + x^62 + x^61 + x^58 + x^57 + x^56 + x^55 + x^51 + x^50 + x^49 + x^41 + x^38 + x^36 + x^34 + x^33 + x^32 + x^24 + x^21 + x^9 + x^6 + 1
+
+10-38-9 285 x^928 + x^898 + x^870 + x^841 + x^840 + x^838 + x^836 + x^811 + x^810 + x^781 + x^777 + x^774 + x^751 + x^748 + x^723 + x^721 + x^720 + x^719 + x^718 + x^717 + x^716 + x^714 + x^712 + x^694 + x^692 + x^691 + x^688 + x^686 + x^664 + x^663 + x^661 + x^660 + x^659 + x^657 + x^652 + x^650 + x^632 + x^631 + x^630 + x^628 + x^627 + x^625 + x^624 + x^623 + x^605 + x^604 + x^603 + x^599 + x^597 + x^594 + x^593 + x^591 + x^590 + x^588 + x^576 + x^575 + x^574 + x^572 + x^571 + x^570 + x^569 + x^567 + x^565 + x^560 + x^544 + x^543 + x^542 + x^540 + x^539 + x^537 + x^535 + x^531 + x^526 + x^514 + x^510 + x^509 + x^507 + x^506 + x^505 + x^504 + x^503 + x^502 + x^498 + x^485 + x^484 + x^478 + x^474 + x^471 + x^470 + x^468 + x^466 + x^464 + x^458 + x^455 + x^452 + x^450 + x^449 + x^448 + x^445 + x^441 + x^439 + x^428 + x^419 + x^416 + x^415 + x^411 + x^407 + x^406 + x^405 + x^404 + x^402 + x^398 + x^392 + x^388 + x^385 + x^384 + x^383 + x^382 + x^381 + x^380 + x^379 + x^376 + x^374 + x^364 + x^359 + x^357 + x^356 + x^355 + x^354 + x^353 + x^351 + x^349 + x^346 + x^345 + x^343 + x^340 + x^338 + x^334 + x^328 + x^326 + x^325 + x^324 + x^321 + x^320 + x^319 + x^318 + x^315 + x^314 + x^312 + x^306 + x^298 + x^297 + x^295 + x^294 + x^293 + x^291 + x^288 + x^287 + x^286 + x^285 + x^283 + x^282 + x^281 + x^278 + x^276 + x^274 + x^270 + x^269 + x^268 + x^263 + x^261 + x^256 + x^255 + x^254 + x^244 + x^242 + x^237 + x^236 + x^235 + x^234 + x^233 + x^232 + x^229 + x^225 + x^222 + x^219 + x^216 + x^214 + x^212 + x^210 + x^209 + x^208 + x^207 + x^206 + x^202 + x^198 + x^194 + x^193 + x^192 + x^191 + x^190 + x^184 + x^182 + x^178 + x^176 + x^175 + x^174 + x^173 + x^168 + x^166 + x^164 + x^160 + x^159 + x^157 + x^154 + x^152 + x^151 + x^150 + x^145 + x^144 + x^142 + x^136 + x^135 + x^134 + x^129 + x^128 + x^122 + x^121 + x^119 + x^118 + x^116 + x^114 + x^113 + x^112 + x^111 + x^108 + x^105 + x^103 + x^100 + x^98 + x^97 + x^95 + x^94 + x^92 + x^89 + x^88 + x^87 + x^85 + x^84 + x^83 + x^78 + x^76 + x^74 + x^73 + x^71 + x^70 + x^69 + x^67 + x^66 + x^64 + x^61 + x^59 + x^57 + x^56 + x^54 + x^53 + x^51 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^32 + x^30 + x^4 + 1
+
+15-22-28 289 x^928 + x^898 + x^870 + x^838 + x^821 + x^806 + x^805 + x^792 + x^790 + x^778 + x^774 + x^762 + x^745 + x^744 + x^718 + x^697 + x^682 + x^672 + x^670 + x^667 + x^666 + x^658 + x^656 + x^653 + x^652 + x^651 + x^650 + x^642 + x^641 + x^638 + x^637 + x^623 + x^608 + x^607 + x^598 + x^594 + x^588 + x^575 + x^574 + x^573 + x^566 + x^565 + x^564 + x^563 + x^562 + x^557 + x^548 + x^547 + x^542 + x^538 + x^533 + x^531 + x^529 + x^526 + x^517 + x^516 + x^514 + x^513 + x^505 + x^504 + x^503 + x^502 + x^501 + x^499 + x^498 + x^497 + x^488 + x^487 + x^484 + x^483 + x^482 + x^474 + x^470 + x^468 + x^467 + x^466 + x^464 + x^457 + x^454 + x^453 + x^449 + x^447 + x^444 + x^443 + x^442 + x^441 + x^440 + x^439 + x^437 + x^436 + x^435 + x^428 + x^427 + x^426 + x^425 + x^422 + x^418 + x^417 + x^414 + x^409 + x^406 + x^405 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^379 + x^378 + x^374 + x^372 + x^371 + x^368 + x^367 + x^362 + x^361 + x^358 + x^357 + x^354 + x^350 + x^349 + x^347 + x^342 + x^341 + x^340 + x^334 + x^333 + x^332 + x^331 + x^330 + x^329 + x^328 + x^327 + x^324 + x^323 + x^320 + x^319 + x^313 + x^308 + x^307 + x^305 + x^303 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^292 + x^288 + x^287 + x^286 + x^283 + x^282 + x^280 + x^279 + x^278 + x^277 + x^276 + x^271 + x^269 + x^268 + x^267 + x^266 + x^265 + x^255 + x^254 + x^253 + x^249 + x^247 + x^241 + x^238 + x^237 + x^236 + x^235 + x^226 + x^225 + x^224 + x^223 + x^220 + x^219 + x^215 + x^214 + x^212 + x^210 + x^209 + x^205 + x^202 + x^201 + x^200 + x^199 + x^197 + x^190 + x^186 + x^182 + x^181 + x^180 + x^177 + x^174 + x^173 + x^172 + x^171 + x^170 + x^169 + x^168 + x^165 + x^163 + x^161 + x^160 + x^158 + x^155 + x^153 + x^151 + x^150 + x^146 + x^143 + x^142 + x^137 + x^136 + x^135 + x^131 + x^130 + x^128 + x^127 + x^126 + x^125 + x^124 + x^123 + x^122 + x^120 + x^119 + x^117 + x^114 + x^113 + x^111 + x^105 + x^104 + x^103 + x^102 + x^101 + x^99 + x^97 + x^93 + x^90 + x^89 + x^88 + x^87 + x^86 + x^84 + x^83 + x^82 + x^81 + x^80 + x^79 + x^77 + x^75 + x^72 + x^71 + x^70 + x^69 + x^68 + x^65 + x^60 + x^59 + x^58 + x^55 + x^54 + x^52 + x^51 + x^50 + x^48 + x^43 + x^42 + x^40 + x^39 + x^30 + x^28 + x^27 + x^24 + x^23 + x^19 + x^16 + x^15 + 1
+
+12-41-35 291 x^928 + x^898 + x^886 + x^873 + x^870 + x^860 + x^856 + x^847 + x^844 + x^834 + x^830 + x^826 + x^818 + x^817 + x^805 + x^804 + x^796 + x^795 + x^791 + x^784 + x^782 + x^779 + x^769 + x^765 + x^762 + x^758 + x^756 + x^753 + x^752 + x^743 + x^739 + x^736 + x^735 + x^732 + x^731 + x^730 + x^727 + x^726 + x^723 + x^722 + x^717 + x^713 + x^710 + x^705 + x^701 + x^700 + x^692 + x^685 + x^683 + x^680 + x^676 + x^671 + x^663 + x^659 + x^657 + x^654 + x^653 + x^645 + x^642 + x^637 + x^632 + x^628 + x^624 + x^623 + x^619 + x^616 + x^615 + x^612 + x^610 + x^607 + x^606 + x^603 + x^598 + x^597 + x^594 + x^593 + x^590 + x^589 + x^585 + x^580 + x^577 + x^576 + x^572 + x^567 + x^564 + x^560 + x^559 + x^556 + x^550 + x^545 + x^543 + x^538 + x^537 + x^534 + x^533 + x^532 + x^528 + x^520 + x^516 + x^513 + x^508 + x^507 + x^506 + x^504 + x^499 + x^496 + x^491 + x^490 + x^487 + x^486 + x^485 + x^481 + x^477 + x^474 + x^466 + x^465 + x^457 + x^452 + x^448 + x^447 + x^446 + x^438 + x^436 + x^435 + x^434 + x^430 + x^425 + x^422 + x^421 + x^417 + x^413 + x^409 + x^404 + x^395 + x^393 + x^392 + x^388 + x^387 + x^386 + x^384 + x^382 + x^380 + x^379 + x^374 + x^373 + x^370 + x^367 + x^366 + x^362 + x^361 + x^358 + x^357 + x^354 + x^353 + x^352 + x^350 + x^349 + x^345 + x^344 + x^343 + x^340 + x^337 + x^336 + x^332 + x^331 + x^328 + x^324 + x^323 + x^317 + x^315 + x^314 + x^313 + x^311 + x^305 + x^302 + x^298 + x^297 + x^296 + x^295 + x^292 + x^291 + x^288 + x^283 + x^280 + x^276 + x^275 + x^272 + x^268 + x^266 + x^262 + x^259 + x^258 + x^255 + x^251 + x^250 + x^242 + x^241 + x^240 + x^232 + x^227 + x^225 + x^224 + x^223 + x^216 + x^214 + x^212 + x^211 + x^210 + x^206 + x^203 + x^198 + x^189 + x^188 + x^177 + x^176 + x^175 + x^173 + x^168 + x^164 + x^162 + x^160 + x^159 + x^156 + x^155 + x^154 + x^152 + x^149 + x^147 + x^146 + x^145 + x^142 + x^139 + x^138 + x^137 + x^134 + x^132 + x^130 + x^124 + x^123 + x^122 + x^115 + x^113 + x^112 + x^111 + x^110 + x^108 + x^106 + x^103 + x^102 + x^98 + x^97 + x^96 + x^95 + x^94 + x^92 + x^91 + x^90 + x^88 + x^85 + x^80 + x^78 + x^77 + x^76 + x^73 + x^71 + x^70 + x^69 + x^68 + x^67 + x^65 + x^64 + x^63 + x^54 + x^53 + x^52 + x^51 + x^50 + x^49 + x^48 + x^47 + x^44 + x^43 + x^42 + x^40 + x^39 + x^31 + x^30 + x^29 + x^21 + x^13 + 1
+
+35-54-56 293 x^928 + x^898 + x^870 + x^862 + x^832 + x^826 + x^808 + x^796 + x^794 + x^790 + x^778 + x^765 + x^758 + x^754 + x^734 + x^729 + x^728 + x^722 + x^718 + x^715 + x^706 + x^700 + x^699 + x^698 + x^693 + x^686 + x^682 + x^676 + x^673 + x^672 + x^669 + x^668 + x^662 + x^658 + x^656 + x^655 + x^652 + x^650 + x^649 + x^646 + x^645 + x^642 + x^639 + x^638 + x^636 + x^630 + x^622 + x^614 + x^613 + x^612 + x^610 + x^608 + x^607 + x^600 + x^596 + x^595 + x^592 + x^590 + x^589 + x^587 + x^582 + x^574 + x^571 + x^568 + x^566 + x^560 + x^558 + x^554 + x^553 + x^552 + x^548 + x^544 + x^542 + x^538 + x^536 + x^534 + x^530 + x^528 + x^527 + x^524 + x^523 + x^522 + x^520 + x^518 + x^516 + x^515 + x^511 + x^506 + x^499 + x^497 + x^493 + x^492 + x^490 + x^487 + x^482 + x^478 + x^474 + x^467 + x^462 + x^461 + x^452 + x^445 + x^442 + x^439 + x^437 + x^436 + x^433 + x^428 + x^427 + x^422 + x^418 + x^413 + x^412 + x^410 + x^409 + x^407 + x^406 + x^403 + x^401 + x^398 + x^396 + x^392 + x^390 + x^386 + x^384 + x^383 + x^382 + x^380 + x^378 + x^377 + x^373 + x^372 + x^371 + x^366 + x^365 + x^362 + x^353 + x^352 + x^350 + x^348 + x^346 + x^344 + x^342 + x^340 + x^338 + x^336 + x^335 + x^334 + x^332 + x^331 + x^328 + x^326 + x^320 + x^318 + x^317 + x^316 + x^313 + x^312 + x^311 + x^310 + x^308 + x^304 + x^300 + x^299 + x^298 + x^296 + x^295 + x^293 + x^290 + x^288 + x^284 + x^282 + x^275 + x^271 + x^269 + x^268 + x^266 + x^265 + x^264 + x^263 + x^262 + x^260 + x^259 + x^253 + x^250 + x^247 + x^246 + x^244 + x^242 + x^240 + x^239 + x^238 + x^235 + x^233 + x^232 + x^228 + x^227 + x^226 + x^224 + x^221 + x^220 + x^218 + x^216 + x^214 + x^212 + x^208 + x^203 + x^199 + x^198 + x^196 + x^195 + x^194 + x^193 + x^192 + x^189 + x^187 + x^182 + x^178 + x^176 + x^175 + x^173 + x^168 + x^167 + x^166 + x^163 + x^161 + x^160 + x^156 + x^152 + x^150 + x^148 + x^146 + x^140 + x^138 + x^135 + x^133 + x^131 + x^130 + x^129 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^118 + x^116 + x^115 + x^113 + x^112 + x^109 + x^106 + x^105 + x^104 + x^103 + x^101 + x^100 + x^95 + x^94 + x^92 + x^84 + x^82 + x^80 + x^79 + x^77 + x^76 + x^74 + x^71 + x^69 + x^68 + x^66 + x^65 + x^64 + x^63 + x^55 + x^54 + x^53 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^38 + x^36 + x^34 + x^24 + x^18 + x^6 + 1
+
+44-42-5 307 x^928 + x^898 + x^880 + x^870 + x^856 + x^850 + x^839 + x^832 + x^826 + x^820 + x^816 + x^815 + x^808 + x^792 + x^791 + x^790 + x^784 + x^779 + x^778 + x^768 + x^762 + x^760 + x^756 + x^754 + x^753 + x^747 + x^744 + x^738 + x^737 + x^736 + x^731 + x^726 + x^723 + x^720 + x^719 + x^717 + x^713 + x^707 + x^696 + x^693 + x^689 + x^688 + x^682 + x^678 + x^677 + x^670 + x^666 + x^665 + x^663 + x^660 + x^658 + x^657 + x^653 + x^646 + x^633 + x^630 + x^628 + x^624 + x^617 + x^616 + x^612 + x^611 + x^606 + x^605 + x^604 + x^603 + x^600 + x^599 + x^597 + x^594 + x^592 + x^588 + x^587 + x^586 + x^582 + x^580 + x^576 + x^575 + x^568 + x^563 + x^556 + x^552 + x^546 + x^544 + x^542 + x^540 + x^539 + x^537 + x^534 + x^533 + x^526 + x^522 + x^521 + x^520 + x^518 + x^517 + x^516 + x^514 + x^511 + x^510 + x^508 + x^505 + x^503 + x^494 + x^492 + x^488 + x^485 + x^481 + x^475 + x^474 + x^470 + x^467 + x^464 + x^463 + x^462 + x^454 + x^452 + x^449 + x^447 + x^446 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^432 + x^431 + x^430 + x^427 + x^426 + x^424 + x^422 + x^419 + x^418 + x^413 + x^410 + x^409 + x^406 + x^404 + x^401 + x^398 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^385 + x^383 + x^380 + x^379 + x^376 + x^374 + x^372 + x^370 + x^368 + x^367 + x^366 + x^365 + x^364 + x^363 + x^361 + x^358 + x^355 + x^354 + x^353 + x^349 + x^348 + x^347 + x^344 + x^343 + x^342 + x^341 + x^338 + x^337 + x^336 + x^334 + x^332 + x^329 + x^328 + x^318 + x^317 + x^312 + x^310 + x^308 + x^307 + x^306 + x^305 + x^304 + x^299 + x^296 + x^294 + x^293 + x^291 + x^289 + x^281 + x^280 + x^278 + x^277 + x^276 + x^274 + x^272 + x^270 + x^267 + x^265 + x^264 + x^263 + x^260 + x^253 + x^252 + x^251 + x^250 + x^247 + x^242 + x^241 + x^239 + x^234 + x^233 + x^231 + x^230 + x^229 + x^224 + x^223 + x^222 + x^217 + x^214 + x^212 + x^210 + x^209 + x^208 + x^203 + x^200 + x^199 + x^198 + x^196 + x^195 + x^192 + x^191 + x^186 + x^185 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^172 + x^171 + x^170 + x^169 + x^168 + x^166 + x^165 + x^161 + x^160 + x^159 + x^151 + x^146 + x^144 + x^143 + x^142 + x^141 + x^139 + x^137 + x^136 + x^135 + x^133 + x^131 + x^130 + x^120 + x^116 + x^114 + x^113 + x^108 + x^107 + x^106 + x^104 + x^101 + x^98 + x^97 + x^96 + x^91 + x^90 + x^89 + x^87 + x^82 + x^80 + x^78 + x^73 + x^72 + x^67 + x^62 + x^58 + x^56 + x^55 + x^53 + x^49 + x^46 + x^44 + x^39 + x^32 + x^26 + x^17 + 1
+
+18-7-29 311 x^928 + x^926 + x^920 + x^918 + x^912 + x^910 + x^904 + x^902 + x^898 + x^896 + x^894 + x^890 + x^888 + x^886 + x^882 + x^880 + x^878 + x^874 + x^872 + x^870 + x^866 + x^858 + x^850 + x^842 + x^808 + x^806 + x^792 + x^790 + x^778 + x^776 + x^774 + x^762 + x^760 + x^758 + x^746 + x^730 + x^688 + x^686 + x^680 + x^678 + x^669 + x^667 + x^661 + x^659 + x^658 + x^656 + x^655 + x^654 + x^651 + x^650 + x^648 + x^647 + x^646 + x^643 + x^626 + x^618 + x^611 + x^605 + x^595 + x^589 + x^587 + x^575 + x^569 + x^568 + x^566 + x^561 + x^553 + x^541 + x^539 + x^538 + x^537 + x^536 + x^534 + x^533 + x^515 + x^511 + x^509 + x^507 + x^506 + x^503 + x^501 + x^497 + x^495 + x^493 + x^489 + x^485 + x^483 + x^481 + x^479 + x^475 + x^473 + x^471 + x^469 + x^457 + x^455 + x^453 + x^451 + x^449 + x^448 + x^447 + x^446 + x^443 + x^440 + x^439 + x^438 + x^437 + x^435 + x^433 + x^432 + x^431 + x^429 + x^426 + x^425 + x^424 + x^421 + x^418 + x^417 + x^416 + x^415 + x^414 + x^412 + x^409 + x^408 + x^406 + x^405 + x^404 + x^401 + x^398 + x^396 + x^395 + x^393 + x^392 + x^390 + x^388 + x^387 + x^380 + x^379 + x^377 + x^376 + x^372 + x^371 + x^370 + x^369 + x^367 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^354 + x^352 + x^350 + x^349 + x^348 + x^341 + x^340 + x^337 + x^336 + x^335 + x^331 + x^330 + x^328 + x^326 + x^320 + x^319 + x^318 + x^317 + x^315 + x^314 + x^313 + x^312 + x^310 + x^308 + x^307 + x^302 + x^301 + x^299 + x^297 + x^295 + x^293 + x^291 + x^287 + x^284 + x^283 + x^282 + x^281 + x^280 + x^279 + x^278 + x^274 + x^271 + x^267 + x^266 + x^264 + x^263 + x^257 + x^256 + x^255 + x^252 + x^251 + x^250 + x^246 + x^241 + x^240 + x^239 + x^234 + x^233 + x^231 + x^230 + x^229 + x^226 + x^225 + x^224 + x^223 + x^222 + x^218 + x^216 + x^214 + x^212 + x^211 + x^206 + x^203 + x^202 + x^199 + x^198 + x^197 + x^193 + x^191 + x^190 + x^188 + x^185 + x^183 + x^181 + x^180 + x^179 + x^176 + x^171 + x^169 + x^167 + x^158 + x^156 + x^155 + x^154 + x^153 + x^151 + x^150 + x^148 + x^145 + x^143 + x^142 + x^141 + x^138 + x^133 + x^132 + x^130 + x^127 + x^125 + x^123 + x^121 + x^118 + x^109 + x^108 + x^105 + x^104 + x^103 + x^102 + x^100 + x^97 + x^95 + x^94 + x^92 + x^90 + x^85 + x^84 + x^82 + x^80 + x^76 + x^74 + x^73 + x^71 + x^70 + x^68 + x^67 + x^66 + x^65 + x^64 + x^61 + x^59 + x^57 + x^55 + x^53 + x^52 + x^48 + x^47 + x^45 + x^41 + x^38 + x^36 + x^34 + x^31 + x^28 + x^26 + x^24 + x^22 + x^18 + x^16 + x^12 + x^10 + x^2 + 1
+
+48-55-49 313 x^928 + x^898 + x^894 + x^893 + x^870 + x^864 + x^860 + x^858 + x^838 + x^836 + x^832 + x^831 + x^830 + x^828 + x^804 + x^802 + x^796 + x^794 + x^778 + x^774 + x^773 + x^770 + x^769 + x^768 + x^741 + x^740 + x^737 + x^736 + x^734 + x^732 + x^731 + x^718 + x^712 + x^711 + x^706 + x^704 + x^702 + x^701 + x^684 + x^681 + x^679 + x^678 + x^676 + x^675 + x^672 + x^671 + x^669 + x^658 + x^656 + x^654 + x^653 + x^652 + x^651 + x^647 + x^646 + x^645 + x^621 + x^618 + x^617 + x^616 + x^615 + x^614 + x^611 + x^610 + x^609 + x^598 + x^596 + x^592 + x^590 + x^589 + x^583 + x^582 + x^580 + x^579 + x^576 + x^561 + x^559 + x^558 + x^557 + x^554 + x^548 + x^547 + x^545 + x^538 + x^534 + x^533 + x^531 + x^529 + x^527 + x^526 + x^524 + x^522 + x^521 + x^515 + x^512 + x^500 + x^497 + x^486 + x^484 + x^478 + x^474 + x^470 + x^469 + x^468 + x^467 + x^466 + x^465 + x^464 + x^462 + x^460 + x^458 + x^456 + x^454 + x^453 + x^450 + x^444 + x^438 + x^436 + x^435 + x^434 + x^433 + x^432 + x^429 + x^424 + x^422 + x^421 + x^418 + x^416 + x^413 + x^412 + x^407 + x^406 + x^405 + x^404 + x^402 + x^399 + x^398 + x^397 + x^396 + x^394 + x^392 + x^391 + x^388 + x^384 + x^380 + x^378 + x^377 + x^375 + x^373 + x^372 + x^371 + x^364 + x^359 + x^356 + x^354 + x^353 + x^352 + x^351 + x^350 + x^347 + x^343 + x^342 + x^340 + x^339 + x^334 + x^331 + x^328 + x^327 + x^325 + x^324 + x^322 + x^316 + x^312 + x^311 + x^310 + x^308 + x^306 + x^305 + x^304 + x^302 + x^301 + x^300 + x^298 + x^297 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^288 + x^282 + x^280 + x^279 + x^278 + x^277 + x^276 + x^275 + x^273 + x^271 + x^268 + x^264 + x^261 + x^258 + x^256 + x^254 + x^253 + x^251 + x^249 + x^248 + x^246 + x^245 + x^244 + x^242 + x^241 + x^240 + x^239 + x^237 + x^236 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^224 + x^223 + x^219 + x^216 + x^215 + x^211 + x^210 + x^207 + x^206 + x^204 + x^203 + x^199 + x^198 + x^194 + x^188 + x^187 + x^186 + x^182 + x^181 + x^180 + x^174 + x^171 + x^170 + x^168 + x^165 + x^164 + x^160 + x^152 + x^151 + x^150 + x^149 + x^148 + x^147 + x^144 + x^143 + x^142 + x^141 + x^139 + x^134 + x^129 + x^127 + x^124 + x^121 + x^119 + x^115 + x^108 + x^107 + x^105 + x^104 + x^103 + x^102 + x^95 + x^94 + x^90 + x^89 + x^88 + x^86 + x^84 + x^79 + x^77 + x^73 + x^72 + x^69 + x^66 + x^64 + x^63 + x^62 + x^60 + x^57 + x^56 + x^55 + x^54 + x^53 + x^52 + x^50 + x^49 + x^48 + x^46 + x^45 + x^41 + x^36 + x^34 + x^31 + x^29 + x^28 + x^26 + x^25 + 1
+
+40-44-57 319 x^928 + x^898 + x^870 + x^846 + x^822 + x^819 + x^808 + x^800 + x^794 + x^792 + x^786 + x^778 + x^770 + x^764 + x^759 + x^748 + x^746 + x^740 + x^732 + x^716 + x^713 + x^697 + x^696 + x^691 + x^686 + x^674 + x^664 + x^661 + x^658 + x^650 + x^648 + x^645 + x^644 + x^636 + x^629 + x^626 + x^624 + x^623 + x^621 + x^620 + x^618 + x^615 + x^594 + x^593 + x^591 + x^590 + x^586 + x^583 + x^580 + x^579 + x^577 + x^575 + x^574 + x^572 + x^571 + x^568 + x^564 + x^563 + x^561 + x^558 + x^556 + x^555 + x^553 + x^550 + x^547 + x^545 + x^544 + x^542 + x^541 + x^538 + x^536 + x^533 + x^528 + x^526 + x^525 + x^522 + x^519 + x^513 + x^512 + x^510 + x^509 + x^508 + x^507 + x^504 + x^503 + x^501 + x^495 + x^488 + x^487 + x^485 + x^484 + x^483 + x^482 + x^480 + x^479 + x^474 + x^473 + x^471 + x^470 + x^466 + x^463 + x^460 + x^458 + x^457 + x^454 + x^453 + x^450 + x^449 + x^446 + x^444 + x^443 + x^441 + x^440 + x^439 + x^436 + x^434 + x^433 + x^432 + x^431 + x^430 + x^427 + x^425 + x^424 + x^422 + x^420 + x^417 + x^416 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^398 + x^397 + x^395 + x^392 + x^390 + x^387 + x^386 + x^385 + x^383 + x^375 + x^370 + x^369 + x^368 + x^367 + x^365 + x^364 + x^363 + x^360 + x^359 + x^357 + x^356 + x^353 + x^351 + x^349 + x^342 + x^340 + x^339 + x^336 + x^335 + x^329 + x^327 + x^326 + x^324 + x^323 + x^320 + x^319 + x^318 + x^317 + x^316 + x^315 + x^312 + x^311 + x^307 + x^306 + x^302 + x^299 + x^298 + x^297 + x^295 + x^294 + x^293 + x^291 + x^290 + x^287 + x^285 + x^284 + x^283 + x^282 + x^281 + x^279 + x^277 + x^276 + x^275 + x^272 + x^271 + x^268 + x^266 + x^263 + x^262 + x^261 + x^255 + x^251 + x^249 + x^248 + x^245 + x^244 + x^243 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^230 + x^229 + x^228 + x^227 + x^226 + x^224 + x^221 + x^217 + x^214 + x^212 + x^209 + x^208 + x^204 + x^202 + x^201 + x^197 + x^194 + x^193 + x^192 + x^191 + x^189 + x^188 + x^185 + x^184 + x^182 + x^181 + x^178 + x^176 + x^173 + x^172 + x^171 + x^169 + x^166 + x^163 + x^161 + x^160 + x^158 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^148 + x^146 + x^145 + x^144 + x^142 + x^141 + x^134 + x^132 + x^129 + x^122 + x^121 + x^119 + x^117 + x^116 + x^113 + x^112 + x^110 + x^109 + x^103 + x^102 + x^101 + x^100 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^87 + x^86 + x^85 + x^84 + x^81 + x^80 + x^75 + x^74 + x^71 + x^70 + x^68 + x^66 + x^63 + x^52 + x^51 + x^50 + x^47 + x^45 + x^44 + x^43 + x^39 + x^38 + x^34 + x^24 + x^16 + x^8 + 1
+
+21-52-12 321 x^928 + x^898 + x^870 + x^868 + x^856 + x^838 + x^828 + x^826 + x^816 + x^815 + x^808 + x^804 + x^786 + x^784 + x^778 + x^748 + x^744 + x^736 + x^734 + x^733 + x^732 + x^731 + x^726 + x^722 + x^718 + x^710 + x^706 + x^704 + x^703 + x^694 + x^692 + x^691 + x^688 + x^683 + x^680 + x^679 + x^678 + x^674 + x^672 + x^668 + x^664 + x^660 + x^658 + x^656 + x^653 + x^649 + x^648 + x^644 + x^643 + x^638 + x^632 + x^630 + x^625 + x^623 + x^619 + x^618 + x^616 + x^615 + x^613 + x^610 + x^607 + x^606 + x^602 + x^601 + x^600 + x^595 + x^593 + x^589 + x^588 + x^586 + x^585 + x^580 + x^579 + x^578 + x^571 + x^570 + x^566 + x^565 + x^564 + x^563 + x^560 + x^559 + x^555 + x^554 + x^550 + x^548 + x^547 + x^546 + x^544 + x^543 + x^541 + x^539 + x^538 + x^537 + x^535 + x^531 + x^530 + x^529 + x^522 + x^520 + x^514 + x^513 + x^509 + x^507 + x^504 + x^501 + x^500 + x^499 + x^498 + x^496 + x^495 + x^494 + x^492 + x^491 + x^490 + x^486 + x^483 + x^480 + x^479 + x^476 + x^473 + x^469 + x^466 + x^463 + x^460 + x^459 + x^457 + x^451 + x^449 + x^443 + x^441 + x^440 + x^436 + x^433 + x^432 + x^431 + x^424 + x^420 + x^418 + x^416 + x^414 + x^411 + x^410 + x^409 + x^408 + x^406 + x^404 + x^403 + x^401 + x^400 + x^398 + x^393 + x^390 + x^388 + x^385 + x^384 + x^381 + x^375 + x^372 + x^366 + x^365 + x^361 + x^358 + x^356 + x^354 + x^352 + x^347 + x^346 + x^341 + x^340 + x^338 + x^335 + x^334 + x^333 + x^331 + x^330 + x^326 + x^323 + x^320 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^303 + x^301 + x^299 + x^297 + x^296 + x^295 + x^290 + x^289 + x^283 + x^282 + x^277 + x^276 + x^273 + x^268 + x^267 + x^266 + x^264 + x^262 + x^261 + x^260 + x^256 + x^254 + x^251 + x^250 + x^247 + x^245 + x^244 + x^243 + x^240 + x^238 + x^235 + x^234 + x^233 + x^231 + x^229 + x^225 + x^224 + x^217 + x^212 + x^211 + x^209 + x^208 + x^205 + x^204 + x^202 + x^200 + x^198 + x^196 + x^195 + x^191 + x^190 + x^188 + x^187 + x^186 + x^182 + x^181 + x^180 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^166 + x^164 + x^158 + x^154 + x^153 + x^152 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^141 + x^140 + x^138 + x^137 + x^136 + x^135 + x^133 + x^131 + x^127 + x^125 + x^123 + x^122 + x^121 + x^120 + x^119 + x^115 + x^113 + x^112 + x^111 + x^106 + x^102 + x^101 + x^100 + x^98 + x^96 + x^95 + x^93 + x^92 + x^91 + x^90 + x^89 + x^88 + x^87 + x^81 + x^79 + x^76 + x^72 + x^71 + x^70 + x^64 + x^60 + x^57 + x^56 + x^55 + x^54 + x^50 + x^49 + x^48 + x^47 + x^43 + x^39 + x^38 + x^30 + x^29 + x^26 + x^25 + x^14 + x^10 + 1
+
+25-44-4 331 x^928 + x^898 + x^870 + x^866 + x^862 + x^859 + x^836 + x^834 + x^829 + x^822 + x^808 + x^806 + x^804 + x^800 + x^799 + x^798 + x^797 + x^795 + x^778 + x^776 + x^770 + x^769 + x^767 + x^762 + x^753 + x^739 + x^735 + x^734 + x^731 + x^721 + x^713 + x^709 + x^708 + x^706 + x^705 + x^703 + x^701 + x^698 + x^688 + x^679 + x^677 + x^676 + x^674 + x^670 + x^669 + x^667 + x^666 + x^661 + x^659 + x^658 + x^649 + x^647 + x^645 + x^643 + x^642 + x^638 + x^635 + x^633 + x^629 + x^626 + x^624 + x^620 + x^618 + x^617 + x^614 + x^611 + x^605 + x^603 + x^598 + x^596 + x^594 + x^593 + x^590 + x^587 + x^581 + x^580 + x^579 + x^571 + x^570 + x^568 + x^566 + x^562 + x^558 + x^557 + x^551 + x^550 + x^548 + x^547 + x^546 + x^544 + x^542 + x^541 + x^539 + x^536 + x^533 + x^532 + x^530 + x^527 + x^526 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^507 + x^506 + x^504 + x^501 + x^497 + x^493 + x^492 + x^490 + x^488 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^473 + x^467 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^456 + x^454 + x^453 + x^452 + x^450 + x^448 + x^446 + x^444 + x^443 + x^442 + x^433 + x^426 + x^423 + x^422 + x^420 + x^419 + x^416 + x^413 + x^412 + x^411 + x^410 + x^406 + x^404 + x^403 + x^402 + x^401 + x^400 + x^398 + x^396 + x^395 + x^392 + x^391 + x^389 + x^387 + x^386 + x^385 + x^380 + x^372 + x^366 + x^365 + x^363 + x^362 + x^359 + x^357 + x^354 + x^353 + x^352 + x^348 + x^346 + x^345 + x^342 + x^340 + x^338 + x^335 + x^334 + x^333 + x^332 + x^325 + x^324 + x^323 + x^320 + x^319 + x^318 + x^314 + x^312 + x^309 + x^308 + x^303 + x^302 + x^301 + x^299 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^286 + x^284 + x^279 + x^278 + x^274 + x^273 + x^268 + x^266 + x^265 + x^263 + x^261 + x^257 + x^256 + x^255 + x^254 + x^253 + x^248 + x^245 + x^244 + x^241 + x^240 + x^237 + x^235 + x^234 + x^233 + x^232 + x^230 + x^229 + x^228 + x^226 + x^223 + x^222 + x^220 + x^218 + x^214 + x^212 + x^211 + x^209 + x^207 + x^206 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^196 + x^191 + x^189 + x^184 + x^178 + x^177 + x^176 + x^175 + x^172 + x^171 + x^169 + x^166 + x^165 + x^162 + x^161 + x^159 + x^157 + x^156 + x^155 + x^150 + x^149 + x^148 + x^147 + x^143 + x^142 + x^141 + x^140 + x^137 + x^136 + x^135 + x^133 + x^131 + x^130 + x^129 + x^127 + x^126 + x^125 + x^124 + x^123 + x^120 + x^113 + x^112 + x^108 + x^105 + x^104 + x^98 + x^96 + x^92 + x^90 + x^82 + x^81 + x^80 + x^78 + x^76 + x^74 + x^73 + x^68 + x^66 + x^64 + x^62 + x^60 + x^58 + x^54 + x^42 + x^38 + x^36 + x^32 + x^26 + x^18 + x^16 + x^10 + x^8 + x^2 + 1
+
+16-8-37 341 x^928 + x^898 + x^870 + x^842 + x^814 + x^808 + x^788 + x^786 + x^784 + x^778 + x^777 + x^775 + x^773 + x^762 + x^756 + x^751 + x^745 + x^736 + x^723 + x^721 + x^717 + x^715 + x^713 + x^710 + x^700 + x^697 + x^693 + x^691 + x^688 + x^685 + x^678 + x^674 + x^673 + x^672 + x^667 + x^654 + x^650 + x^647 + x^645 + x^644 + x^643 + x^642 + x^641 + x^635 + x^634 + x^632 + x^631 + x^630 + x^622 + x^621 + x^618 + x^615 + x^614 + x^612 + x^608 + x^605 + x^604 + x^603 + x^601 + x^596 + x^595 + x^592 + x^590 + x^589 + x^588 + x^587 + x^586 + x^585 + x^584 + x^583 + x^581 + x^579 + x^578 + x^576 + x^575 + x^573 + x^571 + x^569 + x^565 + x^564 + x^561 + x^560 + x^557 + x^556 + x^555 + x^554 + x^552 + x^544 + x^543 + x^540 + x^535 + x^533 + x^530 + x^528 + x^527 + x^524 + x^522 + x^520 + x^519 + x^517 + x^516 + x^515 + x^514 + x^513 + x^510 + x^509 + x^508 + x^507 + x^503 + x^502 + x^500 + x^497 + x^496 + x^493 + x^491 + x^490 + x^486 + x^480 + x^477 + x^476 + x^475 + x^474 + x^473 + x^472 + x^471 + x^467 + x^464 + x^463 + x^461 + x^458 + x^457 + x^453 + x^446 + x^444 + x^441 + x^439 + x^436 + x^434 + x^433 + x^432 + x^430 + x^427 + x^426 + x^422 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^410 + x^405 + x^404 + x^401 + x^399 + x^396 + x^395 + x^392 + x^391 + x^390 + x^388 + x^387 + x^386 + x^385 + x^384 + x^383 + x^378 + x^377 + x^375 + x^373 + x^372 + x^371 + x^366 + x^364 + x^358 + x^357 + x^356 + x^352 + x^348 + x^345 + x^342 + x^340 + x^339 + x^338 + x^336 + x^335 + x^331 + x^330 + x^329 + x^327 + x^324 + x^323 + x^322 + x^321 + x^320 + x^317 + x^316 + x^315 + x^314 + x^310 + x^307 + x^306 + x^303 + x^297 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^286 + x^284 + x^283 + x^282 + x^278 + x^276 + x^275 + x^274 + x^269 + x^268 + x^267 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^256 + x^251 + x^249 + x^248 + x^247 + x^245 + x^242 + x^241 + x^239 + x^238 + x^236 + x^235 + x^234 + x^233 + x^232 + x^230 + x^229 + x^225 + x^224 + x^223 + x^222 + x^220 + x^218 + x^216 + x^214 + x^213 + x^212 + x^211 + x^209 + x^206 + x^201 + x^200 + x^199 + x^197 + x^196 + x^194 + x^193 + x^190 + x^186 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^169 + x^168 + x^166 + x^164 + x^160 + x^158 + x^157 + x^156 + x^153 + x^152 + x^147 + x^146 + x^136 + x^134 + x^132 + x^129 + x^126 + x^125 + x^124 + x^123 + x^122 + x^120 + x^119 + x^116 + x^114 + x^112 + x^108 + x^107 + x^106 + x^104 + x^102 + x^98 + x^95 + x^91 + x^85 + x^84 + x^82 + x^81 + x^80 + x^79 + x^77 + x^76 + x^73 + x^72 + x^70 + x^62 + x^60 + x^59 + x^58 + x^56 + x^55 + x^53 + x^49 + x^44 + x^42 + x^41 + x^39 + x^38 + x^35 + x^34 + x^32 + x^28 + x^26 + x^24 + x^22 + 1
+
+17-12-36 341 x^928 + x^898 + x^870 + x^868 + x^860 + x^848 + x^838 + x^830 + x^829 + x^806 + x^798 + x^797 + x^789 + x^788 + x^772 + x^770 + x^767 + x^762 + x^761 + x^756 + x^751 + x^749 + x^748 + x^746 + x^742 + x^740 + x^738 + x^730 + x^726 + x^721 + x^718 + x^716 + x^714 + x^710 + x^709 + x^707 + x^706 + x^705 + x^696 + x^688 + x^684 + x^681 + x^677 + x^676 + x^674 + x^669 + x^666 + x^664 + x^659 + x^658 + x^657 + x^656 + x^655 + x^654 + x^651 + x^650 + x^647 + x^645 + x^639 + x^637 + x^636 + x^634 + x^631 + x^627 + x^625 + x^624 + x^622 + x^621 + x^619 + x^615 + x^614 + x^608 + x^605 + x^601 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^588 + x^587 + x^586 + x^585 + x^583 + x^582 + x^580 + x^578 + x^577 + x^576 + x^575 + x^574 + x^573 + x^572 + x^569 + x^568 + x^567 + x^565 + x^564 + x^561 + x^560 + x^559 + x^558 + x^557 + x^554 + x^553 + x^546 + x^545 + x^543 + x^542 + x^541 + x^539 + x^538 + x^536 + x^533 + x^530 + x^529 + x^527 + x^526 + x^525 + x^521 + x^520 + x^513 + x^509 + x^508 + x^504 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^488 + x^486 + x^484 + x^480 + x^479 + x^478 + x^475 + x^471 + x^469 + x^466 + x^463 + x^458 + x^456 + x^455 + x^452 + x^450 + x^449 + x^445 + x^437 + x^436 + x^433 + x^432 + x^430 + x^428 + x^426 + x^425 + x^423 + x^417 + x^416 + x^415 + x^413 + x^401 + x^400 + x^395 + x^394 + x^392 + x^391 + x^387 + x^386 + x^385 + x^384 + x^383 + x^379 + x^375 + x^373 + x^372 + x^371 + x^368 + x^366 + x^361 + x^360 + x^359 + x^358 + x^357 + x^354 + x^352 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^343 + x^340 + x^334 + x^332 + x^330 + x^328 + x^327 + x^325 + x^323 + x^321 + x^318 + x^317 + x^316 + x^315 + x^314 + x^311 + x^310 + x^309 + x^308 + x^307 + x^306 + x^304 + x^299 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^288 + x^287 + x^286 + x^282 + x^281 + x^280 + x^272 + x^271 + x^268 + x^267 + x^262 + x^256 + x^253 + x^252 + x^250 + x^244 + x^242 + x^241 + x^240 + x^238 + x^234 + x^233 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^212 + x^211 + x^208 + x^206 + x^203 + x^201 + x^199 + x^198 + x^195 + x^194 + x^193 + x^192 + x^189 + x^185 + x^182 + x^180 + x^179 + x^177 + x^176 + x^173 + x^172 + x^170 + x^164 + x^163 + x^160 + x^157 + x^155 + x^153 + x^152 + x^150 + x^147 + x^146 + x^139 + x^137 + x^132 + x^131 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^115 + x^113 + x^111 + x^109 + x^107 + x^106 + x^104 + x^103 + x^101 + x^100 + x^99 + x^98 + x^97 + x^94 + x^88 + x^85 + x^78 + x^77 + x^76 + x^71 + x^68 + x^66 + x^64 + x^51 + x^47 + x^45 + x^39 + x^38 + x^36 + x^31 + x^30 + x^26 + x^24 + x^22 + x^20 + x^15 + 1
+
+2-30-27 343 x^928 + x^898 + x^881 + x^870 + x^868 + x^866 + x^851 + x^838 + x^819 + x^817 + x^808 + x^806 + x^804 + x^778 + x^776 + x^774 + x^772 + x^761 + x^759 + x^755 + x^753 + x^748 + x^742 + x^740 + x^731 + x^725 + x^718 + x^716 + x^712 + x^710 + x^706 + x^695 + x^693 + x^691 + x^689 + x^688 + x^682 + x^678 + x^674 + x^665 + x^663 + x^661 + x^658 + x^657 + x^652 + x^646 + x^644 + x^642 + x^641 + x^637 + x^629 + x^628 + x^627 + x^626 + x^625 + x^618 + x^616 + x^614 + x^612 + x^611 + x^610 + x^607 + x^601 + x^598 + x^597 + x^593 + x^592 + x^588 + x^580 + x^579 + x^577 + x^575 + x^573 + x^571 + x^569 + x^568 + x^566 + x^564 + x^563 + x^562 + x^561 + x^560 + x^554 + x^552 + x^550 + x^548 + x^543 + x^539 + x^538 + x^536 + x^534 + x^531 + x^530 + x^529 + x^528 + x^524 + x^521 + x^519 + x^517 + x^515 + x^513 + x^509 + x^508 + x^507 + x^505 + x^502 + x^500 + x^499 + x^498 + x^497 + x^492 + x^491 + x^487 + x^486 + x^484 + x^479 + x^478 + x^477 + x^476 + x^473 + x^470 + x^468 + x^466 + x^465 + x^464 + x^458 + x^454 + x^450 + x^448 + x^447 + x^446 + x^445 + x^439 + x^436 + x^435 + x^434 + x^433 + x^432 + x^428 + x^426 + x^422 + x^420 + x^416 + x^415 + x^413 + x^411 + x^409 + x^407 + x^406 + x^404 + x^399 + x^396 + x^392 + x^389 + x^384 + x^383 + x^382 + x^381 + x^379 + x^377 + x^376 + x^374 + x^372 + x^370 + x^367 + x^359 + x^355 + x^352 + x^347 + x^346 + x^344 + x^342 + x^341 + x^339 + x^338 + x^336 + x^335 + x^334 + x^328 + x^327 + x^324 + x^320 + x^318 + x^316 + x^314 + x^313 + x^309 + x^308 + x^304 + x^303 + x^300 + x^298 + x^297 + x^296 + x^294 + x^292 + x^287 + x^286 + x^284 + x^283 + x^282 + x^278 + x^276 + x^272 + x^269 + x^266 + x^265 + x^264 + x^261 + x^256 + x^252 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^242 + x^239 + x^238 + x^237 + x^236 + x^235 + x^234 + x^233 + x^231 + x^229 + x^226 + x^225 + x^224 + x^220 + x^219 + x^216 + x^213 + x^212 + x^210 + x^205 + x^204 + x^203 + x^201 + x^199 + x^197 + x^194 + x^192 + x^191 + x^190 + x^189 + x^188 + x^186 + x^184 + x^183 + x^182 + x^178 + x^177 + x^176 + x^175 + x^173 + x^171 + x^170 + x^169 + x^166 + x^165 + x^163 + x^162 + x^161 + x^157 + x^156 + x^155 + x^153 + x^152 + x^150 + x^148 + x^147 + x^146 + x^144 + x^143 + x^141 + x^139 + x^137 + x^134 + x^133 + x^129 + x^128 + x^127 + x^126 + x^125 + x^123 + x^119 + x^117 + x^116 + x^115 + x^114 + x^113 + x^111 + x^110 + x^102 + x^101 + x^100 + x^99 + x^97 + x^96 + x^94 + x^93 + x^89 + x^88 + x^84 + x^83 + x^81 + x^78 + x^74 + x^72 + x^71 + x^69 + x^67 + x^62 + x^61 + x^59 + x^57 + x^56 + x^55 + x^53 + x^51 + x^47 + x^44 + x^42 + x^39 + x^37 + x^36 + x^35 + x^33 + x^30 + x^26 + x^24 + x^23 + x^21 + x^19 + x^18 + x^17 + x^16 + x^10 + x^8 + x^2 + 1
+
+26-55-39 345 x^928 + x^904 + x^898 + x^870 + x^861 + x^856 + x^851 + x^850 + x^831 + x^821 + x^820 + x^818 + x^813 + x^802 + x^796 + x^794 + x^790 + x^788 + x^783 + x^778 + x^775 + x^772 + x^770 + x^765 + x^760 + x^754 + x^746 + x^745 + x^741 + x^740 + x^736 + x^735 + x^734 + x^732 + x^731 + x^729 + x^727 + x^723 + x^722 + x^721 + x^716 + x^715 + x^710 + x^708 + x^705 + x^701 + x^699 + x^686 + x^685 + x^684 + x^681 + x^679 + x^678 + x^676 + x^674 + x^673 + x^672 + x^668 + x^664 + x^663 + x^661 + x^660 + x^658 + x^656 + x^650 + x^648 + x^645 + x^643 + x^641 + x^638 + x^637 + x^636 + x^632 + x^622 + x^621 + x^618 + x^616 + x^615 + x^614 + x^612 + x^608 + x^603 + x^600 + x^598 + x^595 + x^594 + x^593 + x^591 + x^590 + x^589 + x^588 + x^585 + x^582 + x^581 + x^576 + x^574 + x^571 + x^569 + x^568 + x^564 + x^562 + x^557 + x^556 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^543 + x^538 + x^535 + x^530 + x^525 + x^520 + x^517 + x^515 + x^514 + x^510 + x^509 + x^506 + x^501 + x^497 + x^495 + x^489 + x^486 + x^484 + x^483 + x^482 + x^480 + x^479 + x^476 + x^474 + x^473 + x^471 + x^470 + x^469 + x^467 + x^464 + x^462 + x^460 + x^453 + x^452 + x^450 + x^449 + x^448 + x^446 + x^444 + x^443 + x^441 + x^436 + x^435 + x^434 + x^433 + x^432 + x^429 + x^428 + x^427 + x^424 + x^419 + x^418 + x^417 + x^416 + x^413 + x^412 + x^410 + x^407 + x^404 + x^403 + x^401 + x^399 + x^398 + x^397 + x^396 + x^394 + x^393 + x^392 + x^390 + x^386 + x^385 + x^383 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^372 + x^366 + x^362 + x^359 + x^357 + x^355 + x^354 + x^351 + x^350 + x^347 + x^346 + x^344 + x^340 + x^339 + x^338 + x^337 + x^333 + x^332 + x^331 + x^330 + x^328 + x^326 + x^325 + x^323 + x^319 + x^315 + x^314 + x^313 + x^311 + x^310 + x^308 + x^307 + x^306 + x^304 + x^301 + x^300 + x^298 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^286 + x^283 + x^280 + x^277 + x^274 + x^272 + x^265 + x^264 + x^263 + x^261 + x^260 + x^258 + x^255 + x^252 + x^251 + x^250 + x^249 + x^247 + x^245 + x^244 + x^241 + x^238 + x^235 + x^234 + x^230 + x^228 + x^225 + x^221 + x^218 + x^212 + x^211 + x^210 + x^208 + x^206 + x^204 + x^203 + x^202 + x^199 + x^198 + x^196 + x^195 + x^193 + x^188 + x^186 + x^184 + x^183 + x^177 + x^176 + x^167 + x^166 + x^165 + x^163 + x^161 + x^160 + x^158 + x^156 + x^153 + x^151 + x^146 + x^144 + x^141 + x^140 + x^134 + x^133 + x^129 + x^128 + x^127 + x^124 + x^123 + x^121 + x^119 + x^117 + x^115 + x^114 + x^113 + x^112 + x^111 + x^110 + x^109 + x^105 + x^104 + x^103 + x^100 + x^99 + x^93 + x^92 + x^91 + x^86 + x^84 + x^81 + x^80 + x^77 + x^75 + x^72 + x^71 + x^70 + x^68 + x^66 + x^65 + x^64 + x^61 + x^54 + x^53 + x^47 + x^45 + x^36 + x^35 + x^34 + x^32 + x^29 + x^18 + x^7 + 1
+
+40-36-23 345 x^928 + x^898 + x^886 + x^870 + x^862 + x^844 + x^838 + x^826 + x^820 + x^816 + x^814 + x^808 + x^797 + x^792 + x^791 + x^790 + x^784 + x^778 + x^777 + x^772 + x^768 + x^767 + x^766 + x^762 + x^761 + x^756 + x^753 + x^749 + x^747 + x^744 + x^742 + x^738 + x^735 + x^734 + x^726 + x^724 + x^723 + x^720 + x^712 + x^702 + x^701 + x^695 + x^689 + x^684 + x^683 + x^681 + x^677 + x^675 + x^670 + x^669 + x^664 + x^663 + x^660 + x^659 + x^658 + x^653 + x^648 + x^646 + x^644 + x^634 + x^629 + x^628 + x^627 + x^626 + x^625 + x^622 + x^621 + x^617 + x^616 + x^611 + x^609 + x^605 + x^604 + x^603 + x^602 + x^597 + x^595 + x^594 + x^593 + x^592 + x^586 + x^585 + x^584 + x^578 + x^575 + x^574 + x^573 + x^572 + x^571 + x^569 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^554 + x^547 + x^545 + x^543 + x^539 + x^537 + x^536 + x^535 + x^534 + x^529 + x^528 + x^527 + x^525 + x^524 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^512 + x^510 + x^509 + x^508 + x^507 + x^506 + x^504 + x^503 + x^501 + x^499 + x^496 + x^494 + x^490 + x^489 + x^487 + x^485 + x^484 + x^482 + x^481 + x^480 + x^479 + x^478 + x^477 + x^475 + x^473 + x^470 + x^466 + x^465 + x^464 + x^463 + x^460 + x^457 + x^456 + x^454 + x^453 + x^452 + x^447 + x^446 + x^442 + x^441 + x^439 + x^436 + x^434 + x^432 + x^430 + x^428 + x^427 + x^423 + x^421 + x^416 + x^415 + x^414 + x^413 + x^411 + x^408 + x^405 + x^402 + x^401 + x^399 + x^396 + x^394 + x^393 + x^391 + x^390 + x^389 + x^388 + x^387 + x^386 + x^384 + x^381 + x^379 + x^378 + x^377 + x^375 + x^374 + x^372 + x^369 + x^367 + x^366 + x^364 + x^363 + x^361 + x^360 + x^359 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^349 + x^345 + x^343 + x^342 + x^338 + x^336 + x^335 + x^334 + x^333 + x^331 + x^329 + x^328 + x^327 + x^320 + x^318 + x^317 + x^316 + x^312 + x^307 + x^304 + x^303 + x^300 + x^298 + x^296 + x^295 + x^294 + x^293 + x^291 + x^290 + x^288 + x^287 + x^286 + x^285 + x^284 + x^276 + x^275 + x^274 + x^273 + x^272 + x^271 + x^269 + x^268 + x^266 + x^263 + x^262 + x^259 + x^257 + x^255 + x^254 + x^251 + x^248 + x^246 + x^244 + x^240 + x^238 + x^237 + x^235 + x^234 + x^232 + x^228 + x^226 + x^225 + x^224 + x^222 + x^220 + x^217 + x^213 + x^212 + x^211 + x^209 + x^208 + x^207 + x^202 + x^200 + x^199 + x^198 + x^192 + x^190 + x^187 + x^183 + x^182 + x^180 + x^175 + x^172 + x^171 + x^170 + x^169 + x^167 + x^166 + x^165 + x^164 + x^163 + x^160 + x^157 + x^154 + x^153 + x^152 + x^150 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^140 + x^137 + x^136 + x^134 + x^132 + x^129 + x^128 + x^124 + x^119 + x^117 + x^116 + x^115 + x^110 + x^108 + x^106 + x^103 + x^98 + x^88 + x^82 + x^76 + x^75 + x^74 + x^69 + x^68 + x^64 + x^62 + x^51 + x^47 + x^46 + x^39 + x^32 + x^23 + x^22 + 1
+
+24-36-37 347 x^928 + x^898 + x^878 + x^870 + x^854 + x^830 + x^824 + x^821 + x^818 + x^816 + x^813 + x^808 + x^806 + x^800 + x^792 + x^791 + x^789 + x^783 + x^780 + x^778 + x^776 + x^768 + x^765 + x^759 + x^753 + x^750 + x^747 + x^745 + x^744 + x^741 + x^740 + x^736 + x^734 + x^729 + x^721 + x^717 + x^715 + x^714 + x^708 + x^705 + x^704 + x^702 + x^699 + x^694 + x^690 + x^688 + x^684 + x^682 + x^681 + x^680 + x^679 + x^670 + x^669 + x^666 + x^664 + x^663 + x^660 + x^652 + x^649 + x^646 + x^645 + x^643 + x^639 + x^636 + x^634 + x^633 + x^631 + x^629 + x^627 + x^622 + x^621 + x^620 + x^614 + x^613 + x^612 + x^611 + x^610 + x^609 + x^605 + x^603 + x^601 + x^600 + x^599 + x^596 + x^593 + x^590 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^581 + x^579 + x^577 + x^573 + x^565 + x^564 + x^563 + x^562 + x^561 + x^560 + x^559 + x^558 + x^557 + x^554 + x^550 + x^549 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^538 + x^536 + x^535 + x^534 + x^529 + x^527 + x^525 + x^524 + x^523 + x^521 + x^519 + x^518 + x^516 + x^515 + x^512 + x^510 + x^505 + x^504 + x^503 + x^501 + x^500 + x^499 + x^493 + x^492 + x^488 + x^484 + x^483 + x^479 + x^474 + x^472 + x^470 + x^465 + x^464 + x^459 + x^457 + x^455 + x^454 + x^450 + x^440 + x^435 + x^434 + x^433 + x^427 + x^426 + x^424 + x^421 + x^420 + x^419 + x^414 + x^413 + x^412 + x^409 + x^407 + x^406 + x^405 + x^403 + x^401 + x^400 + x^399 + x^398 + x^395 + x^393 + x^391 + x^390 + x^388 + x^383 + x^381 + x^376 + x^374 + x^370 + x^367 + x^365 + x^363 + x^359 + x^356 + x^355 + x^353 + x^352 + x^348 + x^347 + x^346 + x^345 + x^344 + x^343 + x^342 + x^339 + x^336 + x^330 + x^327 + x^326 + x^325 + x^324 + x^323 + x^321 + x^318 + x^316 + x^315 + x^314 + x^312 + x^311 + x^310 + x^302 + x^300 + x^298 + x^295 + x^294 + x^292 + x^284 + x^282 + x^279 + x^278 + x^277 + x^276 + x^271 + x^268 + x^267 + x^266 + x^265 + x^264 + x^262 + x^260 + x^256 + x^253 + x^250 + x^249 + x^248 + x^244 + x^243 + x^242 + x^239 + x^236 + x^235 + x^232 + x^231 + x^229 + x^227 + x^226 + x^222 + x^220 + x^219 + x^216 + x^215 + x^214 + x^213 + x^211 + x^209 + x^208 + x^204 + x^202 + x^200 + x^199 + x^198 + x^196 + x^193 + x^191 + x^190 + x^189 + x^188 + x^187 + x^186 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^170 + x^169 + x^167 + x^163 + x^162 + x^161 + x^160 + x^153 + x^150 + x^149 + x^147 + x^145 + x^140 + x^138 + x^136 + x^135 + x^133 + x^131 + x^130 + x^128 + x^127 + x^119 + x^117 + x^113 + x^111 + x^110 + x^108 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^97 + x^96 + x^93 + x^88 + x^87 + x^86 + x^85 + x^84 + x^83 + x^82 + x^80 + x^78 + x^77 + x^72 + x^71 + x^70 + x^67 + x^66 + x^64 + x^63 + x^62 + x^61 + x^59 + x^58 + x^56 + x^54 + x^53 + x^50 + x^47 + x^46 + x^38 + x^24 + x^16 + 1
+
+26-38-9 353 x^928 + x^898 + x^875 + x^870 + x^848 + x^822 + x^808 + x^806 + x^800 + x^798 + x^797 + x^795 + x^792 + x^788 + x^778 + x^776 + x^769 + x^767 + x^765 + x^762 + x^758 + x^756 + x^747 + x^741 + x^732 + x^730 + x^728 + x^727 + x^723 + x^719 + x^714 + x^712 + x^711 + x^709 + x^706 + x^703 + x^700 + x^697 + x^695 + x^689 + x^688 + x^686 + x^684 + x^682 + x^680 + x^678 + x^676 + x^674 + x^673 + x^667 + x^666 + x^664 + x^661 + x^658 + x^653 + x^652 + x^649 + x^648 + x^646 + x^645 + x^635 + x^634 + x^633 + x^629 + x^626 + x^625 + x^620 + x^616 + x^614 + x^612 + x^611 + x^610 + x^607 + x^606 + x^604 + x^603 + x^599 + x^595 + x^594 + x^591 + x^583 + x^580 + x^578 + x^577 + x^572 + x^569 + x^568 + x^567 + x^566 + x^564 + x^559 + x^558 + x^555 + x^554 + x^550 + x^549 + x^548 + x^543 + x^542 + x^541 + x^539 + x^533 + x^532 + x^531 + x^528 + x^527 + x^526 + x^523 + x^519 + x^518 + x^515 + x^514 + x^513 + x^512 + x^511 + x^510 + x^509 + x^508 + x^507 + x^506 + x^502 + x^497 + x^495 + x^491 + x^488 + x^487 + x^485 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^473 + x^469 + x^466 + x^463 + x^462 + x^460 + x^458 + x^457 + x^456 + x^451 + x^447 + x^444 + x^443 + x^442 + x^440 + x^438 + x^437 + x^435 + x^433 + x^432 + x^430 + x^427 + x^424 + x^418 + x^417 + x^416 + x^414 + x^410 + x^409 + x^403 + x^401 + x^398 + x^397 + x^396 + x^394 + x^393 + x^391 + x^389 + x^388 + x^386 + x^385 + x^384 + x^382 + x^381 + x^380 + x^375 + x^374 + x^368 + x^364 + x^363 + x^359 + x^358 + x^357 + x^356 + x^354 + x^350 + x^349 + x^347 + x^346 + x^339 + x^337 + x^336 + x^334 + x^332 + x^330 + x^329 + x^328 + x^327 + x^326 + x^325 + x^324 + x^320 + x^318 + x^317 + x^315 + x^313 + x^309 + x^307 + x^305 + x^304 + x^303 + x^300 + x^299 + x^295 + x^293 + x^290 + x^288 + x^286 + x^285 + x^281 + x^279 + x^277 + x^274 + x^273 + x^269 + x^267 + x^266 + x^265 + x^263 + x^262 + x^257 + x^256 + x^255 + x^251 + x^249 + x^247 + x^246 + x^243 + x^241 + x^237 + x^236 + x^233 + x^230 + x^228 + x^227 + x^226 + x^225 + x^224 + x^223 + x^222 + x^221 + x^220 + x^212 + x^211 + x^210 + x^209 + x^208 + x^205 + x^204 + x^202 + x^201 + x^200 + x^197 + x^192 + x^191 + x^186 + x^184 + x^183 + x^181 + x^177 + x^175 + x^174 + x^170 + x^167 + x^165 + x^164 + x^162 + x^156 + x^154 + x^149 + x^148 + x^147 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^133 + x^131 + x^130 + x^128 + x^127 + x^126 + x^120 + x^116 + x^115 + x^113 + x^111 + x^108 + x^107 + x^105 + x^101 + x^99 + x^97 + x^95 + x^91 + x^90 + x^88 + x^87 + x^85 + x^81 + x^79 + x^78 + x^75 + x^72 + x^71 + x^70 + x^69 + x^66 + x^65 + x^63 + x^59 + x^57 + x^55 + x^54 + x^52 + x^51 + x^50 + x^49 + x^46 + x^44 + x^43 + x^39 + x^36 + x^34 + x^33 + x^32 + x^31 + x^30 + x^26 + x^24 + x^22 + x^16 + x^14 + x^8 + x^6 + 1
+
+31-6-30 353 x^928 + x^898 + x^870 + x^834 + x^814 + x^796 + x^790 + x^788 + x^784 + x^774 + x^772 + x^770 + x^762 + x^760 + x^756 + x^748 + x^740 + x^734 + x^732 + x^728 + x^727 + x^726 + x^718 + x^716 + x^712 + x^707 + x^701 + x^700 + x^697 + x^692 + x^688 + x^686 + x^684 + x^682 + x^681 + x^678 + x^677 + x^676 + x^674 + x^671 + x^670 + x^668 + x^665 + x^660 + x^658 + x^655 + x^652 + x^651 + x^650 + x^649 + x^646 + x^642 + x^641 + x^639 + x^638 + x^637 + x^636 + x^635 + x^630 + x^625 + x^624 + x^623 + x^622 + x^621 + x^620 + x^619 + x^617 + x^612 + x^611 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^601 + x^598 + x^597 + x^593 + x^592 + x^591 + x^590 + x^582 + x^579 + x^578 + x^572 + x^570 + x^567 + x^566 + x^565 + x^563 + x^561 + x^559 + x^558 + x^555 + x^554 + x^544 + x^543 + x^542 + x^540 + x^539 + x^536 + x^533 + x^529 + x^528 + x^525 + x^522 + x^517 + x^516 + x^512 + x^511 + x^510 + x^507 + x^505 + x^502 + x^501 + x^499 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^481 + x^480 + x^476 + x^473 + x^469 + x^468 + x^466 + x^465 + x^464 + x^457 + x^451 + x^449 + x^448 + x^445 + x^444 + x^441 + x^440 + x^438 + x^436 + x^435 + x^433 + x^432 + x^431 + x^428 + x^425 + x^422 + x^420 + x^418 + x^414 + x^413 + x^412 + x^411 + x^410 + x^406 + x^405 + x^402 + x^401 + x^400 + x^394 + x^390 + x^389 + x^387 + x^384 + x^382 + x^380 + x^376 + x^375 + x^372 + x^371 + x^370 + x^369 + x^366 + x^363 + x^362 + x^361 + x^359 + x^357 + x^356 + x^354 + x^352 + x^351 + x^349 + x^347 + x^346 + x^344 + x^343 + x^342 + x^341 + x^340 + x^338 + x^337 + x^336 + x^334 + x^333 + x^331 + x^328 + x^323 + x^322 + x^318 + x^315 + x^313 + x^312 + x^310 + x^309 + x^308 + x^307 + x^301 + x^300 + x^298 + x^296 + x^295 + x^294 + x^292 + x^287 + x^285 + x^284 + x^283 + x^282 + x^279 + x^276 + x^275 + x^272 + x^270 + x^269 + x^268 + x^267 + x^263 + x^261 + x^259 + x^258 + x^256 + x^250 + x^248 + x^247 + x^246 + x^245 + x^244 + x^240 + x^239 + x^238 + x^237 + x^236 + x^235 + x^232 + x^231 + x^230 + x^229 + x^226 + x^223 + x^220 + x^217 + x^216 + x^213 + x^212 + x^210 + x^208 + x^205 + x^204 + x^201 + x^195 + x^194 + x^192 + x^191 + x^189 + x^188 + x^182 + x^181 + x^177 + x^175 + x^174 + x^173 + x^171 + x^169 + x^167 + x^162 + x^161 + x^159 + x^158 + x^154 + x^153 + x^148 + x^146 + x^145 + x^144 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^135 + x^134 + x^133 + x^122 + x^119 + x^118 + x^115 + x^111 + x^110 + x^108 + x^107 + x^106 + x^105 + x^101 + x^99 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^90 + x^87 + x^84 + x^83 + x^80 + x^74 + x^73 + x^71 + x^70 + x^67 + x^66 + x^63 + x^55 + x^53 + x^52 + x^51 + x^49 + x^45 + x^44 + x^43 + x^40 + x^35 + x^34 + x^33 + x^32 + x^27 + x^25 + x^24 + x^22 + x^21 + x^20 + x^17 + x^16 + x^11 + x^4 + 1
+
+54-21-7 353 x^928 + x^898 + x^870 + x^861 + x^860 + x^859 + x^858 + x^846 + x^842 + x^837 + x^836 + x^835 + x^831 + x^830 + x^829 + x^828 + x^822 + x^818 + x^811 + x^810 + x^808 + x^807 + x^804 + x^798 + x^792 + x^788 + x^781 + x^778 + x^758 + x^756 + x^751 + x^750 + x^746 + x^745 + x^740 + x^739 + x^738 + x^722 + x^720 + x^716 + x^703 + x^701 + x^696 + x^695 + x^688 + x^686 + x^674 + x^666 + x^659 + x^658 + x^656 + x^655 + x^654 + x^649 + x^644 + x^643 + x^641 + x^637 + x^632 + x^630 + x^629 + x^626 + x^623 + x^621 + x^620 + x^618 + x^614 + x^613 + x^606 + x^601 + x^599 + x^597 + x^595 + x^592 + x^591 + x^589 + x^588 + x^586 + x^584 + x^582 + x^577 + x^576 + x^575 + x^568 + x^567 + x^565 + x^564 + x^562 + x^558 + x^556 + x^553 + x^551 + x^550 + x^548 + x^547 + x^541 + x^540 + x^535 + x^534 + x^528 + x^527 + x^526 + x^522 + x^521 + x^520 + x^517 + x^514 + x^512 + x^510 + x^504 + x^503 + x^502 + x^498 + x^497 + x^496 + x^487 + x^482 + x^474 + x^473 + x^469 + x^468 + x^466 + x^463 + x^462 + x^459 + x^454 + x^453 + x^452 + x^451 + x^447 + x^442 + x^441 + x^433 + x^431 + x^430 + x^429 + x^426 + x^424 + x^423 + x^422 + x^421 + x^419 + x^417 + x^415 + x^412 + x^411 + x^409 + x^405 + x^402 + x^397 + x^396 + x^393 + x^392 + x^391 + x^385 + x^384 + x^382 + x^381 + x^380 + x^370 + x^369 + x^367 + x^365 + x^364 + x^361 + x^359 + x^356 + x^355 + x^351 + x^350 + x^349 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^336 + x^335 + x^333 + x^332 + x^331 + x^330 + x^326 + x^325 + x^324 + x^323 + x^318 + x^317 + x^315 + x^313 + x^310 + x^309 + x^306 + x^301 + x^300 + x^298 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^289 + x^288 + x^282 + x^281 + x^278 + x^277 + x^276 + x^275 + x^273 + x^271 + x^268 + x^266 + x^265 + x^263 + x^261 + x^260 + x^259 + x^257 + x^252 + x^249 + x^247 + x^244 + x^243 + x^238 + x^236 + x^232 + x^231 + x^229 + x^228 + x^227 + x^226 + x^225 + x^224 + x^221 + x^220 + x^219 + x^215 + x^214 + x^211 + x^209 + x^207 + x^204 + x^201 + x^198 + x^196 + x^195 + x^194 + x^193 + x^191 + x^189 + x^186 + x^185 + x^182 + x^181 + x^179 + x^178 + x^174 + x^173 + x^172 + x^170 + x^168 + x^166 + x^164 + x^162 + x^160 + x^159 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^148 + x^147 + x^146 + x^145 + x^143 + x^140 + x^134 + x^133 + x^130 + x^129 + x^128 + x^126 + x^124 + x^123 + x^122 + x^121 + x^119 + x^118 + x^117 + x^116 + x^115 + x^113 + x^110 + x^107 + x^106 + x^105 + x^104 + x^103 + x^102 + x^101 + x^99 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^91 + x^90 + x^89 + x^86 + x^85 + x^82 + x^81 + x^80 + x^79 + x^78 + x^76 + x^73 + x^71 + x^69 + x^65 + x^63 + x^60 + x^58 + x^57 + x^56 + x^55 + x^54 + x^52 + x^49 + x^47 + x^46 + x^45 + x^43 + x^42 + x^40 + x^39 + x^38 + x^36 + x^33 + x^32 + x^28 + x^25 + x^19 + x^18 + x^7 + 1
+
+8-36-47 355 x^928 + x^898 + x^870 + x^860 + x^856 + x^830 + x^818 + x^814 + x^813 + x^808 + x^800 + x^797 + x^796 + x^792 + x^788 + x^783 + x^778 + x^776 + x^772 + x^771 + x^770 + x^767 + x^766 + x^762 + x^755 + x^750 + x^740 + x^737 + x^736 + x^734 + x^730 + x^729 + x^724 + x^719 + x^711 + x^710 + x^707 + x^706 + x^698 + x^693 + x^692 + x^690 + x^688 + x^687 + x^680 + x^676 + x^674 + x^673 + x^672 + x^669 + x^665 + x^663 + x^662 + x^658 + x^657 + x^656 + x^653 + x^651 + x^650 + x^648 + x^647 + x^642 + x^635 + x^632 + x^631 + x^630 + x^627 + x^625 + x^624 + x^623 + x^622 + x^620 + x^619 + x^618 + x^609 + x^600 + x^595 + x^593 + x^592 + x^591 + x^589 + x^587 + x^583 + x^582 + x^579 + x^578 + x^577 + x^574 + x^570 + x^566 + x^565 + x^561 + x^559 + x^558 + x^557 + x^556 + x^555 + x^552 + x^550 + x^548 + x^544 + x^542 + x^541 + x^540 + x^537 + x^536 + x^534 + x^533 + x^532 + x^531 + x^528 + x^527 + x^525 + x^524 + x^521 + x^519 + x^518 + x^517 + x^516 + x^515 + x^514 + x^513 + x^512 + x^511 + x^509 + x^507 + x^505 + x^504 + x^502 + x^501 + x^497 + x^496 + x^493 + x^492 + x^491 + x^490 + x^488 + x^486 + x^485 + x^480 + x^478 + x^476 + x^475 + x^473 + x^469 + x^468 + x^467 + x^466 + x^463 + x^462 + x^453 + x^452 + x^451 + x^449 + x^447 + x^446 + x^445 + x^444 + x^443 + x^440 + x^438 + x^437 + x^436 + x^435 + x^427 + x^426 + x^423 + x^421 + x^419 + x^416 + x^411 + x^410 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^402 + x^400 + x^398 + x^397 + x^395 + x^391 + x^390 + x^389 + x^385 + x^384 + x^380 + x^378 + x^377 + x^374 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^363 + x^361 + x^360 + x^354 + x^352 + x^351 + x^350 + x^347 + x^342 + x^339 + x^337 + x^334 + x^333 + x^330 + x^328 + x^326 + x^324 + x^323 + x^315 + x^314 + x^309 + x^306 + x^304 + x^302 + x^298 + x^297 + x^296 + x^295 + x^293 + x^291 + x^289 + x^284 + x^282 + x^281 + x^279 + x^275 + x^274 + x^273 + x^269 + x^267 + x^265 + x^263 + x^261 + x^260 + x^259 + x^257 + x^256 + x^254 + x^252 + x^248 + x^247 + x^246 + x^244 + x^243 + x^242 + x^241 + x^238 + x^235 + x^234 + x^232 + x^229 + x^227 + x^225 + x^224 + x^223 + x^219 + x^217 + x^215 + x^211 + x^208 + x^206 + x^205 + x^203 + x^200 + x^197 + x^195 + x^190 + x^189 + x^187 + x^185 + x^176 + x^174 + x^172 + x^169 + x^165 + x^160 + x^159 + x^158 + x^156 + x^155 + x^154 + x^153 + x^152 + x^150 + x^146 + x^141 + x^139 + x^137 + x^135 + x^132 + x^131 + x^130 + x^127 + x^124 + x^120 + x^119 + x^116 + x^114 + x^111 + x^110 + x^109 + x^108 + x^105 + x^102 + x^99 + x^98 + x^95 + x^94 + x^93 + x^92 + x^90 + x^87 + x^86 + x^76 + x^75 + x^74 + x^72 + x^70 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^59 + x^58 + x^57 + x^54 + x^51 + x^50 + x^48 + x^46 + x^45 + x^44 + x^43 + x^41 + x^39 + x^38 + x^36 + x^30 + x^27 + x^26 + x^24 + x^18 + x^14 + x^12 + 1
+
+44-14-41 357 x^928 + x^898 + x^870 + x^856 + x^852 + x^847 + x^831 + x^822 + x^817 + x^814 + x^808 + x^796 + x^795 + x^792 + x^784 + x^778 + x^777 + x^775 + x^772 + x^771 + x^766 + x^763 + x^756 + x^754 + x^747 + x^746 + x^745 + x^744 + x^742 + x^736 + x^733 + x^732 + x^730 + x^727 + x^726 + x^724 + x^721 + x^717 + x^716 + x^715 + x^714 + x^711 + x^705 + x^704 + x^694 + x^693 + x^691 + x^684 + x^682 + x^678 + x^674 + x^670 + x^664 + x^662 + x^655 + x^653 + x^647 + x^645 + x^644 + x^643 + x^637 + x^636 + x^635 + x^633 + x^631 + x^627 + x^626 + x^625 + x^624 + x^620 + x^618 + x^605 + x^604 + x^603 + x^601 + x^597 + x^588 + x^585 + x^583 + x^578 + x^575 + x^574 + x^569 + x^568 + x^567 + x^566 + x^565 + x^563 + x^558 + x^556 + x^554 + x^553 + x^552 + x^551 + x^550 + x^548 + x^544 + x^543 + x^542 + x^539 + x^538 + x^537 + x^535 + x^533 + x^532 + x^530 + x^528 + x^525 + x^523 + x^521 + x^520 + x^516 + x^515 + x^514 + x^513 + x^510 + x^509 + x^506 + x^504 + x^502 + x^497 + x^496 + x^491 + x^487 + x^485 + x^484 + x^482 + x^481 + x^480 + x^473 + x^471 + x^470 + x^468 + x^466 + x^464 + x^463 + x^462 + x^461 + x^459 + x^458 + x^455 + x^452 + x^450 + x^449 + x^447 + x^446 + x^443 + x^442 + x^440 + x^438 + x^436 + x^435 + x^432 + x^429 + x^428 + x^423 + x^420 + x^418 + x^417 + x^416 + x^413 + x^412 + x^411 + x^410 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^400 + x^397 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^386 + x^385 + x^384 + x^382 + x^380 + x^378 + x^376 + x^371 + x^370 + x^369 + x^368 + x^365 + x^364 + x^363 + x^359 + x^358 + x^357 + x^356 + x^353 + x^351 + x^350 + x^349 + x^348 + x^346 + x^345 + x^343 + x^342 + x^340 + x^339 + x^338 + x^335 + x^333 + x^332 + x^327 + x^324 + x^322 + x^317 + x^316 + x^315 + x^313 + x^311 + x^308 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^289 + x^284 + x^281 + x^279 + x^278 + x^276 + x^275 + x^273 + x^272 + x^271 + x^269 + x^266 + x^264 + x^260 + x^258 + x^256 + x^255 + x^251 + x^250 + x^248 + x^247 + x^244 + x^243 + x^241 + x^240 + x^239 + x^236 + x^235 + x^233 + x^232 + x^230 + x^226 + x^224 + x^223 + x^221 + x^220 + x^218 + x^217 + x^216 + x^215 + x^211 + x^210 + x^209 + x^208 + x^206 + x^204 + x^201 + x^200 + x^197 + x^196 + x^192 + x^187 + x^185 + x^183 + x^182 + x^181 + x^179 + x^178 + x^177 + x^175 + x^173 + x^170 + x^169 + x^168 + x^166 + x^159 + x^158 + x^157 + x^155 + x^154 + x^150 + x^149 + x^146 + x^144 + x^139 + x^138 + x^134 + x^132 + x^131 + x^128 + x^125 + x^123 + x^122 + x^120 + x^119 + x^116 + x^115 + x^111 + x^110 + x^109 + x^108 + x^101 + x^100 + x^99 + x^97 + x^96 + x^93 + x^92 + x^90 + x^87 + x^77 + x^74 + x^71 + x^70 + x^63 + x^58 + x^56 + x^54 + x^53 + x^52 + x^51 + x^50 + x^46 + x^42 + x^40 + x^38 + x^37 + x^36 + x^30 + x^28 + x^26 + x^14 + x^12 + 1
+
+22-40-11 359 x^928 + x^898 + x^870 + x^829 + x^816 + x^814 + x^808 + x^803 + x^799 + x^786 + x^784 + x^778 + x^777 + x^773 + x^764 + x^762 + x^743 + x^738 + x^736 + x^734 + x^725 + x^723 + x^719 + x^713 + x^710 + x^708 + x^699 + x^691 + x^688 + x^686 + x^684 + x^682 + x^673 + x^672 + x^665 + x^661 + x^657 + x^656 + x^654 + x^652 + x^650 + x^648 + x^645 + x^644 + x^642 + x^639 + x^637 + x^633 + x^631 + x^630 + x^626 + x^624 + x^622 + x^621 + x^620 + x^619 + x^618 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^604 + x^603 + x^601 + x^600 + x^599 + x^598 + x^594 + x^591 + x^587 + x^586 + x^585 + x^582 + x^580 + x^578 + x^577 + x^576 + x^572 + x^562 + x^561 + x^559 + x^558 + x^557 + x^556 + x^554 + x^553 + x^552 + x^550 + x^549 + x^548 + x^545 + x^543 + x^541 + x^540 + x^537 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^527 + x^526 + x^522 + x^521 + x^518 + x^517 + x^516 + x^515 + x^514 + x^512 + x^511 + x^510 + x^509 + x^508 + x^507 + x^501 + x^499 + x^494 + x^491 + x^490 + x^489 + x^488 + x^486 + x^484 + x^483 + x^481 + x^480 + x^479 + x^478 + x^476 + x^475 + x^474 + x^472 + x^471 + x^469 + x^468 + x^466 + x^465 + x^464 + x^463 + x^461 + x^459 + x^457 + x^450 + x^449 + x^448 + x^446 + x^445 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^431 + x^430 + x^429 + x^427 + x^426 + x^423 + x^418 + x^417 + x^415 + x^413 + x^403 + x^402 + x^401 + x^399 + x^398 + x^397 + x^395 + x^394 + x^393 + x^386 + x^382 + x^379 + x^378 + x^377 + x^368 + x^367 + x^366 + x^364 + x^363 + x^362 + x^360 + x^359 + x^356 + x^354 + x^352 + x^344 + x^343 + x^342 + x^341 + x^340 + x^337 + x^336 + x^331 + x^330 + x^325 + x^323 + x^321 + x^320 + x^319 + x^318 + x^315 + x^313 + x^311 + x^310 + x^308 + x^306 + x^303 + x^302 + x^300 + x^298 + x^297 + x^296 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^286 + x^285 + x^283 + x^278 + x^277 + x^275 + x^274 + x^273 + x^271 + x^269 + x^268 + x^267 + x^265 + x^261 + x^260 + x^259 + x^257 + x^256 + x^255 + x^254 + x^251 + x^249 + x^248 + x^245 + x^244 + x^242 + x^240 + x^238 + x^237 + x^236 + x^231 + x^229 + x^227 + x^225 + x^224 + x^223 + x^222 + x^221 + x^216 + x^215 + x^213 + x^211 + x^205 + x^202 + x^196 + x^194 + x^193 + x^192 + x^191 + x^190 + x^184 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^171 + x^169 + x^164 + x^162 + x^161 + x^160 + x^155 + x^153 + x^149 + x^143 + x^142 + x^139 + x^138 + x^135 + x^134 + x^133 + x^132 + x^130 + x^128 + x^127 + x^126 + x^124 + x^123 + x^120 + x^118 + x^117 + x^115 + x^114 + x^113 + x^112 + x^111 + x^109 + x^108 + x^107 + x^104 + x^103 + x^101 + x^98 + x^95 + x^93 + x^92 + x^89 + x^88 + x^86 + x^82 + x^80 + x^76 + x^75 + x^69 + x^67 + x^65 + x^64 + x^60 + x^58 + x^57 + x^55 + x^53 + x^50 + x^49 + x^47 + x^46 + x^45 + x^44 + x^43 + x^42 + x^39 + x^37 + x^36 + x^35 + x^34 + x^32 + x^24 + x^22 + x^20 + 1
+
+33-20-8 359 x^928 + x^898 + x^874 + x^870 + x^845 + x^840 + x^824 + x^808 + x^794 + x^790 + x^787 + x^786 + x^780 + x^778 + x^764 + x^762 + x^761 + x^760 + x^756 + x^752 + x^741 + x^737 + x^736 + x^734 + x^731 + x^729 + x^728 + x^726 + x^720 + x^716 + x^712 + x^710 + x^707 + x^706 + x^703 + x^700 + x^697 + x^696 + x^688 + x^686 + x^683 + x^682 + x^681 + x^675 + x^671 + x^669 + x^667 + x^666 + x^660 + x^658 + x^657 + x^654 + x^653 + x^652 + x^649 + x^647 + x^646 + x^640 + x^639 + x^637 + x^636 + x^634 + x^629 + x^628 + x^627 + x^625 + x^624 + x^618 + x^613 + x^609 + x^608 + x^607 + x^600 + x^598 + x^597 + x^596 + x^595 + x^594 + x^593 + x^592 + x^591 + x^589 + x^587 + x^586 + x^585 + x^583 + x^582 + x^581 + x^580 + x^579 + x^577 + x^570 + x^567 + x^562 + x^554 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^542 + x^539 + x^537 + x^535 + x^533 + x^531 + x^530 + x^524 + x^523 + x^521 + x^520 + x^517 + x^516 + x^512 + x^511 + x^504 + x^503 + x^502 + x^501 + x^497 + x^494 + x^492 + x^490 + x^489 + x^486 + x^480 + x^478 + x^477 + x^476 + x^475 + x^472 + x^467 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^458 + x^456 + x^452 + x^449 + x^447 + x^446 + x^442 + x^440 + x^439 + x^438 + x^437 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^426 + x^425 + x^423 + x^422 + x^421 + x^420 + x^415 + x^414 + x^413 + x^412 + x^411 + x^410 + x^408 + x^404 + x^402 + x^400 + x^399 + x^398 + x^395 + x^394 + x^392 + x^390 + x^387 + x^386 + x^385 + x^383 + x^379 + x^377 + x^376 + x^374 + x^373 + x^372 + x^371 + x^368 + x^366 + x^365 + x^362 + x^361 + x^360 + x^359 + x^358 + x^350 + x^347 + x^342 + x^341 + x^338 + x^337 + x^335 + x^331 + x^330 + x^326 + x^325 + x^322 + x^321 + x^320 + x^319 + x^318 + x^317 + x^312 + x^311 + x^308 + x^307 + x^305 + x^303 + x^301 + x^298 + x^295 + x^292 + x^289 + x^286 + x^282 + x^280 + x^277 + x^273 + x^271 + x^270 + x^265 + x^263 + x^262 + x^261 + x^260 + x^257 + x^253 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^245 + x^243 + x^240 + x^239 + x^236 + x^234 + x^230 + x^228 + x^226 + x^225 + x^224 + x^222 + x^220 + x^219 + x^218 + x^215 + x^214 + x^213 + x^210 + x^205 + x^203 + x^201 + x^195 + x^194 + x^192 + x^191 + x^187 + x^185 + x^184 + x^183 + x^181 + x^178 + x^176 + x^174 + x^173 + x^172 + x^171 + x^170 + x^168 + x^165 + x^164 + x^163 + x^160 + x^157 + x^155 + x^154 + x^153 + x^152 + x^151 + x^150 + x^149 + x^148 + x^139 + x^138 + x^135 + x^134 + x^132 + x^131 + x^129 + x^128 + x^127 + x^126 + x^125 + x^122 + x^121 + x^119 + x^118 + x^115 + x^114 + x^111 + x^110 + x^106 + x^103 + x^101 + x^99 + x^98 + x^95 + x^91 + x^90 + x^89 + x^83 + x^78 + x^77 + x^75 + x^74 + x^70 + x^65 + x^64 + x^61 + x^56 + x^55 + x^52 + x^51 + x^49 + x^46 + x^41 + x^38 + x^36 + x^35 + x^34 + x^32 + x^29 + x^28 + x^27 + x^23 + x^16 + x^12 + x^8 + x^4 + 1
+
+6-42-43 359 x^928 + x^898 + x^877 + x^870 + x^847 + x^846 + x^844 + x^822 + x^808 + x^799 + x^794 + x^793 + x^790 + x^786 + x^778 + x^775 + x^774 + x^772 + x^771 + x^769 + x^766 + x^764 + x^750 + x^749 + x^748 + x^747 + x^744 + x^743 + x^742 + x^739 + x^736 + x^724 + x^721 + x^718 + x^715 + x^712 + x^710 + x^706 + x^702 + x^699 + x^695 + x^693 + x^692 + x^689 + x^687 + x^685 + x^684 + x^683 + x^682 + x^679 + x^674 + x^671 + x^670 + x^668 + x^667 + x^664 + x^662 + x^653 + x^652 + x^650 + x^649 + x^645 + x^644 + x^642 + x^639 + x^638 + x^637 + x^634 + x^633 + x^630 + x^624 + x^622 + x^619 + x^618 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^608 + x^603 + x^601 + x^598 + x^595 + x^592 + x^589 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^578 + x^574 + x^572 + x^568 + x^567 + x^565 + x^562 + x^561 + x^559 + x^558 + x^557 + x^555 + x^554 + x^550 + x^549 + x^547 + x^545 + x^541 + x^534 + x^528 + x^527 + x^523 + x^520 + x^518 + x^515 + x^510 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^495 + x^494 + x^492 + x^489 + x^486 + x^483 + x^482 + x^479 + x^476 + x^475 + x^473 + x^472 + x^468 + x^467 + x^465 + x^464 + x^463 + x^461 + x^459 + x^458 + x^455 + x^452 + x^451 + x^450 + x^449 + x^448 + x^446 + x^445 + x^444 + x^443 + x^441 + x^440 + x^437 + x^434 + x^431 + x^430 + x^429 + x^425 + x^423 + x^422 + x^421 + x^419 + x^418 + x^417 + x^411 + x^408 + x^406 + x^405 + x^403 + x^401 + x^398 + x^397 + x^396 + x^393 + x^390 + x^382 + x^378 + x^376 + x^373 + x^372 + x^370 + x^369 + x^366 + x^361 + x^359 + x^358 + x^356 + x^354 + x^352 + x^351 + x^350 + x^349 + x^348 + x^347 + x^344 + x^340 + x^339 + x^336 + x^335 + x^333 + x^332 + x^329 + x^325 + x^324 + x^322 + x^321 + x^317 + x^316 + x^311 + x^310 + x^309 + x^303 + x^302 + x^301 + x^299 + x^298 + x^295 + x^294 + x^290 + x^289 + x^288 + x^287 + x^283 + x^282 + x^280 + x^279 + x^278 + x^277 + x^272 + x^271 + x^270 + x^268 + x^263 + x^261 + x^260 + x^259 + x^257 + x^256 + x^254 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^241 + x^239 + x^238 + x^237 + x^235 + x^231 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^221 + x^219 + x^217 + x^214 + x^210 + x^209 + x^208 + x^205 + x^204 + x^202 + x^199 + x^196 + x^191 + x^190 + x^189 + x^186 + x^184 + x^183 + x^180 + x^179 + x^178 + x^177 + x^175 + x^174 + x^170 + x^168 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^157 + x^154 + x^153 + x^151 + x^143 + x^137 + x^135 + x^134 + x^129 + x^127 + x^126 + x^122 + x^121 + x^119 + x^118 + x^113 + x^111 + x^106 + x^104 + x^101 + x^100 + x^99 + x^98 + x^96 + x^92 + x^91 + x^90 + x^83 + x^82 + x^81 + x^79 + x^75 + x^74 + x^72 + x^71 + x^68 + x^64 + x^63 + x^60 + x^57 + x^56 + x^54 + x^52 + x^51 + x^49 + x^48 + x^46 + x^45 + x^43 + x^42 + x^39 + x^38 + x^37 + x^36 + x^32 + x^28 + x^26 + x^24 + x^16 + x^14 + 1
+
+33-22-4 361 x^928 + x^898 + x^870 + x^832 + x^822 + x^812 + x^808 + x^805 + x^802 + x^792 + x^784 + x^778 + x^775 + x^774 + x^762 + x^757 + x^756 + x^754 + x^746 + x^744 + x^740 + x^738 + x^736 + x^732 + x^728 + x^726 + x^720 + x^716 + x^711 + x^701 + x^697 + x^692 + x^684 + x^682 + x^680 + x^678 + x^673 + x^672 + x^671 + x^670 + x^658 + x^655 + x^653 + x^652 + x^651 + x^644 + x^637 + x^636 + x^630 + x^626 + x^622 + x^615 + x^613 + x^612 + x^611 + x^610 + x^608 + x^607 + x^606 + x^600 + x^599 + x^594 + x^593 + x^592 + x^590 + x^589 + x^588 + x^587 + x^586 + x^585 + x^583 + x^580 + x^578 + x^577 + x^574 + x^569 + x^567 + x^564 + x^562 + x^561 + x^559 + x^554 + x^553 + x^552 + x^549 + x^548 + x^544 + x^543 + x^538 + x^537 + x^536 + x^535 + x^533 + x^530 + x^525 + x^524 + x^523 + x^522 + x^521 + x^519 + x^517 + x^516 + x^515 + x^514 + x^511 + x^507 + x^506 + x^500 + x^499 + x^498 + x^496 + x^494 + x^487 + x^486 + x^485 + x^483 + x^480 + x^473 + x^468 + x^466 + x^465 + x^464 + x^463 + x^461 + x^460 + x^454 + x^452 + x^448 + x^447 + x^445 + x^441 + x^440 + x^439 + x^438 + x^436 + x^435 + x^434 + x^433 + x^429 + x^427 + x^425 + x^423 + x^421 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^410 + x^409 + x^408 + x^404 + x^402 + x^401 + x^399 + x^397 + x^396 + x^393 + x^391 + x^390 + x^388 + x^387 + x^386 + x^383 + x^381 + x^380 + x^379 + x^376 + x^375 + x^374 + x^371 + x^370 + x^369 + x^368 + x^366 + x^364 + x^363 + x^361 + x^359 + x^356 + x^355 + x^354 + x^353 + x^350 + x^349 + x^344 + x^341 + x^338 + x^337 + x^336 + x^335 + x^332 + x^330 + x^329 + x^328 + x^327 + x^323 + x^322 + x^319 + x^318 + x^315 + x^314 + x^313 + x^309 + x^308 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^298 + x^296 + x^295 + x^294 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^282 + x^280 + x^279 + x^278 + x^275 + x^273 + x^271 + x^268 + x^266 + x^262 + x^261 + x^259 + x^258 + x^256 + x^255 + x^254 + x^253 + x^250 + x^245 + x^241 + x^240 + x^239 + x^237 + x^235 + x^234 + x^232 + x^231 + x^229 + x^226 + x^225 + x^221 + x^220 + x^218 + x^217 + x^215 + x^213 + x^211 + x^209 + x^206 + x^205 + x^201 + x^200 + x^196 + x^195 + x^192 + x^189 + x^188 + x^187 + x^186 + x^184 + x^183 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^169 + x^166 + x^165 + x^162 + x^160 + x^157 + x^154 + x^152 + x^150 + x^149 + x^145 + x^141 + x^138 + x^137 + x^133 + x^131 + x^129 + x^127 + x^125 + x^124 + x^123 + x^120 + x^118 + x^117 + x^115 + x^114 + x^112 + x^109 + x^108 + x^105 + x^102 + x^100 + x^99 + x^97 + x^96 + x^91 + x^90 + x^88 + x^87 + x^86 + x^85 + x^82 + x^80 + x^79 + x^77 + x^75 + x^74 + x^70 + x^66 + x^65 + x^63 + x^62 + x^61 + x^60 + x^59 + x^54 + x^52 + x^50 + x^49 + x^46 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^36 + x^35 + x^33 + x^31 + x^27 + x^26 + x^22 + x^21 + x^19 + x^16 + x^14 + x^12 + 1
+
+46-48-7 361 x^928 + x^898 + x^870 + x^862 + x^848 + x^837 + x^829 + x^820 + x^815 + x^808 + x^807 + x^806 + x^802 + x^799 + x^798 + x^795 + x^790 + x^788 + x^787 + x^785 + x^776 + x^769 + x^765 + x^762 + x^760 + x^756 + x^755 + x^740 + x^739 + x^737 + x^732 + x^730 + x^727 + x^725 + x^717 + x^715 + x^714 + x^710 + x^709 + x^706 + x^704 + x^695 + x^688 + x^687 + x^686 + x^684 + x^682 + x^680 + x^679 + x^678 + x^676 + x^675 + x^667 + x^664 + x^661 + x^658 + x^657 + x^655 + x^654 + x^653 + x^652 + x^650 + x^649 + x^647 + x^646 + x^644 + x^643 + x^638 + x^637 + x^636 + x^634 + x^633 + x^627 + x^624 + x^623 + x^622 + x^620 + x^619 + x^618 + x^615 + x^612 + x^611 + x^606 + x^604 + x^601 + x^594 + x^591 + x^590 + x^589 + x^588 + x^587 + x^585 + x^583 + x^580 + x^575 + x^574 + x^572 + x^571 + x^569 + x^568 + x^567 + x^564 + x^563 + x^558 + x^557 + x^556 + x^552 + x^551 + x^546 + x^544 + x^542 + x^541 + x^535 + x^534 + x^532 + x^531 + x^530 + x^529 + x^528 + x^526 + x^525 + x^523 + x^521 + x^519 + x^518 + x^516 + x^514 + x^513 + x^506 + x^505 + x^504 + x^499 + x^498 + x^497 + x^496 + x^495 + x^493 + x^491 + x^490 + x^488 + x^487 + x^486 + x^485 + x^484 + x^481 + x^480 + x^477 + x^476 + x^473 + x^472 + x^471 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^455 + x^451 + x^449 + x^448 + x^447 + x^446 + x^444 + x^443 + x^441 + x^440 + x^439 + x^437 + x^431 + x^429 + x^428 + x^426 + x^424 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^411 + x^410 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^400 + x^397 + x^394 + x^392 + x^390 + x^388 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^374 + x^367 + x^364 + x^363 + x^360 + x^357 + x^356 + x^354 + x^353 + x^352 + x^351 + x^350 + x^348 + x^343 + x^342 + x^341 + x^337 + x^334 + x^333 + x^330 + x^326 + x^316 + x^313 + x^309 + x^306 + x^305 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^287 + x^285 + x^282 + x^281 + x^278 + x^276 + x^275 + x^271 + x^269 + x^267 + x^263 + x^262 + x^261 + x^260 + x^257 + x^256 + x^255 + x^253 + x^249 + x^248 + x^244 + x^243 + x^242 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^231 + x^226 + x^224 + x^221 + x^217 + x^216 + x^214 + x^211 + x^210 + x^209 + x^208 + x^206 + x^205 + x^202 + x^200 + x^197 + x^196 + x^195 + x^190 + x^186 + x^184 + x^183 + x^181 + x^176 + x^172 + x^171 + x^167 + x^166 + x^165 + x^164 + x^159 + x^157 + x^154 + x^153 + x^151 + x^150 + x^146 + x^145 + x^144 + x^142 + x^141 + x^140 + x^139 + x^137 + x^136 + x^134 + x^131 + x^130 + x^129 + x^125 + x^124 + x^123 + x^120 + x^118 + x^117 + x^111 + x^110 + x^108 + x^107 + x^106 + x^105 + x^98 + x^96 + x^95 + x^94 + x^92 + x^88 + x^83 + x^81 + x^78 + x^76 + x^72 + x^71 + x^67 + x^66 + x^65 + x^63 + x^60 + x^58 + x^57 + x^56 + x^52 + x^51 + x^49 + x^48 + x^46 + x^44 + x^40 + x^38 + x^34 + x^33 + x^32 + x^31 + x^30 + x^28 + x^20 + 1
+
+49-44-52 361 x^928 + x^898 + x^870 + x^864 + x^842 + x^837 + x^834 + x^812 + x^810 + x^808 + x^804 + x^788 + x^786 + x^783 + x^782 + x^780 + x^778 + x^774 + x^758 + x^756 + x^753 + x^752 + x^734 + x^732 + x^729 + x^727 + x^724 + x^723 + x^722 + x^717 + x^704 + x^702 + x^699 + x^696 + x^693 + x^692 + x^690 + x^680 + x^678 + x^672 + x^667 + x^665 + x^663 + x^662 + x^661 + x^660 + x^650 + x^646 + x^637 + x^636 + x^633 + x^631 + x^626 + x^621 + x^618 + x^616 + x^614 + x^612 + x^611 + x^610 + x^609 + x^605 + x^603 + x^602 + x^601 + x^599 + x^597 + x^596 + x^594 + x^589 + x^588 + x^586 + x^576 + x^575 + x^573 + x^572 + x^571 + x^569 + x^568 + x^565 + x^562 + x^561 + x^560 + x^558 + x^557 + x^555 + x^554 + x^551 + x^549 + x^548 + x^543 + x^542 + x^539 + x^536 + x^532 + x^529 + x^528 + x^527 + x^526 + x^525 + x^518 + x^517 + x^514 + x^513 + x^512 + x^511 + x^509 + x^508 + x^506 + x^505 + x^499 + x^496 + x^495 + x^493 + x^492 + x^491 + x^489 + x^486 + x^483 + x^482 + x^479 + x^477 + x^476 + x^474 + x^468 + x^467 + x^462 + x^461 + x^457 + x^456 + x^454 + x^453 + x^452 + x^451 + x^449 + x^444 + x^442 + x^441 + x^439 + x^438 + x^437 + x^436 + x^432 + x^431 + x^429 + x^428 + x^427 + x^425 + x^424 + x^423 + x^422 + x^420 + x^419 + x^418 + x^416 + x^414 + x^413 + x^409 + x^407 + x^406 + x^404 + x^403 + x^402 + x^401 + x^395 + x^394 + x^393 + x^392 + x^390 + x^389 + x^387 + x^386 + x^384 + x^380 + x^378 + x^377 + x^376 + x^372 + x^371 + x^370 + x^369 + x^365 + x^363 + x^362 + x^361 + x^358 + x^357 + x^356 + x^355 + x^352 + x^351 + x^350 + x^347 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^338 + x^332 + x^331 + x^328 + x^326 + x^325 + x^323 + x^322 + x^321 + x^319 + x^317 + x^316 + x^314 + x^313 + x^309 + x^305 + x^303 + x^301 + x^300 + x^299 + x^298 + x^297 + x^294 + x^292 + x^290 + x^285 + x^284 + x^282 + x^280 + x^279 + x^278 + x^276 + x^272 + x^267 + x^266 + x^265 + x^264 + x^263 + x^262 + x^259 + x^256 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^245 + x^243 + x^241 + x^240 + x^238 + x^234 + x^231 + x^229 + x^228 + x^227 + x^224 + x^222 + x^221 + x^215 + x^214 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^204 + x^197 + x^196 + x^194 + x^192 + x^191 + x^189 + x^188 + x^187 + x^186 + x^182 + x^180 + x^178 + x^175 + x^172 + x^168 + x^167 + x^166 + x^163 + x^162 + x^158 + x^154 + x^153 + x^150 + x^148 + x^146 + x^145 + x^144 + x^138 + x^136 + x^132 + x^131 + x^130 + x^129 + x^124 + x^122 + x^120 + x^116 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^103 + x^102 + x^101 + x^99 + x^98 + x^97 + x^96 + x^94 + x^92 + x^90 + x^86 + x^85 + x^84 + x^83 + x^82 + x^80 + x^79 + x^77 + x^76 + x^65 + x^60 + x^59 + x^57 + x^54 + x^52 + x^47 + x^45 + x^44 + x^42 + x^38 + x^37 + x^34 + x^33 + x^31 + x^29 + x^26 + x^25 + x^24 + x^22 + x^21 + x^19 + x^18 + x^17 + x^15 + x^14 + x^12 + x^10 + 1
+
+34-42-39 365 x^928 + x^898 + x^870 + x^860 + x^850 + x^840 + x^831 + x^830 + x^811 + x^808 + x^801 + x^800 + x^792 + x^790 + x^780 + x^778 + x^771 + x^770 + x^762 + x^753 + x^744 + x^742 + x^740 + x^734 + x^720 + x^715 + x^712 + x^710 + x^703 + x^702 + x^694 + x^693 + x^691 + x^688 + x^685 + x^682 + x^680 + x^676 + x^674 + x^672 + x^664 + x^663 + x^662 + x^660 + x^658 + x^657 + x^656 + x^653 + x^652 + x^650 + x^647 + x^646 + x^645 + x^643 + x^637 + x^634 + x^628 + x^627 + x^623 + x^622 + x^618 + x^617 + x^615 + x^614 + x^608 + x^607 + x^604 + x^603 + x^600 + x^597 + x^593 + x^592 + x^589 + x^588 + x^587 + x^586 + x^585 + x^584 + x^579 + x^578 + x^577 + x^574 + x^570 + x^567 + x^565 + x^563 + x^562 + x^560 + x^558 + x^555 + x^550 + x^549 + x^547 + x^544 + x^542 + x^541 + x^536 + x^533 + x^532 + x^529 + x^527 + x^526 + x^521 + x^520 + x^518 + x^517 + x^516 + x^514 + x^510 + x^509 + x^508 + x^506 + x^504 + x^503 + x^502 + x^501 + x^497 + x^496 + x^489 + x^488 + x^487 + x^486 + x^484 + x^481 + x^480 + x^476 + x^475 + x^473 + x^472 + x^471 + x^470 + x^467 + x^466 + x^463 + x^462 + x^459 + x^458 + x^457 + x^456 + x^453 + x^451 + x^450 + x^446 + x^445 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^436 + x^433 + x^432 + x^430 + x^428 + x^427 + x^425 + x^421 + x^420 + x^413 + x^412 + x^411 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^399 + x^398 + x^396 + x^391 + x^388 + x^385 + x^381 + x^378 + x^376 + x^375 + x^374 + x^372 + x^370 + x^368 + x^364 + x^363 + x^360 + x^359 + x^357 + x^354 + x^353 + x^350 + x^349 + x^348 + x^347 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^327 + x^326 + x^325 + x^324 + x^323 + x^321 + x^320 + x^317 + x^312 + x^310 + x^309 + x^303 + x^300 + x^298 + x^296 + x^295 + x^292 + x^291 + x^290 + x^288 + x^287 + x^286 + x^285 + x^284 + x^282 + x^278 + x^277 + x^275 + x^274 + x^273 + x^267 + x^266 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^257 + x^254 + x^250 + x^249 + x^244 + x^243 + x^242 + x^239 + x^238 + x^237 + x^236 + x^231 + x^230 + x^229 + x^228 + x^226 + x^224 + x^223 + x^222 + x^221 + x^220 + x^217 + x^214 + x^213 + x^212 + x^211 + x^208 + x^207 + x^206 + x^205 + x^204 + x^202 + x^198 + x^197 + x^195 + x^194 + x^192 + x^189 + x^187 + x^186 + x^185 + x^181 + x^180 + x^179 + x^178 + x^175 + x^173 + x^170 + x^168 + x^167 + x^166 + x^165 + x^164 + x^157 + x^155 + x^154 + x^150 + x^149 + x^148 + x^144 + x^143 + x^140 + x^138 + x^137 + x^135 + x^134 + x^132 + x^126 + x^124 + x^123 + x^120 + x^119 + x^117 + x^115 + x^113 + x^105 + x^104 + x^102 + x^100 + x^97 + x^96 + x^94 + x^91 + x^88 + x^87 + x^85 + x^84 + x^83 + x^82 + x^80 + x^79 + x^77 + x^76 + x^69 + x^68 + x^64 + x^61 + x^60 + x^55 + x^53 + x^51 + x^50 + x^48 + x^45 + x^44 + x^43 + x^40 + x^39 + x^38 + x^37 + x^36 + x^34 + x^33 + x^30 + x^22 + x^20 + x^19 + x^18 + x^16 + x^14 + 1
+
+34-2-25 367 x^928 + x^898 + x^870 + x^868 + x^866 + x^850 + x^838 + x^832 + x^822 + x^820 + x^808 + x^804 + x^802 + x^797 + x^792 + x^790 + x^788 + x^786 + x^778 + x^770 + x^768 + x^767 + x^760 + x^754 + x^748 + x^747 + x^746 + x^744 + x^738 + x^736 + x^735 + x^728 + x^726 + x^720 + x^717 + x^712 + x^708 + x^696 + x^694 + x^692 + x^690 + x^688 + x^687 + x^685 + x^684 + x^678 + x^677 + x^675 + x^673 + x^669 + x^667 + x^662 + x^658 + x^657 + x^654 + x^652 + x^647 + x^643 + x^642 + x^640 + x^639 + x^638 + x^637 + x^634 + x^633 + x^624 + x^613 + x^612 + x^611 + x^610 + x^609 + x^607 + x^606 + x^603 + x^600 + x^598 + x^597 + x^593 + x^591 + x^590 + x^588 + x^587 + x^586 + x^584 + x^583 + x^582 + x^581 + x^577 + x^576 + x^574 + x^571 + x^570 + x^568 + x^567 + x^564 + x^563 + x^562 + x^560 + x^558 + x^557 + x^554 + x^553 + x^551 + x^549 + x^548 + x^547 + x^546 + x^545 + x^539 + x^538 + x^535 + x^533 + x^531 + x^530 + x^529 + x^527 + x^525 + x^524 + x^523 + x^522 + x^520 + x^517 + x^515 + x^514 + x^511 + x^510 + x^507 + x^506 + x^504 + x^503 + x^500 + x^499 + x^498 + x^496 + x^493 + x^491 + x^490 + x^489 + x^487 + x^485 + x^483 + x^482 + x^480 + x^478 + x^477 + x^474 + x^473 + x^471 + x^469 + x^468 + x^465 + x^464 + x^460 + x^459 + x^457 + x^455 + x^451 + x^450 + x^449 + x^447 + x^446 + x^442 + x^441 + x^438 + x^430 + x^428 + x^427 + x^426 + x^425 + x^421 + x^420 + x^417 + x^416 + x^415 + x^414 + x^411 + x^410 + x^409 + x^406 + x^405 + x^404 + x^402 + x^396 + x^394 + x^393 + x^390 + x^389 + x^388 + x^386 + x^384 + x^382 + x^381 + x^380 + x^379 + x^378 + x^377 + x^376 + x^374 + x^373 + x^372 + x^371 + x^369 + x^366 + x^365 + x^364 + x^363 + x^356 + x^354 + x^352 + x^351 + x^344 + x^342 + x^338 + x^336 + x^335 + x^334 + x^327 + x^323 + x^321 + x^319 + x^318 + x^317 + x^312 + x^308 + x^305 + x^303 + x^302 + x^301 + x^299 + x^298 + x^297 + x^289 + x^286 + x^285 + x^283 + x^277 + x^276 + x^275 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^263 + x^258 + x^255 + x^254 + x^252 + x^251 + x^247 + x^246 + x^235 + x^233 + x^232 + x^229 + x^226 + x^225 + x^223 + x^220 + x^219 + x^216 + x^212 + x^210 + x^209 + x^208 + x^206 + x^205 + x^204 + x^202 + x^201 + x^200 + x^198 + x^196 + x^193 + x^190 + x^187 + x^185 + x^184 + x^182 + x^180 + x^179 + x^174 + x^173 + x^172 + x^171 + x^169 + x^167 + x^166 + x^165 + x^164 + x^159 + x^158 + x^156 + x^155 + x^154 + x^151 + x^150 + x^149 + x^148 + x^147 + x^146 + x^144 + x^143 + x^141 + x^137 + x^133 + x^132 + x^131 + x^130 + x^129 + x^126 + x^124 + x^123 + x^122 + x^118 + x^112 + x^111 + x^109 + x^108 + x^107 + x^105 + x^104 + x^103 + x^102 + x^99 + x^96 + x^93 + x^92 + x^91 + x^89 + x^86 + x^84 + x^83 + x^82 + x^81 + x^79 + x^77 + x^76 + x^75 + x^71 + x^70 + x^67 + x^65 + x^63 + x^53 + x^49 + x^44 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^32 + x^31 + x^28 + x^26 + x^25 + x^24 + x^22 + x^18 + x^16 + x^10 + x^8 + x^4 + 1
+
+34-39-1 367 x^928 + x^898 + x^894 + x^874 + x^870 + x^864 + x^855 + x^844 + x^840 + x^835 + x^834 + x^825 + x^820 + x^815 + x^814 + x^808 + x^805 + x^804 + x^801 + x^800 + x^796 + x^790 + x^785 + x^784 + x^778 + x^776 + x^770 + x^766 + x^761 + x^760 + x^756 + x^754 + x^751 + x^750 + x^746 + x^741 + x^740 + x^735 + x^732 + x^731 + x^730 + x^727 + x^724 + x^722 + x^721 + x^720 + x^716 + x^715 + x^712 + x^706 + x^705 + x^700 + x^697 + x^694 + x^692 + x^688 + x^686 + x^685 + x^682 + x^677 + x^676 + x^672 + x^667 + x^664 + x^657 + x^655 + x^653 + x^651 + x^650 + x^648 + x^642 + x^638 + x^632 + x^631 + x^630 + x^628 + x^627 + x^625 + x^622 + x^620 + x^618 + x^617 + x^616 + x^612 + x^611 + x^602 + x^600 + x^598 + x^597 + x^591 + x^588 + x^586 + x^582 + x^581 + x^579 + x^578 + x^577 + x^574 + x^573 + x^572 + x^568 + x^566 + x^564 + x^560 + x^552 + x^541 + x^538 + x^537 + x^535 + x^534 + x^532 + x^531 + x^529 + x^528 + x^523 + x^522 + x^521 + x^519 + x^518 + x^516 + x^515 + x^510 + x^509 + x^508 + x^506 + x^504 + x^500 + x^499 + x^498 + x^497 + x^495 + x^492 + x^490 + x^489 + x^488 + x^484 + x^482 + x^477 + x^475 + x^474 + x^472 + x^471 + x^470 + x^469 + x^467 + x^466 + x^465 + x^464 + x^462 + x^461 + x^460 + x^457 + x^455 + x^454 + x^453 + x^448 + x^447 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^431 + x^430 + x^429 + x^426 + x^424 + x^423 + x^421 + x^419 + x^418 + x^417 + x^416 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^397 + x^395 + x^394 + x^389 + x^388 + x^384 + x^383 + x^382 + x^380 + x^379 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^370 + x^369 + x^368 + x^367 + x^366 + x^361 + x^360 + x^359 + x^357 + x^355 + x^353 + x^350 + x^349 + x^344 + x^342 + x^341 + x^340 + x^338 + x^337 + x^336 + x^335 + x^334 + x^333 + x^332 + x^331 + x^329 + x^328 + x^326 + x^321 + x^320 + x^318 + x^317 + x^316 + x^313 + x^311 + x^310 + x^309 + x^306 + x^303 + x^302 + x^300 + x^299 + x^296 + x^295 + x^294 + x^293 + x^292 + x^291 + x^288 + x^287 + x^286 + x^284 + x^279 + x^276 + x^274 + x^270 + x^269 + x^268 + x^265 + x^264 + x^262 + x^259 + x^257 + x^256 + x^255 + x^251 + x^248 + x^247 + x^245 + x^244 + x^243 + x^240 + x^237 + x^234 + x^232 + x^230 + x^227 + x^224 + x^223 + x^219 + x^214 + x^212 + x^206 + x^204 + x^201 + x^198 + x^197 + x^194 + x^192 + x^190 + x^189 + x^186 + x^185 + x^182 + x^179 + x^178 + x^174 + x^172 + x^171 + x^168 + x^166 + x^163 + x^162 + x^161 + x^159 + x^158 + x^154 + x^153 + x^152 + x^151 + x^149 + x^148 + x^146 + x^143 + x^142 + x^140 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^131 + x^128 + x^126 + x^125 + x^124 + x^123 + x^119 + x^118 + x^116 + x^115 + x^109 + x^108 + x^106 + x^105 + x^103 + x^100 + x^98 + x^91 + x^89 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^70 + x^69 + x^67 + x^66 + x^65 + x^59 + x^58 + x^56 + x^48 + x^45 + x^43 + x^42 + x^38 + x^37 + x^34 + x^29 + x^26 + x^21 + x^10 + 1
+
+8-38-53 367 x^928 + x^898 + x^870 + x^843 + x^838 + x^833 + x^830 + x^820 + x^816 + x^811 + x^808 + x^800 + x^786 + x^781 + x^778 + x^773 + x^768 + x^760 + x^756 + x^752 + x^750 + x^743 + x^742 + x^738 + x^733 + x^732 + x^730 + x^728 + x^726 + x^723 + x^720 + x^718 + x^711 + x^710 + x^708 + x^700 + x^699 + x^698 + x^696 + x^695 + x^693 + x^691 + x^690 + x^688 + x^686 + x^685 + x^683 + x^681 + x^672 + x^670 + x^667 + x^666 + x^665 + x^664 + x^663 + x^662 + x^661 + x^658 + x^657 + x^655 + x^654 + x^650 + x^648 + x^646 + x^645 + x^644 + x^642 + x^640 + x^639 + x^638 + x^636 + x^634 + x^626 + x^622 + x^620 + x^617 + x^615 + x^614 + x^613 + x^612 + x^606 + x^605 + x^603 + x^600 + x^597 + x^596 + x^592 + x^591 + x^590 + x^589 + x^588 + x^585 + x^584 + x^581 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^569 + x^568 + x^564 + x^562 + x^561 + x^556 + x^554 + x^551 + x^549 + x^544 + x^543 + x^542 + x^540 + x^539 + x^538 + x^533 + x^532 + x^530 + x^529 + x^527 + x^526 + x^524 + x^521 + x^520 + x^517 + x^515 + x^514 + x^510 + x^507 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^495 + x^493 + x^489 + x^487 + x^486 + x^483 + x^482 + x^480 + x^477 + x^474 + x^471 + x^469 + x^468 + x^463 + x^461 + x^459 + x^456 + x^453 + x^450 + x^447 + x^443 + x^442 + x^441 + x^439 + x^438 + x^437 + x^436 + x^435 + x^431 + x^424 + x^422 + x^415 + x^411 + x^410 + x^409 + x^407 + x^406 + x^405 + x^404 + x^401 + x^400 + x^396 + x^395 + x^392 + x^391 + x^389 + x^388 + x^385 + x^382 + x^381 + x^380 + x^379 + x^377 + x^374 + x^369 + x^368 + x^367 + x^366 + x^365 + x^364 + x^359 + x^357 + x^353 + x^351 + x^349 + x^345 + x^344 + x^342 + x^341 + x^340 + x^339 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^327 + x^326 + x^324 + x^323 + x^322 + x^320 + x^319 + x^318 + x^314 + x^313 + x^312 + x^311 + x^309 + x^307 + x^304 + x^303 + x^300 + x^298 + x^294 + x^288 + x^285 + x^284 + x^281 + x^280 + x^279 + x^277 + x^276 + x^275 + x^273 + x^271 + x^270 + x^269 + x^268 + x^266 + x^261 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^245 + x^244 + x^242 + x^240 + x^238 + x^236 + x^233 + x^231 + x^230 + x^227 + x^226 + x^224 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^216 + x^215 + x^213 + x^212 + x^209 + x^208 + x^207 + x^202 + x^198 + x^195 + x^189 + x^186 + x^183 + x^182 + x^180 + x^179 + x^177 + x^175 + x^172 + x^170 + x^168 + x^167 + x^159 + x^158 + x^154 + x^153 + x^150 + x^149 + x^144 + x^141 + x^140 + x^138 + x^136 + x^135 + x^134 + x^133 + x^132 + x^130 + x^129 + x^126 + x^125 + x^124 + x^123 + x^122 + x^121 + x^117 + x^116 + x^114 + x^113 + x^112 + x^111 + x^110 + x^108 + x^106 + x^105 + x^102 + x^98 + x^97 + x^96 + x^95 + x^92 + x^91 + x^90 + x^87 + x^79 + x^77 + x^74 + x^73 + x^72 + x^69 + x^64 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^53 + x^50 + x^49 + x^47 + x^46 + x^44 + x^43 + x^36 + x^35 + x^30 + x^29 + x^22 + x^16 + 1
+
+40-6-51 369 x^928 + x^898 + x^870 + x^859 + x^840 + x^830 + x^819 + x^790 + x^780 + x^779 + x^771 + x^770 + x^768 + x^761 + x^760 + x^757 + x^752 + x^750 + x^748 + x^742 + x^741 + x^740 + x^739 + x^738 + x^732 + x^728 + x^727 + x^721 + x^719 + x^718 + x^717 + x^712 + x^709 + x^708 + x^702 + x^699 + x^692 + x^690 + x^687 + x^684 + x^678 + x^677 + x^673 + x^672 + x^671 + x^668 + x^666 + x^659 + x^658 + x^657 + x^655 + x^654 + x^653 + x^652 + x^651 + x^648 + x^647 + x^645 + x^644 + x^643 + x^637 + x^636 + x^634 + x^632 + x^631 + x^624 + x^622 + x^621 + x^620 + x^616 + x^614 + x^613 + x^612 + x^611 + x^609 + x^608 + x^607 + x^598 + x^596 + x^594 + x^593 + x^592 + x^591 + x^588 + x^585 + x^583 + x^579 + x^578 + x^576 + x^575 + x^574 + x^573 + x^572 + x^571 + x^570 + x^567 + x^566 + x^563 + x^562 + x^560 + x^557 + x^555 + x^554 + x^549 + x^547 + x^546 + x^544 + x^542 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^529 + x^527 + x^526 + x^522 + x^520 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^508 + x^505 + x^504 + x^500 + x^497 + x^496 + x^494 + x^492 + x^481 + x^477 + x^475 + x^473 + x^471 + x^470 + x^468 + x^467 + x^466 + x^465 + x^464 + x^463 + x^462 + x^460 + x^457 + x^456 + x^453 + x^451 + x^450 + x^449 + x^447 + x^446 + x^444 + x^443 + x^441 + x^436 + x^435 + x^434 + x^429 + x^428 + x^427 + x^423 + x^422 + x^421 + x^419 + x^418 + x^416 + x^414 + x^413 + x^412 + x^410 + x^408 + x^406 + x^405 + x^402 + x^401 + x^400 + x^399 + x^398 + x^396 + x^395 + x^394 + x^393 + x^391 + x^390 + x^388 + x^385 + x^384 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^371 + x^370 + x^367 + x^366 + x^365 + x^363 + x^360 + x^358 + x^355 + x^354 + x^353 + x^352 + x^350 + x^347 + x^344 + x^342 + x^340 + x^339 + x^338 + x^335 + x^334 + x^331 + x^330 + x^328 + x^324 + x^323 + x^322 + x^321 + x^318 + x^316 + x^315 + x^313 + x^307 + x^306 + x^304 + x^303 + x^301 + x^300 + x^299 + x^298 + x^297 + x^290 + x^287 + x^285 + x^283 + x^282 + x^281 + x^280 + x^279 + x^278 + x^276 + x^275 + x^274 + x^270 + x^264 + x^263 + x^262 + x^261 + x^259 + x^258 + x^254 + x^253 + x^252 + x^244 + x^242 + x^241 + x^240 + x^239 + x^237 + x^236 + x^235 + x^230 + x^228 + x^224 + x^220 + x^217 + x^214 + x^210 + x^209 + x^208 + x^206 + x^203 + x^202 + x^201 + x^200 + x^199 + x^196 + x^195 + x^194 + x^192 + x^189 + x^188 + x^186 + x^185 + x^184 + x^181 + x^176 + x^175 + x^173 + x^172 + x^171 + x^170 + x^165 + x^163 + x^161 + x^159 + x^156 + x^154 + x^153 + x^144 + x^143 + x^137 + x^135 + x^134 + x^132 + x^130 + x^129 + x^126 + x^125 + x^122 + x^120 + x^118 + x^114 + x^113 + x^110 + x^109 + x^108 + x^107 + x^98 + x^97 + x^95 + x^92 + x^88 + x^87 + x^86 + x^85 + x^84 + x^83 + x^80 + x^76 + x^74 + x^71 + x^70 + x^69 + x^64 + x^63 + x^62 + x^61 + x^57 + x^53 + x^52 + x^50 + x^46 + x^40 + x^38 + x^37 + x^34 + x^33 + x^32 + x^31 + x^28 + x^25 + x^22 + x^18 + x^6 + 1
+
+48-40-25 371 x^928 + x^898 + x^878 + x^870 + x^851 + x^844 + x^832 + x^828 + x^818 + x^809 + x^808 + x^802 + x^790 + x^782 + x^779 + x^772 + x^755 + x^751 + x^749 + x^744 + x^742 + x^740 + x^738 + x^732 + x^731 + x^728 + x^725 + x^719 + x^718 + x^714 + x^713 + x^712 + x^708 + x^705 + x^695 + x^691 + x^690 + x^688 + x^687 + x^686 + x^684 + x^683 + x^679 + x^676 + x^674 + x^671 + x^668 + x^665 + x^663 + x^662 + x^661 + x^656 + x^655 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^641 + x^640 + x^638 + x^636 + x^635 + x^633 + x^630 + x^627 + x^626 + x^625 + x^624 + x^621 + x^620 + x^619 + x^618 + x^617 + x^614 + x^613 + x^608 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^599 + x^597 + x^596 + x^591 + x^589 + x^586 + x^585 + x^584 + x^582 + x^578 + x^576 + x^572 + x^569 + x^566 + x^564 + x^558 + x^555 + x^553 + x^550 + x^549 + x^548 + x^545 + x^543 + x^541 + x^540 + x^538 + x^537 + x^533 + x^530 + x^527 + x^524 + x^523 + x^521 + x^520 + x^519 + x^517 + x^516 + x^515 + x^513 + x^510 + x^504 + x^503 + x^501 + x^500 + x^498 + x^497 + x^496 + x^494 + x^492 + x^491 + x^488 + x^485 + x^482 + x^478 + x^476 + x^474 + x^473 + x^471 + x^469 + x^468 + x^464 + x^461 + x^460 + x^459 + x^454 + x^450 + x^449 + x^448 + x^444 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^431 + x^428 + x^426 + x^424 + x^420 + x^417 + x^416 + x^413 + x^411 + x^408 + x^407 + x^406 + x^403 + x^400 + x^399 + x^398 + x^397 + x^396 + x^392 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^381 + x^378 + x^374 + x^370 + x^369 + x^368 + x^367 + x^365 + x^364 + x^359 + x^356 + x^354 + x^350 + x^348 + x^346 + x^344 + x^343 + x^342 + x^340 + x^338 + x^337 + x^334 + x^332 + x^330 + x^329 + x^327 + x^322 + x^317 + x^316 + x^314 + x^311 + x^308 + x^307 + x^301 + x^300 + x^299 + x^296 + x^295 + x^292 + x^291 + x^290 + x^286 + x^284 + x^282 + x^279 + x^278 + x^276 + x^273 + x^270 + x^269 + x^265 + x^263 + x^259 + x^258 + x^257 + x^256 + x^255 + x^253 + x^251 + x^249 + x^247 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^238 + x^236 + x^231 + x^230 + x^229 + x^228 + x^226 + x^223 + x^221 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^212 + x^211 + x^210 + x^208 + x^207 + x^206 + x^205 + x^202 + x^200 + x^198 + x^193 + x^192 + x^191 + x^187 + x^186 + x^184 + x^182 + x^179 + x^173 + x^171 + x^169 + x^168 + x^164 + x^163 + x^162 + x^161 + x^157 + x^156 + x^155 + x^154 + x^153 + x^151 + x^149 + x^147 + x^146 + x^145 + x^143 + x^140 + x^137 + x^136 + x^133 + x^127 + x^122 + x^121 + x^119 + x^115 + x^114 + x^112 + x^111 + x^110 + x^108 + x^104 + x^103 + x^101 + x^98 + x^94 + x^88 + x^87 + x^85 + x^83 + x^81 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^73 + x^70 + x^69 + x^68 + x^67 + x^65 + x^63 + x^62 + x^60 + x^59 + x^58 + x^57 + x^56 + x^54 + x^53 + x^52 + x^50 + x^49 + x^47 + x^46 + x^45 + x^41 + x^39 + x^36 + x^34 + x^33 + x^32 + x^31 + x^30 + x^29 + x^28 + x^26 + x^25 + x^21 + x^16 + x^14 + x^4 + 1
+
+19-22-10 373 x^928 + x^898 + x^870 + x^866 + x^842 + x^836 + x^834 + x^821 + x^808 + x^807 + x^806 + x^804 + x^802 + x^794 + x^792 + x^782 + x^778 + x^777 + x^776 + x^770 + x^766 + x^761 + x^757 + x^753 + x^748 + x^743 + x^739 + x^738 + x^736 + x^735 + x^734 + x^732 + x^728 + x^725 + x^722 + x^721 + x^718 + x^716 + x^713 + x^711 + x^710 + x^709 + x^708 + x^705 + x^703 + x^702 + x^693 + x^686 + x^681 + x^680 + x^677 + x^664 + x^662 + x^659 + x^652 + x^651 + x^649 + x^646 + x^644 + x^643 + x^641 + x^638 + x^636 + x^629 + x^627 + x^625 + x^623 + x^622 + x^619 + x^617 + x^616 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^600 + x^597 + x^596 + x^595 + x^592 + x^591 + x^590 + x^586 + x^582 + x^580 + x^577 + x^576 + x^574 + x^572 + x^570 + x^569 + x^567 + x^565 + x^563 + x^562 + x^560 + x^557 + x^556 + x^555 + x^554 + x^552 + x^549 + x^548 + x^546 + x^545 + x^544 + x^542 + x^540 + x^538 + x^536 + x^534 + x^533 + x^532 + x^530 + x^528 + x^525 + x^520 + x^519 + x^518 + x^516 + x^514 + x^513 + x^511 + x^509 + x^504 + x^501 + x^497 + x^496 + x^495 + x^488 + x^487 + x^485 + x^482 + x^481 + x^480 + x^479 + x^478 + x^476 + x^475 + x^474 + x^472 + x^470 + x^468 + x^466 + x^465 + x^463 + x^458 + x^453 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^444 + x^443 + x^439 + x^438 + x^437 + x^436 + x^433 + x^428 + x^424 + x^418 + x^417 + x^414 + x^412 + x^411 + x^408 + x^407 + x^406 + x^404 + x^403 + x^401 + x^400 + x^399 + x^396 + x^395 + x^393 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^384 + x^382 + x^380 + x^379 + x^375 + x^371 + x^370 + x^369 + x^365 + x^363 + x^362 + x^357 + x^355 + x^354 + x^351 + x^348 + x^346 + x^345 + x^344 + x^342 + x^340 + x^338 + x^336 + x^334 + x^331 + x^328 + x^327 + x^326 + x^324 + x^323 + x^322 + x^320 + x^315 + x^308 + x^306 + x^298 + x^295 + x^292 + x^287 + x^286 + x^285 + x^284 + x^282 + x^281 + x^280 + x^279 + x^278 + x^276 + x^274 + x^273 + x^272 + x^270 + x^269 + x^268 + x^267 + x^265 + x^262 + x^258 + x^256 + x^253 + x^252 + x^251 + x^250 + x^246 + x^245 + x^244 + x^243 + x^242 + x^240 + x^239 + x^238 + x^237 + x^235 + x^232 + x^228 + x^226 + x^224 + x^217 + x^215 + x^213 + x^211 + x^210 + x^208 + x^206 + x^201 + x^199 + x^196 + x^195 + x^192 + x^190 + x^187 + x^186 + x^185 + x^184 + x^182 + x^180 + x^178 + x^175 + x^174 + x^173 + x^172 + x^165 + x^160 + x^159 + x^158 + x^157 + x^155 + x^154 + x^153 + x^148 + x^146 + x^145 + x^143 + x^142 + x^137 + x^135 + x^133 + x^132 + x^131 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^117 + x^115 + x^114 + x^113 + x^112 + x^108 + x^107 + x^106 + x^105 + x^103 + x^102 + x^101 + x^100 + x^94 + x^93 + x^92 + x^89 + x^87 + x^86 + x^85 + x^83 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^72 + x^70 + x^67 + x^66 + x^62 + x^61 + x^59 + x^58 + x^57 + x^55 + x^51 + x^50 + x^49 + x^42 + x^41 + x^39 + x^36 + x^34 + x^32 + x^30 + x^26 + x^24 + x^23 + x^22 + x^21 + x^18 + x^16 + x^14 + x^10 + x^9 + x^8 + x^2 + 1
+
+52-17-25 375 x^928 + x^898 + x^870 + x^861 + x^860 + x^859 + x^858 + x^849 + x^848 + x^847 + x^846 + x^842 + x^836 + x^835 + x^831 + x^830 + x^829 + x^828 + x^823 + x^822 + x^811 + x^810 + x^808 + x^807 + x^806 + x^804 + x^800 + x^799 + x^793 + x^792 + x^789 + x^788 + x^786 + x^780 + x^778 + x^777 + x^775 + x^774 + x^770 + x^769 + x^768 + x^764 + x^763 + x^762 + x^758 + x^757 + x^756 + x^755 + x^751 + x^750 + x^744 + x^740 + x^739 + x^738 + x^733 + x^731 + x^728 + x^721 + x^720 + x^716 + x^715 + x^714 + x^713 + x^710 + x^709 + x^702 + x^701 + x^697 + x^696 + x^695 + x^692 + x^688 + x^686 + x^684 + x^683 + x^680 + x^679 + x^678 + x^677 + x^674 + x^673 + x^672 + x^665 + x^662 + x^658 + x^654 + x^647 + x^643 + x^636 + x^635 + x^631 + x^628 + x^626 + x^625 + x^622 + x^621 + x^619 + x^618 + x^617 + x^614 + x^613 + x^612 + x^611 + x^609 + x^608 + x^598 + x^595 + x^591 + x^589 + x^588 + x^587 + x^586 + x^584 + x^582 + x^576 + x^574 + x^571 + x^569 + x^567 + x^564 + x^563 + x^560 + x^557 + x^550 + x^549 + x^548 + x^547 + x^546 + x^544 + x^539 + x^537 + x^536 + x^529 + x^527 + x^526 + x^523 + x^522 + x^521 + x^516 + x^513 + x^512 + x^509 + x^508 + x^505 + x^503 + x^502 + x^499 + x^493 + x^492 + x^491 + x^487 + x^486 + x^484 + x^482 + x^479 + x^478 + x^477 + x^475 + x^474 + x^471 + x^468 + x^467 + x^465 + x^463 + x^462 + x^461 + x^460 + x^455 + x^452 + x^445 + x^443 + x^442 + x^437 + x^433 + x^432 + x^429 + x^427 + x^426 + x^424 + x^423 + x^422 + x^421 + x^417 + x^411 + x^410 + x^408 + x^407 + x^403 + x^402 + x^400 + x^399 + x^393 + x^391 + x^390 + x^389 + x^386 + x^384 + x^381 + x^379 + x^375 + x^373 + x^372 + x^369 + x^367 + x^366 + x^364 + x^363 + x^362 + x^361 + x^360 + x^357 + x^356 + x^353 + x^352 + x^348 + x^345 + x^344 + x^342 + x^341 + x^340 + x^335 + x^332 + x^330 + x^329 + x^328 + x^327 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^310 + x^308 + x^305 + x^302 + x^300 + x^299 + x^298 + x^297 + x^296 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^283 + x^282 + x^281 + x^278 + x^277 + x^276 + x^274 + x^272 + x^269 + x^267 + x^263 + x^262 + x^260 + x^259 + x^256 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^242 + x^241 + x^240 + x^235 + x^234 + x^231 + x^226 + x^225 + x^221 + x^219 + x^214 + x^212 + x^211 + x^209 + x^207 + x^206 + x^205 + x^202 + x^199 + x^198 + x^195 + x^190 + x^189 + x^187 + x^185 + x^182 + x^181 + x^180 + x^179 + x^177 + x^176 + x^175 + x^174 + x^171 + x^169 + x^165 + x^164 + x^163 + x^162 + x^161 + x^160 + x^155 + x^154 + x^153 + x^152 + x^146 + x^145 + x^142 + x^139 + x^137 + x^136 + x^128 + x^127 + x^124 + x^121 + x^120 + x^119 + x^117 + x^114 + x^113 + x^112 + x^110 + x^109 + x^108 + x^104 + x^102 + x^101 + x^99 + x^97 + x^87 + x^85 + x^84 + x^83 + x^82 + x^78 + x^76 + x^73 + x^72 + x^69 + x^64 + x^62 + x^59 + x^52 + x^51 + x^50 + x^49 + x^46 + x^45 + x^44 + x^42 + x^41 + x^40 + x^36 + x^35 + x^33 + x^28 + x^26 + x^25 + x^21 + x^19 + x^13 + x^12 + x^7 + x^6 + 1
+
+35-28-44 377 x^928 + x^898 + x^894 + x^870 + x^859 + x^829 + x^828 + x^825 + x^808 + x^804 + x^800 + x^799 + x^795 + x^794 + x^789 + x^778 + x^774 + x^769 + x^768 + x^759 + x^758 + x^755 + x^754 + x^748 + x^744 + x^739 + x^735 + x^734 + x^727 + x^726 + x^722 + x^718 + x^714 + x^713 + x^709 + x^708 + x^705 + x^704 + x^700 + x^694 + x^691 + x^690 + x^688 + x^687 + x^685 + x^682 + x^681 + x^675 + x^668 + x^665 + x^659 + x^657 + x^656 + x^655 + x^653 + x^652 + x^651 + x^649 + x^647 + x^644 + x^640 + x^638 + x^635 + x^634 + x^631 + x^630 + x^629 + x^628 + x^625 + x^624 + x^619 + x^617 + x^614 + x^613 + x^612 + x^611 + x^610 + x^608 + x^602 + x^599 + x^598 + x^593 + x^592 + x^591 + x^590 + x^586 + x^585 + x^583 + x^582 + x^581 + x^580 + x^579 + x^578 + x^576 + x^575 + x^573 + x^569 + x^566 + x^560 + x^559 + x^558 + x^557 + x^553 + x^552 + x^551 + x^549 + x^542 + x^536 + x^535 + x^533 + x^524 + x^522 + x^521 + x^520 + x^518 + x^517 + x^516 + x^515 + x^512 + x^509 + x^507 + x^506 + x^504 + x^502 + x^500 + x^499 + x^498 + x^497 + x^496 + x^491 + x^489 + x^485 + x^484 + x^483 + x^482 + x^481 + x^480 + x^477 + x^476 + x^474 + x^467 + x^466 + x^465 + x^462 + x^460 + x^459 + x^454 + x^450 + x^447 + x^446 + x^445 + x^443 + x^439 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^421 + x^419 + x^417 + x^413 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^405 + x^404 + x^403 + x^401 + x^400 + x^394 + x^389 + x^386 + x^383 + x^381 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^372 + x^371 + x^369 + x^368 + x^367 + x^366 + x^365 + x^364 + x^362 + x^359 + x^356 + x^349 + x^347 + x^346 + x^345 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^337 + x^336 + x^335 + x^332 + x^331 + x^330 + x^329 + x^325 + x^324 + x^320 + x^319 + x^318 + x^317 + x^316 + x^315 + x^311 + x^309 + x^307 + x^304 + x^303 + x^301 + x^300 + x^298 + x^297 + x^296 + x^295 + x^294 + x^292 + x^291 + x^289 + x^288 + x^285 + x^283 + x^282 + x^281 + x^274 + x^272 + x^271 + x^269 + x^262 + x^261 + x^260 + x^258 + x^257 + x^252 + x^251 + x^250 + x^249 + x^247 + x^246 + x^244 + x^241 + x^236 + x^234 + x^231 + x^230 + x^227 + x^226 + x^219 + x^218 + x^216 + x^215 + x^213 + x^206 + x^205 + x^204 + x^203 + x^202 + x^201 + x^200 + x^198 + x^196 + x^195 + x^194 + x^193 + x^192 + x^190 + x^186 + x^185 + x^184 + x^182 + x^176 + x^174 + x^167 + x^166 + x^164 + x^163 + x^162 + x^161 + x^159 + x^155 + x^154 + x^153 + x^151 + x^150 + x^146 + x^145 + x^143 + x^140 + x^138 + x^135 + x^131 + x^130 + x^129 + x^125 + x^124 + x^123 + x^118 + x^116 + x^113 + x^110 + x^107 + x^101 + x^100 + x^99 + x^95 + x^94 + x^93 + x^92 + x^91 + x^88 + x^86 + x^82 + x^81 + x^80 + x^79 + x^78 + x^76 + x^75 + x^73 + x^72 + x^71 + x^70 + x^69 + x^68 + x^67 + x^65 + x^63 + x^62 + x^60 + x^58 + x^57 + x^56 + x^55 + x^52 + x^50 + x^48 + x^46 + x^44 + x^42 + x^40 + x^39 + x^38 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^24 + x^21 + x^16 + x^13 + x^8 + 1
+
+45-7-6 377 x^928 + x^898 + x^897 + x^870 + x^868 + x^854 + x^853 + x^850 + x^836 + x^835 + x^832 + x^821 + x^810 + x^809 + x^808 + x^807 + x^805 + x^803 + x^802 + x^801 + x^798 + x^794 + x^792 + x^791 + x^790 + x^780 + x^778 + x^775 + x^770 + x^767 + x^766 + x^765 + x^764 + x^760 + x^754 + x^750 + x^743 + x^740 + x^737 + x^735 + x^732 + x^726 + x^723 + x^722 + x^721 + x^720 + x^716 + x^714 + x^710 + x^707 + x^706 + x^703 + x^701 + x^700 + x^699 + x^695 + x^691 + x^689 + x^687 + x^686 + x^685 + x^683 + x^680 + x^676 + x^675 + x^672 + x^671 + x^670 + x^668 + x^667 + x^666 + x^665 + x^662 + x^658 + x^655 + x^653 + x^652 + x^648 + x^644 + x^643 + x^642 + x^637 + x^629 + x^628 + x^627 + x^626 + x^624 + x^621 + x^617 + x^616 + x^612 + x^610 + x^609 + x^608 + x^607 + x^603 + x^602 + x^600 + x^595 + x^594 + x^592 + x^591 + x^589 + x^586 + x^585 + x^582 + x^578 + x^576 + x^574 + x^573 + x^571 + x^570 + x^566 + x^563 + x^561 + x^560 + x^558 + x^557 + x^556 + x^555 + x^554 + x^553 + x^552 + x^551 + x^549 + x^548 + x^545 + x^538 + x^533 + x^530 + x^524 + x^520 + x^519 + x^512 + x^509 + x^508 + x^505 + x^503 + x^502 + x^497 + x^495 + x^493 + x^492 + x^486 + x^485 + x^484 + x^482 + x^480 + x^479 + x^477 + x^472 + x^470 + x^469 + x^466 + x^464 + x^462 + x^460 + x^459 + x^458 + x^456 + x^455 + x^454 + x^452 + x^451 + x^448 + x^446 + x^442 + x^441 + x^440 + x^437 + x^431 + x^430 + x^427 + x^426 + x^425 + x^424 + x^423 + x^420 + x^417 + x^415 + x^414 + x^413 + x^412 + x^410 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^399 + x^395 + x^393 + x^392 + x^384 + x^381 + x^375 + x^370 + x^368 + x^367 + x^364 + x^363 + x^361 + x^360 + x^356 + x^355 + x^354 + x^353 + x^351 + x^349 + x^346 + x^343 + x^341 + x^340 + x^339 + x^335 + x^334 + x^333 + x^330 + x^328 + x^326 + x^325 + x^324 + x^323 + x^319 + x^318 + x^316 + x^315 + x^312 + x^306 + x^303 + x^302 + x^301 + x^299 + x^294 + x^292 + x^291 + x^290 + x^289 + x^283 + x^281 + x^276 + x^275 + x^274 + x^273 + x^271 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^257 + x^255 + x^254 + x^253 + x^252 + x^250 + x^247 + x^246 + x^245 + x^243 + x^241 + x^240 + x^239 + x^235 + x^228 + x^224 + x^223 + x^220 + x^217 + x^216 + x^215 + x^209 + x^205 + x^204 + x^203 + x^202 + x^197 + x^196 + x^195 + x^192 + x^191 + x^189 + x^187 + x^183 + x^181 + x^180 + x^179 + x^178 + x^173 + x^172 + x^170 + x^165 + x^163 + x^161 + x^159 + x^156 + x^155 + x^153 + x^148 + x^146 + x^141 + x^138 + x^134 + x^133 + x^131 + x^130 + x^127 + x^126 + x^125 + x^123 + x^122 + x^119 + x^117 + x^116 + x^110 + x^109 + x^108 + x^107 + x^106 + x^95 + x^93 + x^92 + x^91 + x^88 + x^87 + x^86 + x^84 + x^82 + x^80 + x^79 + x^76 + x^75 + x^73 + x^72 + x^69 + x^68 + x^64 + x^63 + x^61 + x^59 + x^57 + x^55 + x^54 + x^53 + x^51 + x^49 + x^46 + x^43 + x^41 + x^40 + x^36 + x^35 + x^34 + x^33 + x^31 + x^27 + x^25 + x^23 + x^22 + x^21 + x^19 + x^15 + x^13 + x^12 + x^11 + x^10 + x^9 + x^8 + 1
+
+23-49-24 379 x^928 + x^898 + x^872 + x^870 + x^856 + x^843 + x^842 + x^827 + x^826 + x^824 + x^818 + x^813 + x^812 + x^811 + x^797 + x^796 + x^795 + x^792 + x^789 + x^788 + x^781 + x^780 + x^772 + x^767 + x^765 + x^759 + x^757 + x^752 + x^743 + x^742 + x^741 + x^740 + x^737 + x^735 + x^730 + x^729 + x^728 + x^727 + x^724 + x^722 + x^721 + x^720 + x^718 + x^714 + x^712 + x^710 + x^707 + x^706 + x^704 + x^703 + x^702 + x^700 + x^699 + x^698 + x^696 + x^694 + x^692 + x^691 + x^690 + x^689 + x^688 + x^686 + x^682 + x^681 + x^679 + x^677 + x^675 + x^674 + x^665 + x^663 + x^661 + x^660 + x^657 + x^656 + x^655 + x^651 + x^649 + x^647 + x^646 + x^644 + x^642 + x^640 + x^637 + x^635 + x^633 + x^625 + x^622 + x^620 + x^619 + x^617 + x^616 + x^615 + x^613 + x^612 + x^610 + x^609 + x^607 + x^606 + x^605 + x^601 + x^600 + x^597 + x^596 + x^595 + x^593 + x^592 + x^590 + x^588 + x^584 + x^583 + x^582 + x^579 + x^578 + x^574 + x^571 + x^570 + x^567 + x^566 + x^564 + x^561 + x^560 + x^559 + x^558 + x^554 + x^553 + x^547 + x^543 + x^539 + x^536 + x^535 + x^534 + x^533 + x^529 + x^527 + x^526 + x^525 + x^518 + x^516 + x^515 + x^510 + x^509 + x^508 + x^506 + x^505 + x^504 + x^503 + x^499 + x^498 + x^497 + x^495 + x^493 + x^491 + x^489 + x^488 + x^487 + x^486 + x^485 + x^484 + x^482 + x^479 + x^475 + x^473 + x^472 + x^469 + x^468 + x^464 + x^463 + x^462 + x^459 + x^457 + x^455 + x^453 + x^448 + x^446 + x^444 + x^443 + x^442 + x^438 + x^435 + x^431 + x^429 + x^427 + x^424 + x^423 + x^418 + x^416 + x^414 + x^406 + x^404 + x^403 + x^401 + x^397 + x^396 + x^390 + x^387 + x^384 + x^380 + x^377 + x^375 + x^373 + x^369 + x^366 + x^365 + x^364 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^348 + x^346 + x^340 + x^338 + x^336 + x^334 + x^329 + x^326 + x^325 + x^322 + x^320 + x^318 + x^312 + x^307 + x^305 + x^302 + x^301 + x^299 + x^297 + x^296 + x^294 + x^293 + x^291 + x^288 + x^287 + x^286 + x^281 + x^278 + x^277 + x^276 + x^274 + x^273 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^262 + x^261 + x^258 + x^256 + x^255 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^243 + x^240 + x^237 + x^236 + x^235 + x^233 + x^231 + x^230 + x^223 + x^222 + x^220 + x^218 + x^216 + x^212 + x^211 + x^208 + x^207 + x^205 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^195 + x^193 + x^192 + x^191 + x^187 + x^186 + x^183 + x^181 + x^180 + x^179 + x^176 + x^174 + x^173 + x^169 + x^166 + x^161 + x^159 + x^158 + x^157 + x^156 + x^154 + x^152 + x^151 + x^149 + x^145 + x^144 + x^143 + x^142 + x^141 + x^139 + x^136 + x^135 + x^131 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^120 + x^118 + x^117 + x^116 + x^114 + x^111 + x^110 + x^108 + x^107 + x^106 + x^103 + x^100 + x^99 + x^97 + x^96 + x^95 + x^93 + x^92 + x^91 + x^90 + x^87 + x^84 + x^81 + x^80 + x^79 + x^78 + x^77 + x^74 + x^73 + x^71 + x^67 + x^64 + x^61 + x^59 + x^58 + x^54 + x^49 + x^47 + x^44 + x^43 + x^41 + x^38 + x^37 + x^33 + x^30 + x^25 + x^17 + x^16 + x^15 + x^14 + x^12 + x^11 + x^8 + x^7 + x^4 + 1
+
+19-18-26 381 x^928 + x^898 + x^870 + x^844 + x^836 + x^832 + x^820 + x^814 + x^808 + x^802 + x^798 + x^794 + x^791 + x^790 + x^784 + x^778 + x^774 + x^770 + x^769 + x^766 + x^764 + x^761 + x^754 + x^748 + x^743 + x^734 + x^732 + x^731 + x^727 + x^726 + x^724 + x^723 + x^721 + x^718 + x^716 + x^715 + x^713 + x^711 + x^709 + x^706 + x^704 + x^703 + x^702 + x^701 + x^700 + x^699 + x^697 + x^696 + x^695 + x^693 + x^692 + x^691 + x^690 + x^685 + x^684 + x^676 + x^674 + x^667 + x^664 + x^663 + x^658 + x^657 + x^656 + x^654 + x^653 + x^651 + x^650 + x^646 + x^645 + x^644 + x^643 + x^639 + x^638 + x^637 + x^633 + x^631 + x^630 + x^627 + x^626 + x^625 + x^624 + x^620 + x^611 + x^610 + x^607 + x^606 + x^604 + x^603 + x^598 + x^597 + x^595 + x^593 + x^590 + x^589 + x^588 + x^586 + x^585 + x^584 + x^582 + x^580 + x^577 + x^575 + x^570 + x^569 + x^568 + x^563 + x^562 + x^561 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^550 + x^548 + x^547 + x^546 + x^545 + x^542 + x^541 + x^540 + x^539 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^523 + x^522 + x^521 + x^517 + x^515 + x^514 + x^512 + x^510 + x^509 + x^508 + x^506 + x^497 + x^494 + x^493 + x^490 + x^487 + x^486 + x^483 + x^481 + x^479 + x^476 + x^474 + x^472 + x^471 + x^467 + x^465 + x^464 + x^463 + x^462 + x^460 + x^456 + x^454 + x^452 + x^450 + x^449 + x^448 + x^447 + x^445 + x^444 + x^440 + x^439 + x^438 + x^437 + x^436 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^425 + x^424 + x^422 + x^420 + x^419 + x^418 + x^416 + x^414 + x^413 + x^409 + x^407 + x^405 + x^404 + x^402 + x^397 + x^396 + x^392 + x^391 + x^389 + x^386 + x^385 + x^384 + x^381 + x^377 + x^376 + x^373 + x^371 + x^368 + x^366 + x^364 + x^362 + x^360 + x^359 + x^357 + x^355 + x^354 + x^353 + x^352 + x^351 + x^350 + x^349 + x^348 + x^346 + x^343 + x^341 + x^340 + x^338 + x^337 + x^336 + x^334 + x^331 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^320 + x^316 + x^314 + x^313 + x^311 + x^309 + x^307 + x^306 + x^305 + x^304 + x^302 + x^301 + x^299 + x^297 + x^291 + x^289 + x^288 + x^285 + x^283 + x^282 + x^280 + x^279 + x^272 + x^271 + x^270 + x^269 + x^268 + x^264 + x^263 + x^260 + x^259 + x^257 + x^249 + x^245 + x^242 + x^241 + x^238 + x^234 + x^233 + x^232 + x^230 + x^229 + x^227 + x^226 + x^225 + x^223 + x^221 + x^214 + x^211 + x^210 + x^209 + x^206 + x^205 + x^204 + x^203 + x^201 + x^200 + x^199 + x^197 + x^195 + x^188 + x^186 + x^181 + x^180 + x^177 + x^174 + x^173 + x^171 + x^160 + x^159 + x^158 + x^157 + x^154 + x^148 + x^147 + x^144 + x^142 + x^141 + x^140 + x^139 + x^135 + x^134 + x^129 + x^124 + x^123 + x^120 + x^118 + x^117 + x^116 + x^113 + x^112 + x^110 + x^109 + x^108 + x^107 + x^106 + x^104 + x^103 + x^100 + x^97 + x^95 + x^94 + x^89 + x^86 + x^84 + x^83 + x^79 + x^76 + x^75 + x^73 + x^72 + x^70 + x^67 + x^66 + x^65 + x^63 + x^61 + x^60 + x^59 + x^58 + x^56 + x^53 + x^52 + x^51 + x^50 + x^45 + x^41 + x^40 + x^39 + x^37 + x^36 + x^35 + x^29 + x^26 + x^22 + x^19 + x^18 + x^17 + x^16 + x^13 + x^11 + x^6 + 1
+
+26-3-47 381 x^928 + x^898 + x^878 + x^870 + x^869 + x^860 + x^859 + x^858 + x^850 + x^849 + x^848 + x^840 + x^839 + x^838 + x^830 + x^820 + x^818 + x^810 + x^808 + x^807 + x^798 + x^788 + x^780 + x^778 + x^777 + x^769 + x^767 + x^758 + x^750 + x^740 + x^730 + x^729 + x^728 + x^727 + x^721 + x^720 + x^719 + x^717 + x^716 + x^711 + x^701 + x^700 + x^696 + x^690 + x^689 + x^687 + x^686 + x^681 + x^679 + x^678 + x^676 + x^670 + x^668 + x^667 + x^661 + x^660 + x^657 + x^656 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^641 + x^638 + x^637 + x^636 + x^632 + x^629 + x^627 + x^625 + x^622 + x^620 + x^619 + x^617 + x^616 + x^610 + x^607 + x^606 + x^602 + x^601 + x^600 + x^599 + x^597 + x^596 + x^592 + x^591 + x^590 + x^588 + x^587 + x^586 + x^585 + x^581 + x^578 + x^576 + x^572 + x^571 + x^570 + x^567 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^551 + x^550 + x^549 + x^548 + x^546 + x^542 + x^541 + x^536 + x^534 + x^531 + x^530 + x^528 + x^525 + x^523 + x^522 + x^520 + x^519 + x^518 + x^515 + x^514 + x^511 + x^510 + x^509 + x^508 + x^505 + x^504 + x^502 + x^501 + x^500 + x^499 + x^494 + x^493 + x^485 + x^484 + x^481 + x^480 + x^479 + x^477 + x^476 + x^475 + x^473 + x^466 + x^464 + x^462 + x^461 + x^460 + x^458 + x^457 + x^453 + x^447 + x^444 + x^442 + x^441 + x^440 + x^439 + x^438 + x^433 + x^432 + x^429 + x^428 + x^426 + x^425 + x^424 + x^422 + x^421 + x^420 + x^419 + x^418 + x^414 + x^412 + x^411 + x^407 + x^404 + x^401 + x^398 + x^396 + x^393 + x^392 + x^391 + x^389 + x^387 + x^385 + x^383 + x^382 + x^381 + x^380 + x^378 + x^377 + x^374 + x^372 + x^371 + x^368 + x^365 + x^363 + x^362 + x^359 + x^357 + x^356 + x^355 + x^354 + x^350 + x^347 + x^344 + x^343 + x^341 + x^338 + x^337 + x^335 + x^334 + x^333 + x^331 + x^330 + x^329 + x^328 + x^324 + x^322 + x^319 + x^317 + x^314 + x^310 + x^306 + x^300 + x^299 + x^295 + x^294 + x^291 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^282 + x^281 + x^279 + x^278 + x^275 + x^272 + x^271 + x^270 + x^269 + x^266 + x^264 + x^262 + x^260 + x^259 + x^258 + x^254 + x^250 + x^249 + x^247 + x^246 + x^244 + x^243 + x^241 + x^239 + x^237 + x^236 + x^233 + x^232 + x^231 + x^229 + x^227 + x^226 + x^221 + x^220 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^212 + x^210 + x^209 + x^207 + x^206 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^195 + x^193 + x^192 + x^189 + x^188 + x^180 + x^176 + x^174 + x^173 + x^172 + x^170 + x^167 + x^165 + x^164 + x^162 + x^160 + x^157 + x^155 + x^153 + x^152 + x^151 + x^149 + x^148 + x^147 + x^144 + x^142 + x^140 + x^139 + x^136 + x^134 + x^133 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^119 + x^117 + x^115 + x^113 + x^112 + x^110 + x^107 + x^105 + x^101 + x^100 + x^99 + x^98 + x^94 + x^92 + x^91 + x^90 + x^89 + x^87 + x^85 + x^83 + x^81 + x^80 + x^78 + x^77 + x^74 + x^72 + x^71 + x^70 + x^69 + x^65 + x^64 + x^63 + x^62 + x^61 + x^57 + x^56 + x^55 + x^54 + x^53 + x^49 + x^48 + x^42 + x^41 + x^39 + x^36 + x^34 + x^32 + x^31 + x^24 + x^23 + x^21 + x^14 + x^10 + 1
+
+37-33-14 381 x^928 + x^898 + x^874 + x^870 + x^849 + x^845 + x^841 + x^837 + x^836 + x^832 + x^824 + x^820 + x^812 + x^811 + x^804 + x^802 + x^794 + x^789 + x^785 + x^783 + x^781 + x^777 + x^775 + x^771 + x^770 + x^764 + x^761 + x^757 + x^754 + x^751 + x^746 + x^742 + x^741 + x^740 + x^738 + x^736 + x^734 + x^733 + x^731 + x^727 + x^726 + x^725 + x^724 + x^723 + x^721 + x^720 + x^718 + x^717 + x^716 + x^715 + x^714 + x^713 + x^712 + x^711 + x^709 + x^705 + x^704 + x^703 + x^701 + x^695 + x^692 + x^691 + x^690 + x^688 + x^687 + x^686 + x^685 + x^684 + x^682 + x^680 + x^679 + x^676 + x^671 + x^670 + x^665 + x^663 + x^662 + x^661 + x^660 + x^659 + x^653 + x^652 + x^651 + x^650 + x^648 + x^644 + x^643 + x^642 + x^641 + x^637 + x^635 + x^634 + x^631 + x^630 + x^629 + x^627 + x^626 + x^623 + x^622 + x^621 + x^619 + x^617 + x^616 + x^614 + x^613 + x^611 + x^610 + x^603 + x^601 + x^600 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^589 + x^587 + x^585 + x^583 + x^582 + x^579 + x^575 + x^573 + x^571 + x^570 + x^567 + x^566 + x^560 + x^557 + x^556 + x^554 + x^553 + x^552 + x^551 + x^548 + x^546 + x^541 + x^540 + x^538 + x^535 + x^534 + x^531 + x^527 + x^526 + x^525 + x^524 + x^523 + x^517 + x^516 + x^511 + x^509 + x^507 + x^499 + x^496 + x^493 + x^491 + x^490 + x^485 + x^482 + x^481 + x^479 + x^477 + x^475 + x^474 + x^470 + x^469 + x^468 + x^465 + x^462 + x^461 + x^459 + x^458 + x^453 + x^451 + x^446 + x^444 + x^441 + x^436 + x^435 + x^434 + x^432 + x^429 + x^420 + x^419 + x^416 + x^414 + x^411 + x^410 + x^409 + x^407 + x^405 + x^404 + x^403 + x^402 + x^401 + x^397 + x^395 + x^393 + x^392 + x^390 + x^388 + x^384 + x^381 + x^379 + x^376 + x^374 + x^368 + x^367 + x^365 + x^362 + x^361 + x^360 + x^359 + x^357 + x^355 + x^351 + x^349 + x^346 + x^345 + x^344 + x^342 + x^341 + x^339 + x^337 + x^336 + x^335 + x^333 + x^331 + x^326 + x^320 + x^318 + x^316 + x^315 + x^314 + x^313 + x^312 + x^311 + x^310 + x^309 + x^306 + x^304 + x^303 + x^302 + x^301 + x^300 + x^298 + x^297 + x^296 + x^295 + x^294 + x^293 + x^292 + x^290 + x^289 + x^288 + x^284 + x^283 + x^282 + x^278 + x^277 + x^274 + x^273 + x^272 + x^270 + x^266 + x^265 + x^261 + x^258 + x^256 + x^255 + x^254 + x^248 + x^246 + x^245 + x^239 + x^237 + x^234 + x^230 + x^229 + x^225 + x^224 + x^222 + x^221 + x^217 + x^215 + x^214 + x^213 + x^212 + x^208 + x^206 + x^204 + x^203 + x^202 + x^201 + x^199 + x^198 + x^195 + x^194 + x^191 + x^189 + x^188 + x^186 + x^184 + x^182 + x^181 + x^179 + x^177 + x^176 + x^175 + x^171 + x^169 + x^168 + x^162 + x^161 + x^159 + x^157 + x^156 + x^151 + x^150 + x^148 + x^146 + x^145 + x^142 + x^140 + x^139 + x^138 + x^135 + x^134 + x^131 + x^129 + x^126 + x^124 + x^119 + x^118 + x^117 + x^116 + x^108 + x^106 + x^105 + x^103 + x^99 + x^97 + x^93 + x^92 + x^91 + x^90 + x^87 + x^86 + x^84 + x^83 + x^78 + x^76 + x^73 + x^66 + x^65 + x^64 + x^62 + x^61 + x^58 + x^53 + x^52 + x^51 + x^48 + x^47 + x^46 + x^45 + x^44 + x^42 + x^41 + x^38 + x^34 + x^29 + x^28 + x^26 + x^23 + x^16 + x^8 + x^6 + 1
+
+36-46-33 383 x^928 + x^898 + x^870 + x^857 + x^828 + x^827 + x^816 + x^815 + x^809 + x^808 + x^804 + x^797 + x^792 + x^786 + x^785 + x^780 + x^778 + x^775 + x^773 + x^768 + x^767 + x^762 + x^755 + x^751 + x^750 + x^737 + x^734 + x^732 + x^728 + x^727 + x^725 + x^722 + x^716 + x^715 + x^714 + x^710 + x^708 + x^707 + x^704 + x^703 + x^701 + x^698 + x^697 + x^695 + x^689 + x^688 + x^685 + x^681 + x^680 + x^679 + x^678 + x^677 + x^674 + x^665 + x^658 + x^656 + x^651 + x^650 + x^649 + x^648 + x^647 + x^640 + x^637 + x^635 + x^634 + x^633 + x^631 + x^628 + x^626 + x^624 + x^620 + x^619 + x^617 + x^616 + x^610 + x^607 + x^605 + x^603 + x^602 + x^601 + x^598 + x^591 + x^590 + x^587 + x^584 + x^582 + x^580 + x^577 + x^574 + x^573 + x^571 + x^567 + x^563 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^553 + x^551 + x^550 + x^549 + x^548 + x^547 + x^544 + x^542 + x^540 + x^539 + x^538 + x^537 + x^535 + x^534 + x^533 + x^531 + x^528 + x^527 + x^525 + x^519 + x^517 + x^516 + x^515 + x^510 + x^509 + x^508 + x^507 + x^505 + x^500 + x^499 + x^496 + x^495 + x^494 + x^493 + x^489 + x^488 + x^487 + x^486 + x^485 + x^484 + x^482 + x^480 + x^479 + x^477 + x^475 + x^473 + x^470 + x^468 + x^467 + x^466 + x^465 + x^463 + x^461 + x^460 + x^455 + x^451 + x^450 + x^448 + x^444 + x^443 + x^442 + x^439 + x^438 + x^437 + x^435 + x^434 + x^433 + x^427 + x^426 + x^425 + x^423 + x^421 + x^420 + x^419 + x^418 + x^416 + x^413 + x^411 + x^410 + x^408 + x^407 + x^404 + x^402 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^393 + x^387 + x^386 + x^382 + x^379 + x^378 + x^377 + x^376 + x^375 + x^374 + x^372 + x^371 + x^370 + x^369 + x^366 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^357 + x^356 + x^355 + x^354 + x^352 + x^347 + x^346 + x^345 + x^344 + x^343 + x^341 + x^340 + x^336 + x^335 + x^332 + x^330 + x^329 + x^328 + x^325 + x^324 + x^323 + x^322 + x^321 + x^320 + x^318 + x^316 + x^315 + x^312 + x^302 + x^301 + x^298 + x^295 + x^288 + x^287 + x^286 + x^285 + x^280 + x^279 + x^278 + x^275 + x^273 + x^272 + x^270 + x^267 + x^266 + x^264 + x^261 + x^259 + x^258 + x^255 + x^253 + x^252 + x^250 + x^249 + x^248 + x^247 + x^244 + x^243 + x^242 + x^241 + x^240 + x^237 + x^236 + x^235 + x^231 + x^230 + x^228 + x^225 + x^224 + x^222 + x^220 + x^218 + x^217 + x^216 + x^215 + x^212 + x^211 + x^205 + x^204 + x^203 + x^201 + x^196 + x^194 + x^193 + x^192 + x^191 + x^190 + x^187 + x^186 + x^184 + x^183 + x^182 + x^180 + x^179 + x^178 + x^174 + x^173 + x^172 + x^164 + x^163 + x^162 + x^161 + x^160 + x^159 + x^158 + x^156 + x^154 + x^153 + x^150 + x^149 + x^148 + x^146 + x^144 + x^143 + x^140 + x^134 + x^131 + x^127 + x^125 + x^124 + x^120 + x^119 + x^118 + x^116 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^103 + x^100 + x^99 + x^97 + x^96 + x^95 + x^94 + x^91 + x^87 + x^86 + x^83 + x^81 + x^80 + x^78 + x^77 + x^75 + x^74 + x^72 + x^71 + x^69 + x^68 + x^66 + x^64 + x^63 + x^59 + x^57 + x^55 + x^53 + x^48 + x^47 + x^44 + x^42 + x^41 + x^40 + x^37 + x^28 + x^27 + x^26 + x^20 + x^18 + x^16 + 1
+
+40-1-13 383 x^928 + x^898 + x^870 + x^864 + x^861 + x^858 + x^855 + x^852 + x^837 + x^834 + x^825 + x^808 + x^804 + x^801 + x^798 + x^792 + x^791 + x^788 + x^785 + x^778 + x^777 + x^774 + x^773 + x^758 + x^755 + x^752 + x^743 + x^740 + x^738 + x^737 + x^735 + x^734 + x^725 + x^721 + x^719 + x^718 + x^716 + x^715 + x^713 + x^710 + x^707 + x^705 + x^704 + x^703 + x^698 + x^695 + x^691 + x^689 + x^686 + x^682 + x^680 + x^678 + x^677 + x^676 + x^674 + x^673 + x^671 + x^668 + x^667 + x^664 + x^662 + x^661 + x^659 + x^658 + x^656 + x^652 + x^650 + x^648 + x^647 + x^645 + x^644 + x^643 + x^642 + x^641 + x^640 + x^636 + x^633 + x^630 + x^629 + x^628 + x^627 + x^626 + x^623 + x^621 + x^618 + x^615 + x^612 + x^608 + x^607 + x^605 + x^603 + x^602 + x^600 + x^598 + x^596 + x^594 + x^593 + x^588 + x^583 + x^582 + x^579 + x^574 + x^573 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^548 + x^545 + x^544 + x^542 + x^540 + x^537 + x^535 + x^534 + x^533 + x^532 + x^531 + x^530 + x^526 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^513 + x^509 + x^508 + x^507 + x^502 + x^500 + x^499 + x^496 + x^495 + x^491 + x^489 + x^488 + x^485 + x^482 + x^480 + x^478 + x^476 + x^474 + x^471 + x^468 + x^466 + x^463 + x^462 + x^461 + x^460 + x^459 + x^457 + x^456 + x^453 + x^451 + x^450 + x^447 + x^443 + x^440 + x^439 + x^436 + x^435 + x^434 + x^433 + x^432 + x^426 + x^425 + x^424 + x^422 + x^421 + x^419 + x^417 + x^416 + x^410 + x^409 + x^408 + x^406 + x^405 + x^402 + x^401 + x^399 + x^398 + x^396 + x^389 + x^388 + x^387 + x^385 + x^383 + x^382 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^371 + x^368 + x^366 + x^364 + x^363 + x^360 + x^358 + x^356 + x^355 + x^353 + x^350 + x^349 + x^346 + x^345 + x^344 + x^340 + x^339 + x^338 + x^332 + x^331 + x^329 + x^326 + x^324 + x^323 + x^321 + x^316 + x^315 + x^313 + x^312 + x^310 + x^309 + x^307 + x^306 + x^305 + x^303 + x^302 + x^300 + x^299 + x^296 + x^294 + x^293 + x^292 + x^289 + x^288 + x^286 + x^285 + x^283 + x^282 + x^279 + x^277 + x^274 + x^273 + x^272 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^261 + x^259 + x^256 + x^251 + x^249 + x^245 + x^241 + x^240 + x^239 + x^238 + x^236 + x^235 + x^234 + x^232 + x^230 + x^226 + x^222 + x^220 + x^217 + x^215 + x^211 + x^210 + x^208 + x^203 + x^200 + x^199 + x^197 + x^195 + x^194 + x^193 + x^190 + x^187 + x^186 + x^184 + x^183 + x^182 + x^178 + x^176 + x^174 + x^169 + x^168 + x^167 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^154 + x^153 + x^147 + x^142 + x^138 + x^137 + x^129 + x^128 + x^127 + x^126 + x^124 + x^123 + x^121 + x^119 + x^116 + x^115 + x^112 + x^110 + x^109 + x^107 + x^106 + x^103 + x^101 + x^100 + x^99 + x^98 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^85 + x^83 + x^80 + x^79 + x^77 + x^75 + x^73 + x^72 + x^71 + x^63 + x^61 + x^59 + x^58 + x^57 + x^55 + x^51 + x^48 + x^47 + x^46 + x^45 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^29 + x^28 + x^25 + x^23 + x^20 + x^17 + x^11 + x^10 + x^7 + 1
+
+46-53-31 383 x^928 + x^898 + x^896 + x^875 + x^870 + x^864 + x^856 + x^854 + x^848 + x^845 + x^834 + x^833 + x^827 + x^817 + x^814 + x^812 + x^808 + x^807 + x^806 + x^804 + x^801 + x^796 + x^794 + x^791 + x^787 + x^786 + x^778 + x^777 + x^776 + x^774 + x^773 + x^772 + x^770 + x^767 + x^765 + x^764 + x^761 + x^757 + x^756 + x^754 + x^746 + x^745 + x^744 + x^741 + x^735 + x^734 + x^730 + x^727 + x^725 + x^723 + x^716 + x^715 + x^714 + x^713 + x^712 + x^705 + x^704 + x^703 + x^702 + x^697 + x^696 + x^692 + x^688 + x^685 + x^684 + x^683 + x^682 + x^681 + x^674 + x^673 + x^672 + x^671 + x^670 + x^667 + x^666 + x^664 + x^663 + x^661 + x^660 + x^658 + x^655 + x^654 + x^653 + x^652 + x^651 + x^650 + x^645 + x^639 + x^637 + x^634 + x^631 + x^630 + x^626 + x^625 + x^624 + x^621 + x^620 + x^618 + x^615 + x^610 + x^608 + x^607 + x^606 + x^605 + x^604 + x^602 + x^596 + x^594 + x^588 + x^586 + x^584 + x^582 + x^580 + x^578 + x^574 + x^573 + x^571 + x^570 + x^568 + x^567 + x^560 + x^553 + x^551 + x^548 + x^545 + x^543 + x^542 + x^538 + x^537 + x^536 + x^534 + x^533 + x^532 + x^530 + x^529 + x^528 + x^523 + x^521 + x^513 + x^512 + x^509 + x^508 + x^505 + x^502 + x^491 + x^490 + x^489 + x^487 + x^481 + x^479 + x^468 + x^466 + x^465 + x^464 + x^461 + x^460 + x^459 + x^457 + x^455 + x^454 + x^453 + x^451 + x^450 + x^444 + x^442 + x^440 + x^438 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^422 + x^421 + x^416 + x^415 + x^414 + x^412 + x^410 + x^409 + x^408 + x^402 + x^400 + x^399 + x^398 + x^396 + x^395 + x^393 + x^392 + x^391 + x^388 + x^385 + x^384 + x^381 + x^380 + x^379 + x^377 + x^376 + x^374 + x^373 + x^371 + x^368 + x^366 + x^365 + x^364 + x^362 + x^358 + x^357 + x^356 + x^351 + x^348 + x^345 + x^342 + x^339 + x^338 + x^336 + x^334 + x^331 + x^330 + x^328 + x^327 + x^323 + x^320 + x^319 + x^318 + x^312 + x^311 + x^307 + x^306 + x^305 + x^304 + x^303 + x^302 + x^301 + x^298 + x^295 + x^293 + x^292 + x^291 + x^287 + x^286 + x^285 + x^284 + x^283 + x^280 + x^279 + x^278 + x^276 + x^275 + x^271 + x^269 + x^266 + x^264 + x^263 + x^262 + x^260 + x^257 + x^255 + x^254 + x^253 + x^252 + x^251 + x^250 + x^248 + x^242 + x^241 + x^238 + x^234 + x^231 + x^225 + x^223 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^214 + x^211 + x^209 + x^208 + x^207 + x^206 + x^204 + x^200 + x^196 + x^194 + x^191 + x^188 + x^186 + x^185 + x^182 + x^181 + x^178 + x^176 + x^175 + x^174 + x^169 + x^168 + x^166 + x^164 + x^160 + x^159 + x^158 + x^155 + x^154 + x^153 + x^151 + x^149 + x^147 + x^145 + x^143 + x^138 + x^135 + x^132 + x^131 + x^130 + x^128 + x^127 + x^124 + x^123 + x^121 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^111 + x^110 + x^109 + x^106 + x^105 + x^104 + x^101 + x^99 + x^96 + x^87 + x^85 + x^84 + x^83 + x^81 + x^80 + x^79 + x^75 + x^73 + x^70 + x^69 + x^68 + x^67 + x^66 + x^63 + x^61 + x^60 + x^58 + x^56 + x^54 + x^53 + x^51 + x^49 + x^47 + x^45 + x^44 + x^43 + x^42 + x^41 + x^39 + x^36 + x^34 + x^31 + x^30 + x^29 + x^27 + x^24 + x^22 + x^14 + x^13 + x^12 + 1
+
+1-41-10 385 x^928 + x^898 + x^879 + x^870 + x^855 + x^850 + x^849 + x^831 + x^826 + x^825 + x^819 + x^816 + x^808 + x^807 + x^802 + x^801 + x^800 + x^796 + x^792 + x^789 + x^777 + x^776 + x^768 + x^766 + x^762 + x^758 + x^756 + x^754 + x^748 + x^746 + x^744 + x^742 + x^738 + x^736 + x^735 + x^733 + x^729 + x^728 + x^725 + x^720 + x^716 + x^710 + x^705 + x^704 + x^701 + x^700 + x^696 + x^688 + x^686 + x^682 + x^681 + x^680 + x^679 + x^678 + x^677 + x^676 + x^675 + x^674 + x^671 + x^670 + x^669 + x^666 + x^665 + x^661 + x^660 + x^658 + x^655 + x^653 + x^652 + x^649 + x^648 + x^645 + x^640 + x^637 + x^633 + x^629 + x^628 + x^624 + x^623 + x^621 + x^620 + x^619 + x^618 + x^617 + x^616 + x^610 + x^609 + x^607 + x^605 + x^604 + x^601 + x^600 + x^595 + x^591 + x^589 + x^586 + x^584 + x^581 + x^579 + x^575 + x^573 + x^569 + x^568 + x^561 + x^559 + x^556 + x^555 + x^546 + x^542 + x^540 + x^538 + x^537 + x^534 + x^533 + x^531 + x^530 + x^528 + x^526 + x^525 + x^523 + x^518 + x^517 + x^513 + x^511 + x^507 + x^497 + x^496 + x^494 + x^493 + x^491 + x^489 + x^488 + x^487 + x^485 + x^484 + x^483 + x^482 + x^479 + x^477 + x^476 + x^475 + x^474 + x^471 + x^470 + x^468 + x^466 + x^465 + x^464 + x^463 + x^462 + x^461 + x^459 + x^458 + x^454 + x^453 + x^452 + x^451 + x^449 + x^447 + x^446 + x^442 + x^441 + x^440 + x^434 + x^431 + x^428 + x^427 + x^426 + x^424 + x^421 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^408 + x^405 + x^401 + x^400 + x^399 + x^398 + x^395 + x^394 + x^393 + x^392 + x^391 + x^388 + x^386 + x^385 + x^381 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^364 + x^361 + x^360 + x^359 + x^356 + x^354 + x^353 + x^349 + x^348 + x^346 + x^344 + x^340 + x^335 + x^332 + x^330 + x^325 + x^324 + x^321 + x^318 + x^316 + x^315 + x^314 + x^312 + x^310 + x^309 + x^307 + x^304 + x^301 + x^300 + x^299 + x^298 + x^297 + x^295 + x^291 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^281 + x^280 + x^276 + x^274 + x^269 + x^268 + x^267 + x^265 + x^264 + x^261 + x^260 + x^259 + x^257 + x^256 + x^255 + x^254 + x^251 + x^250 + x^245 + x^242 + x^239 + x^236 + x^233 + x^229 + x^227 + x^225 + x^223 + x^222 + x^219 + x^217 + x^214 + x^213 + x^210 + x^207 + x^205 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^192 + x^190 + x^189 + x^181 + x^180 + x^178 + x^177 + x^175 + x^174 + x^173 + x^172 + x^169 + x^168 + x^165 + x^162 + x^159 + x^158 + x^154 + x^153 + x^152 + x^150 + x^148 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^133 + x^132 + x^128 + x^127 + x^124 + x^123 + x^122 + x^121 + x^118 + x^116 + x^106 + x^102 + x^101 + x^98 + x^96 + x^92 + x^91 + x^90 + x^89 + x^88 + x^86 + x^85 + x^84 + x^83 + x^81 + x^80 + x^78 + x^76 + x^73 + x^72 + x^71 + x^69 + x^67 + x^66 + x^65 + x^63 + x^58 + x^54 + x^53 + x^52 + x^51 + x^50 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^30 + x^25 + x^23 + x^21 + x^20 + x^19 + x^17 + x^16 + x^15 + x^12 + x^9 + x^8 + x^4 + 1
+
+11-33-48 385 x^928 + x^898 + x^882 + x^870 + x^860 + x^853 + x^844 + x^835 + x^828 + x^827 + x^822 + x^819 + x^815 + x^811 + x^808 + x^806 + x^805 + x^794 + x^793 + x^786 + x^784 + x^781 + x^778 + x^773 + x^772 + x^769 + x^765 + x^762 + x^760 + x^759 + x^756 + x^755 + x^748 + x^746 + x^743 + x^739 + x^735 + x^734 + x^733 + x^731 + x^729 + x^727 + x^723 + x^718 + x^713 + x^709 + x^707 + x^706 + x^704 + x^702 + x^699 + x^696 + x^693 + x^692 + x^691 + x^686 + x^685 + x^683 + x^679 + x^677 + x^673 + x^670 + x^669 + x^666 + x^657 + x^656 + x^655 + x^649 + x^648 + x^646 + x^641 + x^639 + x^638 + x^635 + x^633 + x^632 + x^630 + x^628 + x^627 + x^625 + x^620 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^600 + x^595 + x^593 + x^592 + x^589 + x^587 + x^584 + x^581 + x^580 + x^579 + x^577 + x^572 + x^570 + x^568 + x^567 + x^566 + x^564 + x^560 + x^559 + x^557 + x^555 + x^554 + x^552 + x^551 + x^546 + x^542 + x^538 + x^535 + x^534 + x^533 + x^531 + x^530 + x^528 + x^526 + x^524 + x^523 + x^520 + x^519 + x^511 + x^509 + x^506 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^495 + x^494 + x^491 + x^490 + x^489 + x^488 + x^487 + x^485 + x^484 + x^479 + x^475 + x^473 + x^466 + x^459 + x^457 + x^456 + x^455 + x^454 + x^451 + x^450 + x^449 + x^448 + x^447 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^433 + x^432 + x^430 + x^428 + x^427 + x^425 + x^423 + x^419 + x^418 + x^417 + x^414 + x^409 + x^408 + x^406 + x^404 + x^402 + x^400 + x^398 + x^397 + x^396 + x^395 + x^393 + x^389 + x^388 + x^385 + x^379 + x^377 + x^375 + x^374 + x^369 + x^365 + x^364 + x^363 + x^362 + x^361 + x^359 + x^355 + x^354 + x^350 + x^348 + x^345 + x^344 + x^339 + x^336 + x^335 + x^334 + x^333 + x^332 + x^331 + x^330 + x^329 + x^328 + x^326 + x^319 + x^318 + x^316 + x^315 + x^314 + x^313 + x^312 + x^309 + x^308 + x^304 + x^303 + x^302 + x^299 + x^298 + x^297 + x^295 + x^294 + x^293 + x^292 + x^291 + x^290 + x^288 + x^285 + x^282 + x^281 + x^279 + x^277 + x^276 + x^274 + x^272 + x^271 + x^270 + x^269 + x^268 + x^267 + x^265 + x^264 + x^262 + x^261 + x^260 + x^257 + x^253 + x^251 + x^250 + x^247 + x^246 + x^243 + x^242 + x^241 + x^240 + x^237 + x^236 + x^233 + x^232 + x^230 + x^229 + x^226 + x^223 + x^222 + x^221 + x^220 + x^217 + x^215 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^203 + x^201 + x^200 + x^198 + x^196 + x^195 + x^193 + x^189 + x^188 + x^186 + x^184 + x^180 + x^179 + x^177 + x^176 + x^170 + x^168 + x^163 + x^162 + x^160 + x^159 + x^158 + x^157 + x^156 + x^154 + x^151 + x^149 + x^148 + x^145 + x^144 + x^141 + x^140 + x^138 + x^137 + x^136 + x^135 + x^134 + x^133 + x^132 + x^131 + x^130 + x^129 + x^125 + x^124 + x^121 + x^117 + x^116 + x^110 + x^109 + x^108 + x^106 + x^104 + x^103 + x^102 + x^99 + x^98 + x^96 + x^95 + x^93 + x^92 + x^90 + x^89 + x^88 + x^85 + x^83 + x^81 + x^78 + x^76 + x^72 + x^71 + x^70 + x^68 + x^67 + x^66 + x^62 + x^59 + x^58 + x^56 + x^51 + x^48 + x^46 + x^45 + x^44 + x^43 + x^41 + x^40 + x^38 + x^37 + x^35 + x^34 + x^33 + x^32 + x^27 + x^22 + x^19 + x^13 + 1
+
+19-8-4 387 x^928 + x^898 + x^870 + x^844 + x^838 + x^834 + x^828 + x^818 + x^814 + x^806 + x^804 + x^803 + x^797 + x^782 + x^778 + x^776 + x^774 + x^773 + x^772 + x^768 + x^767 + x^764 + x^752 + x^751 + x^745 + x^744 + x^742 + x^740 + x^738 + x^736 + x^733 + x^730 + x^721 + x^718 + x^715 + x^714 + x^710 + x^707 + x^704 + x^702 + x^700 + x^699 + x^698 + x^697 + x^694 + x^692 + x^691 + x^688 + x^686 + x^685 + x^682 + x^676 + x^673 + x^671 + x^670 + x^669 + x^666 + x^662 + x^661 + x^658 + x^656 + x^655 + x^654 + x^652 + x^649 + x^648 + x^647 + x^645 + x^644 + x^642 + x^640 + x^638 + x^636 + x^632 + x^631 + x^630 + x^623 + x^622 + x^621 + x^616 + x^614 + x^612 + x^611 + x^606 + x^605 + x^602 + x^598 + x^597 + x^594 + x^593 + x^591 + x^590 + x^588 + x^587 + x^586 + x^584 + x^582 + x^581 + x^579 + x^577 + x^574 + x^572 + x^571 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^559 + x^558 + x^556 + x^553 + x^551 + x^550 + x^549 + x^546 + x^545 + x^543 + x^542 + x^538 + x^536 + x^535 + x^534 + x^533 + x^531 + x^530 + x^529 + x^527 + x^525 + x^524 + x^522 + x^521 + x^520 + x^518 + x^517 + x^513 + x^512 + x^510 + x^509 + x^507 + x^506 + x^505 + x^504 + x^501 + x^500 + x^499 + x^493 + x^492 + x^491 + x^489 + x^488 + x^486 + x^485 + x^484 + x^480 + x^479 + x^478 + x^477 + x^474 + x^473 + x^472 + x^470 + x^468 + x^464 + x^462 + x^458 + x^456 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^441 + x^439 + x^438 + x^437 + x^436 + x^434 + x^433 + x^432 + x^431 + x^429 + x^426 + x^425 + x^424 + x^423 + x^421 + x^419 + x^418 + x^416 + x^414 + x^412 + x^410 + x^407 + x^405 + x^404 + x^398 + x^397 + x^394 + x^393 + x^392 + x^391 + x^387 + x^386 + x^385 + x^382 + x^381 + x^379 + x^377 + x^375 + x^374 + x^369 + x^368 + x^365 + x^364 + x^363 + x^362 + x^361 + x^359 + x^358 + x^356 + x^355 + x^352 + x^351 + x^350 + x^345 + x^343 + x^341 + x^340 + x^338 + x^333 + x^331 + x^330 + x^329 + x^328 + x^327 + x^325 + x^324 + x^323 + x^322 + x^318 + x^315 + x^312 + x^310 + x^308 + x^305 + x^304 + x^303 + x^299 + x^296 + x^295 + x^294 + x^290 + x^289 + x^288 + x^285 + x^284 + x^281 + x^280 + x^275 + x^274 + x^273 + x^271 + x^268 + x^266 + x^264 + x^263 + x^262 + x^261 + x^260 + x^258 + x^256 + x^255 + x^254 + x^251 + x^245 + x^240 + x^237 + x^236 + x^231 + x^230 + x^229 + x^228 + x^223 + x^221 + x^219 + x^218 + x^215 + x^210 + x^208 + x^207 + x^206 + x^204 + x^202 + x^197 + x^196 + x^195 + x^194 + x^193 + x^192 + x^187 + x^186 + x^184 + x^183 + x^182 + x^180 + x^178 + x^177 + x^175 + x^174 + x^169 + x^168 + x^166 + x^165 + x^163 + x^160 + x^159 + x^156 + x^155 + x^152 + x^150 + x^145 + x^140 + x^138 + x^137 + x^136 + x^135 + x^134 + x^133 + x^131 + x^128 + x^127 + x^126 + x^122 + x^121 + x^118 + x^117 + x^114 + x^109 + x^105 + x^102 + x^101 + x^100 + x^99 + x^96 + x^94 + x^93 + x^91 + x^90 + x^89 + x^88 + x^87 + x^81 + x^79 + x^76 + x^74 + x^71 + x^70 + x^64 + x^63 + x^61 + x^59 + x^56 + x^55 + x^49 + x^47 + x^46 + x^44 + x^43 + x^40 + x^35 + x^34 + x^33 + x^31 + x^28 + x^26 + x^23 + x^21 + x^18 + x^13 + 1
+
+36-23-57 387 x^928 + x^898 + x^897 + x^890 + x^870 + x^860 + x^859 + x^854 + x^853 + x^846 + x^836 + x^835 + x^824 + x^816 + x^810 + x^809 + x^808 + x^804 + x^802 + x^792 + x^791 + x^785 + x^784 + x^780 + x^778 + x^777 + x^776 + x^775 + x^774 + x^773 + x^765 + x^755 + x^753 + x^748 + x^747 + x^744 + x^742 + x^733 + x^732 + x^728 + x^725 + x^724 + x^721 + x^716 + x^714 + x^713 + x^703 + x^701 + x^700 + x^699 + x^697 + x^693 + x^692 + x^691 + x^690 + x^689 + x^680 + x^679 + x^675 + x^673 + x^672 + x^666 + x^663 + x^662 + x^661 + x^658 + x^656 + x^655 + x^653 + x^652 + x^649 + x^647 + x^645 + x^642 + x^641 + x^639 + x^638 + x^637 + x^633 + x^630 + x^629 + x^625 + x^620 + x^619 + x^614 + x^613 + x^612 + x^611 + x^610 + x^606 + x^605 + x^604 + x^603 + x^601 + x^600 + x^599 + x^597 + x^593 + x^591 + x^589 + x^587 + x^586 + x^584 + x^583 + x^581 + x^579 + x^576 + x^572 + x^571 + x^566 + x^565 + x^563 + x^559 + x^554 + x^552 + x^549 + x^548 + x^545 + x^544 + x^543 + x^540 + x^535 + x^534 + x^533 + x^531 + x^529 + x^524 + x^522 + x^517 + x^516 + x^513 + x^512 + x^511 + x^509 + x^507 + x^506 + x^505 + x^503 + x^502 + x^496 + x^495 + x^494 + x^492 + x^491 + x^490 + x^489 + x^487 + x^478 + x^477 + x^475 + x^474 + x^472 + x^471 + x^470 + x^469 + x^466 + x^463 + x^461 + x^459 + x^458 + x^457 + x^456 + x^455 + x^454 + x^453 + x^452 + x^448 + x^447 + x^446 + x^444 + x^442 + x^440 + x^439 + x^438 + x^437 + x^434 + x^431 + x^428 + x^427 + x^426 + x^425 + x^424 + x^423 + x^414 + x^409 + x^408 + x^407 + x^403 + x^401 + x^400 + x^396 + x^395 + x^394 + x^390 + x^389 + x^388 + x^387 + x^386 + x^379 + x^378 + x^377 + x^375 + x^374 + x^370 + x^366 + x^360 + x^359 + x^358 + x^357 + x^356 + x^355 + x^353 + x^351 + x^350 + x^349 + x^348 + x^347 + x^345 + x^343 + x^342 + x^341 + x^340 + x^339 + x^338 + x^336 + x^335 + x^330 + x^329 + x^327 + x^325 + x^324 + x^323 + x^322 + x^319 + x^318 + x^315 + x^313 + x^309 + x^305 + x^304 + x^302 + x^300 + x^298 + x^296 + x^291 + x^289 + x^286 + x^285 + x^284 + x^283 + x^282 + x^281 + x^279 + x^275 + x^274 + x^272 + x^271 + x^265 + x^264 + x^263 + x^259 + x^258 + x^257 + x^253 + x^252 + x^249 + x^246 + x^245 + x^244 + x^242 + x^239 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^221 + x^217 + x^216 + x^212 + x^211 + x^209 + x^208 + x^205 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^189 + x^187 + x^186 + x^183 + x^182 + x^181 + x^177 + x^174 + x^172 + x^170 + x^166 + x^164 + x^163 + x^162 + x^160 + x^156 + x^155 + x^152 + x^151 + x^147 + x^144 + x^143 + x^142 + x^141 + x^138 + x^137 + x^135 + x^133 + x^130 + x^129 + x^126 + x^125 + x^123 + x^121 + x^120 + x^117 + x^114 + x^112 + x^107 + x^106 + x^103 + x^102 + x^100 + x^98 + x^95 + x^94 + x^93 + x^91 + x^90 + x^89 + x^87 + x^85 + x^84 + x^82 + x^81 + x^80 + x^78 + x^76 + x^75 + x^71 + x^70 + x^69 + x^68 + x^66 + x^65 + x^61 + x^60 + x^59 + x^58 + x^56 + x^55 + x^51 + x^49 + x^48 + x^46 + x^44 + x^42 + x^36 + x^34 + x^33 + x^32 + x^29 + x^24 + x^23 + x^20 + x^14 + x^13 + x^12 + x^11 + x^10 + 1
+
+44-4-19 389 x^928 + x^898 + x^874 + x^870 + x^836 + x^832 + x^824 + x^812 + x^809 + x^802 + x^794 + x^793 + x^789 + x^785 + x^781 + x^766 + x^764 + x^763 + x^762 + x^759 + x^758 + x^751 + x^750 + x^746 + x^744 + x^742 + x^738 + x^734 + x^733 + x^732 + x^729 + x^721 + x^719 + x^716 + x^715 + x^714 + x^713 + x^710 + x^706 + x^705 + x^703 + x^702 + x^700 + x^699 + x^698 + x^696 + x^693 + x^691 + x^690 + x^689 + x^688 + x^684 + x^680 + x^678 + x^677 + x^674 + x^672 + x^669 + x^667 + x^665 + x^663 + x^662 + x^660 + x^659 + x^658 + x^656 + x^652 + x^651 + x^649 + x^646 + x^645 + x^642 + x^641 + x^640 + x^633 + x^632 + x^630 + x^627 + x^626 + x^622 + x^617 + x^612 + x^611 + x^610 + x^606 + x^605 + x^604 + x^603 + x^602 + x^601 + x^599 + x^597 + x^596 + x^594 + x^593 + x^592 + x^591 + x^582 + x^581 + x^580 + x^578 + x^577 + x^575 + x^574 + x^573 + x^568 + x^567 + x^564 + x^560 + x^559 + x^558 + x^556 + x^554 + x^550 + x^548 + x^547 + x^545 + x^544 + x^541 + x^540 + x^539 + x^538 + x^536 + x^535 + x^534 + x^532 + x^531 + x^529 + x^523 + x^521 + x^518 + x^517 + x^516 + x^514 + x^511 + x^510 + x^508 + x^507 + x^505 + x^504 + x^499 + x^498 + x^495 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^482 + x^481 + x^478 + x^477 + x^476 + x^475 + x^471 + x^470 + x^468 + x^465 + x^464 + x^460 + x^459 + x^455 + x^454 + x^453 + x^451 + x^445 + x^438 + x^434 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^424 + x^423 + x^419 + x^418 + x^417 + x^416 + x^415 + x^413 + x^411 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^402 + x^400 + x^397 + x^395 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^382 + x^380 + x^379 + x^377 + x^376 + x^374 + x^373 + x^370 + x^369 + x^366 + x^365 + x^364 + x^362 + x^360 + x^359 + x^357 + x^356 + x^355 + x^354 + x^352 + x^349 + x^345 + x^342 + x^341 + x^340 + x^338 + x^334 + x^333 + x^326 + x^324 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^304 + x^302 + x^298 + x^297 + x^296 + x^294 + x^293 + x^290 + x^289 + x^287 + x^286 + x^285 + x^279 + x^277 + x^275 + x^273 + x^268 + x^265 + x^264 + x^263 + x^260 + x^258 + x^254 + x^251 + x^249 + x^248 + x^247 + x^245 + x^244 + x^242 + x^241 + x^240 + x^239 + x^232 + x^229 + x^226 + x^225 + x^223 + x^222 + x^220 + x^219 + x^218 + x^215 + x^214 + x^213 + x^212 + x^210 + x^209 + x^206 + x^203 + x^202 + x^199 + x^197 + x^195 + x^194 + x^192 + x^191 + x^189 + x^188 + x^185 + x^184 + x^181 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^167 + x^164 + x^162 + x^160 + x^159 + x^157 + x^156 + x^154 + x^153 + x^152 + x^150 + x^148 + x^145 + x^144 + x^139 + x^138 + x^137 + x^136 + x^133 + x^126 + x^124 + x^123 + x^122 + x^121 + x^120 + x^119 + x^113 + x^111 + x^108 + x^105 + x^104 + x^103 + x^102 + x^101 + x^98 + x^97 + x^96 + x^95 + x^92 + x^86 + x^85 + x^83 + x^81 + x^80 + x^77 + x^74 + x^73 + x^72 + x^71 + x^70 + x^68 + x^67 + x^66 + x^64 + x^62 + x^61 + x^60 + x^59 + x^57 + x^53 + x^51 + x^43 + x^41 + x^40 + x^39 + x^35 + x^30 + x^29 + x^27 + x^26 + x^24 + x^20 + x^18 + x^14 + x^6 + 1
+
+8-3-35 389 x^928 + x^898 + x^895 + x^870 + x^865 + x^835 + x^832 + x^824 + x^821 + x^812 + x^810 + x^808 + x^807 + x^805 + x^804 + x^794 + x^791 + x^788 + x^778 + x^777 + x^774 + x^772 + x^771 + x^763 + x^755 + x^752 + x^750 + x^747 + x^746 + x^742 + x^739 + x^733 + x^731 + x^728 + x^725 + x^722 + x^721 + x^720 + x^719 + x^716 + x^714 + x^713 + x^712 + x^711 + x^708 + x^705 + x^704 + x^701 + x^700 + x^698 + x^695 + x^694 + x^692 + x^689 + x^683 + x^680 + x^675 + x^674 + x^670 + x^668 + x^667 + x^664 + x^662 + x^661 + x^658 + x^656 + x^654 + x^651 + x^650 + x^645 + x^643 + x^640 + x^639 + x^637 + x^635 + x^634 + x^633 + x^631 + x^630 + x^628 + x^621 + x^620 + x^616 + x^615 + x^614 + x^613 + x^608 + x^605 + x^604 + x^602 + x^601 + x^598 + x^597 + x^591 + x^590 + x^588 + x^587 + x^581 + x^579 + x^578 + x^577 + x^576 + x^573 + x^572 + x^571 + x^570 + x^569 + x^568 + x^566 + x^564 + x^563 + x^562 + x^559 + x^557 + x^553 + x^550 + x^549 + x^547 + x^546 + x^540 + x^537 + x^536 + x^534 + x^530 + x^527 + x^526 + x^525 + x^524 + x^522 + x^521 + x^520 + x^519 + x^518 + x^510 + x^509 + x^505 + x^504 + x^498 + x^496 + x^493 + x^492 + x^490 + x^489 + x^488 + x^487 + x^484 + x^483 + x^482 + x^481 + x^480 + x^479 + x^477 + x^475 + x^474 + x^472 + x^470 + x^468 + x^465 + x^464 + x^463 + x^461 + x^458 + x^457 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^448 + x^447 + x^445 + x^441 + x^440 + x^437 + x^435 + x^434 + x^433 + x^432 + x^431 + x^425 + x^421 + x^418 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^404 + x^403 + x^402 + x^399 + x^398 + x^394 + x^393 + x^391 + x^390 + x^389 + x^384 + x^383 + x^381 + x^380 + x^379 + x^378 + x^375 + x^374 + x^372 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^362 + x^358 + x^357 + x^355 + x^354 + x^353 + x^351 + x^349 + x^347 + x^343 + x^342 + x^338 + x^337 + x^336 + x^334 + x^332 + x^329 + x^328 + x^327 + x^326 + x^323 + x^321 + x^320 + x^319 + x^317 + x^315 + x^311 + x^308 + x^305 + x^304 + x^303 + x^300 + x^298 + x^294 + x^293 + x^292 + x^290 + x^283 + x^281 + x^280 + x^279 + x^276 + x^274 + x^273 + x^269 + x^268 + x^267 + x^266 + x^264 + x^263 + x^259 + x^256 + x^248 + x^247 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^235 + x^234 + x^231 + x^228 + x^227 + x^226 + x^225 + x^224 + x^220 + x^219 + x^218 + x^217 + x^216 + x^213 + x^211 + x^210 + x^206 + x^203 + x^200 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^185 + x^184 + x^180 + x^178 + x^176 + x^175 + x^173 + x^170 + x^169 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^154 + x^153 + x^152 + x^147 + x^141 + x^140 + x^138 + x^135 + x^133 + x^132 + x^131 + x^129 + x^127 + x^126 + x^125 + x^119 + x^115 + x^112 + x^111 + x^108 + x^106 + x^99 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^87 + x^84 + x^82 + x^81 + x^78 + x^76 + x^74 + x^69 + x^68 + x^67 + x^65 + x^63 + x^61 + x^58 + x^57 + x^56 + x^55 + x^54 + x^53 + x^51 + x^49 + x^48 + x^47 + x^46 + x^43 + x^40 + x^39 + x^35 + x^34 + x^32 + x^30 + x^28 + x^27 + x^25 + x^24 + x^21 + x^20 + x^15 + x^14 + x^10 + 1
+
+1-12-46 393 x^928 + x^898 + x^896 + x^870 + x^866 + x^836 + x^834 + x^828 + x^826 + x^808 + x^806 + x^804 + x^802 + x^796 + x^794 + x^778 + x^774 + x^767 + x^766 + x^758 + x^756 + x^744 + x^742 + x^740 + x^738 + x^736 + x^732 + x^731 + x^730 + x^727 + x^726 + x^718 + x^712 + x^710 + x^708 + x^707 + x^706 + x^704 + x^703 + x^701 + x^700 + x^699 + x^698 + x^697 + x^696 + x^695 + x^692 + x^686 + x^685 + x^680 + x^676 + x^672 + x^669 + x^668 + x^665 + x^664 + x^662 + x^661 + x^657 + x^656 + x^655 + x^653 + x^647 + x^646 + x^643 + x^640 + x^639 + x^638 + x^635 + x^628 + x^626 + x^623 + x^622 + x^621 + x^615 + x^612 + x^610 + x^609 + x^608 + x^607 + x^605 + x^604 + x^603 + x^602 + x^600 + x^599 + x^598 + x^597 + x^590 + x^589 + x^587 + x^586 + x^584 + x^583 + x^582 + x^581 + x^579 + x^578 + x^577 + x^576 + x^574 + x^573 + x^571 + x^567 + x^563 + x^561 + x^560 + x^559 + x^556 + x^554 + x^550 + x^548 + x^545 + x^544 + x^542 + x^535 + x^530 + x^529 + x^528 + x^526 + x^524 + x^522 + x^521 + x^519 + x^517 + x^516 + x^515 + x^512 + x^508 + x^507 + x^506 + x^505 + x^504 + x^499 + x^498 + x^497 + x^496 + x^495 + x^494 + x^489 + x^488 + x^487 + x^486 + x^484 + x^483 + x^481 + x^477 + x^476 + x^475 + x^474 + x^473 + x^471 + x^469 + x^466 + x^465 + x^464 + x^461 + x^460 + x^459 + x^457 + x^455 + x^452 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^443 + x^442 + x^440 + x^439 + x^438 + x^433 + x^427 + x^425 + x^424 + x^422 + x^421 + x^419 + x^416 + x^415 + x^414 + x^413 + x^412 + x^408 + x^405 + x^404 + x^403 + x^402 + x^399 + x^398 + x^397 + x^396 + x^394 + x^393 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^384 + x^381 + x^380 + x^376 + x^375 + x^374 + x^373 + x^366 + x^363 + x^362 + x^359 + x^358 + x^357 + x^356 + x^355 + x^353 + x^352 + x^351 + x^347 + x^344 + x^343 + x^342 + x^341 + x^339 + x^337 + x^336 + x^333 + x^331 + x^329 + x^328 + x^327 + x^326 + x^325 + x^321 + x^320 + x^317 + x^316 + x^315 + x^312 + x^311 + x^310 + x^307 + x^306 + x^303 + x^300 + x^298 + x^296 + x^295 + x^292 + x^291 + x^290 + x^287 + x^283 + x^279 + x^278 + x^277 + x^276 + x^273 + x^272 + x^271 + x^270 + x^269 + x^263 + x^262 + x^257 + x^256 + x^255 + x^254 + x^252 + x^249 + x^247 + x^245 + x^242 + x^241 + x^240 + x^235 + x^234 + x^233 + x^232 + x^231 + x^230 + x^229 + x^227 + x^225 + x^224 + x^223 + x^222 + x^219 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^211 + x^206 + x^205 + x^203 + x^200 + x^199 + x^196 + x^194 + x^191 + x^186 + x^185 + x^183 + x^180 + x^179 + x^177 + x^176 + x^175 + x^174 + x^172 + x^171 + x^170 + x^169 + x^167 + x^160 + x^159 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^146 + x^145 + x^144 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^134 + x^133 + x^129 + x^126 + x^125 + x^124 + x^122 + x^121 + x^119 + x^118 + x^117 + x^113 + x^111 + x^110 + x^109 + x^108 + x^99 + x^98 + x^97 + x^95 + x^93 + x^92 + x^90 + x^85 + x^78 + x^76 + x^75 + x^70 + x^69 + x^65 + x^64 + x^63 + x^62 + x^59 + x^56 + x^54 + x^53 + x^51 + x^50 + x^49 + x^45 + x^44 + x^42 + x^41 + x^39 + x^36 + x^35 + x^34 + x^32 + x^31 + x^30 + x^23 + x^20 + x^16 + x^13 + x^12 + 1
+
+21-29-14 393 x^928 + x^898 + x^885 + x^870 + x^858 + x^856 + x^855 + x^831 + x^829 + x^828 + x^826 + x^815 + x^813 + x^812 + x^808 + x^804 + x^802 + x^801 + x^799 + x^798 + x^796 + x^788 + x^785 + x^778 + x^777 + x^775 + x^774 + x^772 + x^769 + x^768 + x^766 + x^765 + x^758 + x^752 + x^748 + x^747 + x^742 + x^741 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^726 + x^725 + x^721 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^706 + x^705 + x^702 + x^701 + x^699 + x^698 + x^694 + x^691 + x^687 + x^685 + x^684 + x^682 + x^681 + x^680 + x^679 + x^676 + x^675 + x^674 + x^671 + x^667 + x^664 + x^658 + x^657 + x^655 + x^653 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^644 + x^641 + x^640 + x^637 + x^635 + x^632 + x^627 + x^625 + x^623 + x^622 + x^619 + x^618 + x^617 + x^613 + x^610 + x^608 + x^601 + x^595 + x^593 + x^592 + x^586 + x^585 + x^583 + x^582 + x^577 + x^572 + x^571 + x^570 + x^568 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^553 + x^550 + x^548 + x^545 + x^544 + x^538 + x^537 + x^534 + x^532 + x^529 + x^526 + x^525 + x^521 + x^520 + x^518 + x^512 + x^511 + x^510 + x^508 + x^507 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^485 + x^481 + x^480 + x^477 + x^476 + x^475 + x^466 + x^464 + x^462 + x^461 + x^460 + x^459 + x^458 + x^454 + x^452 + x^451 + x^449 + x^447 + x^446 + x^444 + x^441 + x^440 + x^439 + x^433 + x^431 + x^430 + x^429 + x^427 + x^425 + x^424 + x^422 + x^416 + x^414 + x^412 + x^408 + x^406 + x^403 + x^402 + x^401 + x^399 + x^398 + x^395 + x^393 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^383 + x^381 + x^380 + x^378 + x^375 + x^374 + x^372 + x^371 + x^370 + x^368 + x^367 + x^362 + x^361 + x^358 + x^356 + x^354 + x^353 + x^351 + x^350 + x^347 + x^346 + x^343 + x^340 + x^339 + x^337 + x^335 + x^331 + x^330 + x^329 + x^328 + x^326 + x^325 + x^323 + x^322 + x^319 + x^318 + x^316 + x^315 + x^311 + x^310 + x^309 + x^308 + x^306 + x^304 + x^303 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^287 + x^284 + x^281 + x^280 + x^276 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^249 + x^248 + x^247 + x^246 + x^244 + x^243 + x^241 + x^240 + x^236 + x^234 + x^233 + x^232 + x^229 + x^224 + x^221 + x^220 + x^217 + x^216 + x^215 + x^213 + x^211 + x^210 + x^208 + x^207 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^173 + x^170 + x^169 + x^168 + x^164 + x^162 + x^160 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^146 + x^144 + x^143 + x^142 + x^140 + x^136 + x^134 + x^132 + x^130 + x^129 + x^128 + x^126 + x^123 + x^120 + x^117 + x^112 + x^111 + x^108 + x^107 + x^105 + x^103 + x^100 + x^99 + x^96 + x^95 + x^91 + x^90 + x^89 + x^87 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^76 + x^69 + x^68 + x^67 + x^66 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^52 + x^51 + x^49 + x^48 + x^46 + x^43 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^26 + x^24 + x^21 + x^20 + x^17 + x^13 + 1
+
+37-29-44 393 x^928 + x^898 + x^885 + x^870 + x^858 + x^856 + x^855 + x^831 + x^829 + x^828 + x^826 + x^815 + x^813 + x^812 + x^808 + x^804 + x^802 + x^801 + x^799 + x^798 + x^796 + x^788 + x^785 + x^778 + x^777 + x^775 + x^774 + x^772 + x^769 + x^768 + x^766 + x^765 + x^758 + x^752 + x^748 + x^747 + x^742 + x^741 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^726 + x^725 + x^721 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^706 + x^705 + x^702 + x^701 + x^699 + x^698 + x^694 + x^691 + x^687 + x^685 + x^684 + x^682 + x^681 + x^680 + x^679 + x^676 + x^675 + x^674 + x^671 + x^667 + x^664 + x^658 + x^657 + x^655 + x^653 + x^652 + x^650 + x^649 + x^648 + x^647 + x^646 + x^644 + x^641 + x^640 + x^637 + x^635 + x^632 + x^627 + x^625 + x^623 + x^622 + x^619 + x^618 + x^617 + x^613 + x^610 + x^608 + x^601 + x^595 + x^593 + x^592 + x^586 + x^585 + x^583 + x^582 + x^577 + x^572 + x^571 + x^570 + x^568 + x^565 + x^563 + x^561 + x^559 + x^557 + x^555 + x^553 + x^550 + x^548 + x^545 + x^544 + x^538 + x^537 + x^534 + x^532 + x^529 + x^526 + x^525 + x^521 + x^520 + x^518 + x^512 + x^511 + x^510 + x^508 + x^507 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^485 + x^481 + x^480 + x^477 + x^476 + x^475 + x^466 + x^464 + x^462 + x^461 + x^460 + x^459 + x^458 + x^454 + x^452 + x^451 + x^449 + x^447 + x^446 + x^444 + x^441 + x^440 + x^439 + x^433 + x^431 + x^430 + x^429 + x^427 + x^425 + x^424 + x^422 + x^416 + x^414 + x^412 + x^408 + x^406 + x^403 + x^402 + x^401 + x^399 + x^398 + x^395 + x^393 + x^390 + x^389 + x^387 + x^386 + x^385 + x^384 + x^383 + x^381 + x^380 + x^378 + x^375 + x^374 + x^372 + x^371 + x^370 + x^368 + x^367 + x^362 + x^361 + x^358 + x^356 + x^354 + x^353 + x^351 + x^350 + x^347 + x^346 + x^343 + x^340 + x^339 + x^337 + x^335 + x^331 + x^330 + x^329 + x^328 + x^326 + x^325 + x^323 + x^322 + x^319 + x^318 + x^316 + x^315 + x^311 + x^310 + x^309 + x^308 + x^306 + x^304 + x^303 + x^298 + x^296 + x^295 + x^294 + x^292 + x^291 + x^290 + x^289 + x^287 + x^284 + x^281 + x^280 + x^276 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^249 + x^248 + x^247 + x^246 + x^244 + x^243 + x^241 + x^240 + x^236 + x^234 + x^233 + x^232 + x^229 + x^224 + x^221 + x^220 + x^217 + x^216 + x^215 + x^213 + x^211 + x^210 + x^208 + x^207 + x^200 + x^199 + x^198 + x^197 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^173 + x^170 + x^169 + x^168 + x^164 + x^162 + x^160 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^146 + x^144 + x^143 + x^142 + x^140 + x^136 + x^134 + x^132 + x^130 + x^129 + x^128 + x^126 + x^123 + x^120 + x^117 + x^112 + x^111 + x^108 + x^107 + x^105 + x^103 + x^100 + x^99 + x^96 + x^95 + x^91 + x^90 + x^89 + x^87 + x^86 + x^84 + x^83 + x^81 + x^79 + x^78 + x^76 + x^69 + x^68 + x^67 + x^66 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^52 + x^51 + x^49 + x^48 + x^46 + x^43 + x^40 + x^38 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^30 + x^29 + x^28 + x^27 + x^26 + x^24 + x^21 + x^20 + x^17 + x^13 + 1
+
+7-48-42 393 x^928 + x^898 + x^892 + x^870 + x^862 + x^843 + x^820 + x^813 + x^808 + x^800 + x^794 + x^784 + x^783 + x^780 + x^778 + x^774 + x^771 + x^770 + x^767 + x^760 + x^757 + x^753 + x^750 + x^748 + x^743 + x^741 + x^740 + x^737 + x^731 + x^727 + x^724 + x^723 + x^718 + x^713 + x^707 + x^705 + x^704 + x^701 + x^700 + x^697 + x^695 + x^693 + x^688 + x^684 + x^683 + x^682 + x^681 + x^678 + x^677 + x^674 + x^671 + x^669 + x^667 + x^664 + x^663 + x^660 + x^653 + x^652 + x^651 + x^650 + x^649 + x^645 + x^644 + x^641 + x^639 + x^638 + x^637 + x^634 + x^633 + x^630 + x^628 + x^625 + x^623 + x^621 + x^620 + x^619 + x^615 + x^612 + x^611 + x^608 + x^607 + x^605 + x^604 + x^603 + x^599 + x^595 + x^593 + x^585 + x^584 + x^581 + x^580 + x^578 + x^577 + x^575 + x^573 + x^572 + x^569 + x^568 + x^565 + x^564 + x^563 + x^561 + x^558 + x^557 + x^551 + x^550 + x^548 + x^547 + x^544 + x^538 + x^537 + x^534 + x^533 + x^532 + x^530 + x^529 + x^524 + x^522 + x^521 + x^519 + x^518 + x^516 + x^515 + x^514 + x^513 + x^512 + x^510 + x^508 + x^506 + x^505 + x^502 + x^501 + x^500 + x^499 + x^496 + x^493 + x^492 + x^491 + x^488 + x^487 + x^483 + x^482 + x^481 + x^479 + x^478 + x^476 + x^475 + x^474 + x^473 + x^472 + x^471 + x^470 + x^469 + x^467 + x^463 + x^460 + x^458 + x^453 + x^452 + x^451 + x^447 + x^446 + x^445 + x^439 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^428 + x^427 + x^425 + x^421 + x^420 + x^419 + x^417 + x^415 + x^413 + x^412 + x^410 + x^407 + x^406 + x^405 + x^404 + x^402 + x^400 + x^397 + x^395 + x^394 + x^393 + x^392 + x^391 + x^390 + x^388 + x^385 + x^381 + x^378 + x^377 + x^376 + x^374 + x^373 + x^370 + x^369 + x^368 + x^366 + x^365 + x^364 + x^363 + x^361 + x^358 + x^356 + x^355 + x^354 + x^351 + x^350 + x^348 + x^347 + x^344 + x^341 + x^340 + x^337 + x^335 + x^334 + x^329 + x^326 + x^325 + x^324 + x^322 + x^321 + x^319 + x^318 + x^314 + x^312 + x^311 + x^310 + x^309 + x^308 + x^307 + x^303 + x^302 + x^301 + x^298 + x^293 + x^292 + x^291 + x^288 + x^281 + x^280 + x^279 + x^278 + x^275 + x^271 + x^270 + x^267 + x^265 + x^264 + x^263 + x^262 + x^261 + x^260 + x^259 + x^258 + x^257 + x^256 + x^253 + x^252 + x^251 + x^250 + x^249 + x^248 + x^247 + x^244 + x^243 + x^242 + x^240 + x^237 + x^236 + x^233 + x^227 + x^226 + x^224 + x^222 + x^221 + x^220 + x^219 + x^218 + x^217 + x^216 + x^213 + x^212 + x^210 + x^208 + x^207 + x^206 + x^205 + x^202 + x^201 + x^200 + x^197 + x^195 + x^194 + x^193 + x^192 + x^191 + x^190 + x^189 + x^186 + x^184 + x^183 + x^182 + x^181 + x^178 + x^177 + x^176 + x^170 + x^168 + x^167 + x^166 + x^162 + x^159 + x^157 + x^149 + x^148 + x^147 + x^143 + x^141 + x^139 + x^138 + x^136 + x^135 + x^131 + x^127 + x^121 + x^119 + x^117 + x^114 + x^110 + x^109 + x^107 + x^103 + x^99 + x^98 + x^96 + x^95 + x^94 + x^92 + x^90 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^82 + x^80 + x^79 + x^78 + x^77 + x^76 + x^74 + x^71 + x^69 + x^68 + x^66 + x^64 + x^62 + x^61 + x^58 + x^57 + x^53 + x^50 + x^46 + x^44 + x^43 + x^42 + x^41 + x^40 + x^37 + x^35 + x^34 + x^32 + x^31 + x^29 + x^27 + x^26 + x^25 + x^22 + x^20 + x^16 + x^12 + x^10 + 1
+
+57-51-22 397 x^928 + x^898 + x^895 + x^870 + x^866 + x^865 + x^862 + x^860 + x^857 + x^835 + x^833 + x^832 + x^828 + x^822 + x^819 + x^810 + x^808 + x^805 + x^797 + x^796 + x^791 + x^790 + x^789 + x^786 + x^784 + x^782 + x^781 + x^778 + x^777 + x^773 + x^767 + x^766 + x^762 + x^757 + x^752 + x^743 + x^742 + x^737 + x^734 + x^717 + x^715 + x^713 + x^708 + x^707 + x^706 + x^705 + x^703 + x^702 + x^701 + x^698 + x^696 + x^690 + x^688 + x^685 + x^683 + x^682 + x^680 + x^677 + x^673 + x^671 + x^668 + x^667 + x^666 + x^663 + x^662 + x^661 + x^656 + x^654 + x^653 + x^649 + x^647 + x^646 + x^645 + x^643 + x^637 + x^635 + x^632 + x^630 + x^629 + x^627 + x^626 + x^625 + x^624 + x^622 + x^619 + x^613 + x^610 + x^608 + x^602 + x^597 + x^594 + x^593 + x^591 + x^590 + x^587 + x^586 + x^584 + x^583 + x^582 + x^580 + x^577 + x^575 + x^574 + x^573 + x^570 + x^569 + x^568 + x^562 + x^556 + x^553 + x^552 + x^551 + x^550 + x^547 + x^546 + x^545 + x^543 + x^541 + x^539 + x^538 + x^535 + x^534 + x^533 + x^528 + x^527 + x^526 + x^524 + x^522 + x^521 + x^515 + x^512 + x^509 + x^505 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^497 + x^493 + x^491 + x^483 + x^480 + x^477 + x^474 + x^473 + x^472 + x^471 + x^470 + x^468 + x^467 + x^463 + x^459 + x^458 + x^457 + x^455 + x^453 + x^452 + x^451 + x^448 + x^447 + x^446 + x^445 + x^444 + x^443 + x^440 + x^439 + x^436 + x^435 + x^434 + x^432 + x^430 + x^429 + x^428 + x^427 + x^426 + x^423 + x^422 + x^421 + x^420 + x^417 + x^416 + x^415 + x^414 + x^413 + x^411 + x^410 + x^407 + x^406 + x^403 + x^401 + x^400 + x^391 + x^390 + x^387 + x^386 + x^385 + x^381 + x^380 + x^379 + x^377 + x^374 + x^373 + x^370 + x^369 + x^362 + x^359 + x^357 + x^356 + x^355 + x^354 + x^349 + x^346 + x^345 + x^344 + x^343 + x^340 + x^339 + x^338 + x^337 + x^336 + x^334 + x^331 + x^330 + x^328 + x^323 + x^322 + x^321 + x^319 + x^318 + x^317 + x^316 + x^314 + x^313 + x^312 + x^311 + x^310 + x^305 + x^303 + x^299 + x^295 + x^294 + x^293 + x^290 + x^289 + x^286 + x^285 + x^284 + x^281 + x^280 + x^278 + x^275 + x^272 + x^271 + x^269 + x^267 + x^266 + x^263 + x^262 + x^261 + x^260 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^252 + x^251 + x^247 + x^246 + x^241 + x^240 + x^239 + x^238 + x^236 + x^233 + x^232 + x^230 + x^228 + x^224 + x^223 + x^220 + x^216 + x^215 + x^213 + x^212 + x^211 + x^208 + x^206 + x^205 + x^204 + x^201 + x^199 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^188 + x^187 + x^186 + x^185 + x^184 + x^182 + x^179 + x^178 + x^176 + x^172 + x^171 + x^170 + x^169 + x^168 + x^167 + x^166 + x^163 + x^162 + x^161 + x^160 + x^157 + x^156 + x^155 + x^153 + x^152 + x^148 + x^145 + x^142 + x^140 + x^139 + x^137 + x^134 + x^133 + x^131 + x^123 + x^119 + x^118 + x^114 + x^112 + x^111 + x^110 + x^108 + x^107 + x^105 + x^104 + x^102 + x^99 + x^98 + x^95 + x^94 + x^93 + x^89 + x^88 + x^86 + x^84 + x^82 + x^80 + x^78 + x^76 + x^73 + x^71 + x^70 + x^68 + x^67 + x^66 + x^64 + x^62 + x^60 + x^59 + x^57 + x^53 + x^52 + x^49 + x^48 + x^47 + x^46 + x^40 + x^37 + x^36 + x^35 + x^34 + x^32 + x^31 + x^28 + x^26 + x^25 + x^24 + x^22 + x^20 + x^19 + x^18 + x^15 + x^10 + x^8 + x^5 + 1
+
+41-40-20 399 x^928 + x^898 + x^870 + x^846 + x^844 + x^821 + x^820 + x^816 + x^814 + x^808 + x^804 + x^801 + x^800 + x^798 + x^795 + x^778 + x^771 + x^770 + x^769 + x^768 + x^765 + x^760 + x^749 + x^748 + x^744 + x^743 + x^741 + x^738 + x^734 + x^729 + x^726 + x^719 + x^717 + x^716 + x^715 + x^714 + x^713 + x^712 + x^711 + x^710 + x^709 + x^706 + x^704 + x^703 + x^702 + x^701 + x^694 + x^693 + x^691 + x^690 + x^685 + x^684 + x^682 + x^681 + x^680 + x^678 + x^677 + x^676 + x^675 + x^674 + x^673 + x^671 + x^669 + x^667 + x^665 + x^661 + x^660 + x^659 + x^658 + x^656 + x^652 + x^651 + x^649 + x^648 + x^643 + x^642 + x^639 + x^637 + x^634 + x^631 + x^629 + x^628 + x^624 + x^620 + x^619 + x^618 + x^617 + x^616 + x^615 + x^614 + x^613 + x^611 + x^610 + x^605 + x^604 + x^603 + x^601 + x^599 + x^598 + x^595 + x^594 + x^593 + x^590 + x^589 + x^585 + x^584 + x^583 + x^579 + x^577 + x^575 + x^573 + x^572 + x^571 + x^570 + x^569 + x^566 + x^564 + x^562 + x^561 + x^560 + x^557 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^547 + x^545 + x^542 + x^540 + x^539 + x^538 + x^537 + x^536 + x^535 + x^533 + x^532 + x^530 + x^529 + x^524 + x^518 + x^516 + x^514 + x^513 + x^512 + x^510 + x^509 + x^504 + x^503 + x^501 + x^493 + x^490 + x^489 + x^487 + x^486 + x^485 + x^484 + x^481 + x^479 + x^478 + x^475 + x^473 + x^471 + x^470 + x^468 + x^467 + x^466 + x^462 + x^460 + x^455 + x^454 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^439 + x^438 + x^436 + x^430 + x^429 + x^424 + x^423 + x^420 + x^419 + x^418 + x^415 + x^414 + x^413 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^403 + x^402 + x^400 + x^398 + x^397 + x^396 + x^395 + x^394 + x^392 + x^391 + x^389 + x^387 + x^386 + x^385 + x^383 + x^382 + x^381 + x^379 + x^375 + x^374 + x^369 + x^367 + x^366 + x^365 + x^363 + x^360 + x^359 + x^358 + x^357 + x^355 + x^354 + x^351 + x^339 + x^338 + x^337 + x^336 + x^335 + x^334 + x^332 + x^330 + x^329 + x^323 + x^320 + x^317 + x^315 + x^312 + x^311 + x^309 + x^305 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^292 + x^291 + x^288 + x^286 + x^285 + x^284 + x^283 + x^282 + x^280 + x^279 + x^278 + x^273 + x^268 + x^267 + x^264 + x^263 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^250 + x^249 + x^248 + x^244 + x^243 + x^242 + x^238 + x^237 + x^236 + x^234 + x^233 + x^231 + x^230 + x^222 + x^218 + x^215 + x^214 + x^211 + x^208 + x^206 + x^205 + x^201 + x^200 + x^198 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^185 + x^182 + x^179 + x^176 + x^174 + x^173 + x^164 + x^163 + x^162 + x^159 + x^158 + x^156 + x^155 + x^152 + x^150 + x^148 + x^142 + x^140 + x^139 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^131 + x^128 + x^124 + x^122 + x^121 + x^120 + x^119 + x^117 + x^116 + x^114 + x^111 + x^110 + x^108 + x^107 + x^105 + x^104 + x^103 + x^101 + x^95 + x^94 + x^93 + x^91 + x^89 + x^88 + x^87 + x^84 + x^83 + x^82 + x^81 + x^80 + x^79 + x^78 + x^77 + x^76 + x^74 + x^73 + x^72 + x^66 + x^65 + x^64 + x^59 + x^57 + x^56 + x^53 + x^49 + x^47 + x^44 + x^43 + x^39 + x^38 + x^37 + x^34 + x^33 + x^32 + x^31 + x^28 + x^23 + x^22 + x^19 + x^12 + x^8 + 1
+
+55-27-24 399 x^928 + x^898 + x^864 + x^847 + x^846 + x^834 + x^824 + x^818 + x^817 + x^816 + x^812 + x^810 + x^808 + x^806 + x^801 + x^800 + x^795 + x^794 + x^788 + x^783 + x^781 + x^777 + x^776 + x^775 + x^771 + x^765 + x^764 + x^753 + x^750 + x^749 + x^747 + x^746 + x^745 + x^743 + x^742 + x^741 + x^737 + x^734 + x^731 + x^728 + x^726 + x^725 + x^724 + x^721 + x^719 + x^717 + x^716 + x^714 + x^712 + x^706 + x^704 + x^703 + x^702 + x^701 + x^699 + x^698 + x^697 + x^695 + x^694 + x^691 + x^690 + x^688 + x^687 + x^684 + x^683 + x^681 + x^680 + x^673 + x^672 + x^670 + x^667 + x^666 + x^664 + x^663 + x^661 + x^659 + x^657 + x^655 + x^650 + x^649 + x^647 + x^640 + x^639 + x^637 + x^636 + x^634 + x^630 + x^626 + x^625 + x^623 + x^622 + x^620 + x^618 + x^617 + x^615 + x^612 + x^611 + x^609 + x^608 + x^607 + x^605 + x^604 + x^602 + x^600 + x^599 + x^596 + x^594 + x^592 + x^590 + x^587 + x^581 + x^578 + x^576 + x^575 + x^574 + x^570 + x^567 + x^566 + x^565 + x^564 + x^563 + x^561 + x^560 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^548 + x^543 + x^537 + x^536 + x^533 + x^532 + x^531 + x^529 + x^528 + x^527 + x^525 + x^524 + x^523 + x^522 + x^519 + x^518 + x^516 + x^515 + x^514 + x^513 + x^512 + x^511 + x^509 + x^507 + x^505 + x^500 + x^498 + x^497 + x^496 + x^494 + x^489 + x^486 + x^481 + x^480 + x^479 + x^476 + x^471 + x^469 + x^467 + x^466 + x^463 + x^459 + x^455 + x^451 + x^450 + x^449 + x^448 + x^447 + x^445 + x^444 + x^441 + x^440 + x^432 + x^430 + x^429 + x^428 + x^426 + x^424 + x^420 + x^418 + x^416 + x^415 + x^413 + x^411 + x^408 + x^406 + x^405 + x^404 + x^400 + x^398 + x^392 + x^390 + x^387 + x^386 + x^382 + x^379 + x^378 + x^377 + x^376 + x^374 + x^373 + x^371 + x^370 + x^368 + x^367 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^351 + x^350 + x^344 + x^343 + x^341 + x^340 + x^339 + x^338 + x^337 + x^332 + x^331 + x^329 + x^327 + x^323 + x^321 + x^320 + x^318 + x^317 + x^314 + x^313 + x^312 + x^311 + x^309 + x^308 + x^306 + x^304 + x^301 + x^300 + x^299 + x^296 + x^295 + x^294 + x^291 + x^290 + x^287 + x^286 + x^285 + x^280 + x^275 + x^274 + x^271 + x^270 + x^268 + x^264 + x^263 + x^258 + x^257 + x^256 + x^254 + x^252 + x^249 + x^248 + x^246 + x^245 + x^242 + x^241 + x^239 + x^238 + x^236 + x^233 + x^231 + x^228 + x^226 + x^225 + x^222 + x^219 + x^218 + x^217 + x^216 + x^215 + x^213 + x^210 + x^209 + x^207 + x^205 + x^203 + x^202 + x^198 + x^197 + x^196 + x^193 + x^192 + x^189 + x^188 + x^187 + x^184 + x^183 + x^182 + x^181 + x^179 + x^178 + x^177 + x^175 + x^172 + x^171 + x^170 + x^169 + x^164 + x^162 + x^161 + x^160 + x^159 + x^155 + x^154 + x^152 + x^151 + x^148 + x^147 + x^143 + x^140 + x^139 + x^137 + x^134 + x^133 + x^132 + x^131 + x^126 + x^125 + x^120 + x^119 + x^118 + x^117 + x^113 + x^111 + x^110 + x^108 + x^104 + x^102 + x^101 + x^100 + x^97 + x^96 + x^90 + x^89 + x^85 + x^82 + x^81 + x^77 + x^76 + x^73 + x^69 + x^68 + x^67 + x^65 + x^64 + x^63 + x^62 + x^61 + x^55 + x^54 + x^53 + x^52 + x^49 + x^47 + x^46 + x^40 + x^39 + x^37 + x^36 + x^35 + x^34 + x^33 + x^32 + x^31 + x^29 + x^26 + x^25 + x^24 + x^23 + x^22 + x^19 + x^17 + x^16 + x^12 + x^9 + x^8 + x^5 + 1
+
+39-32-32 401 x^928 + x^898 + x^870 + x^867 + x^842 + x^837 + x^836 + x^832 + x^807 + x^806 + x^805 + x^802 + x^801 + x^780 + x^778 + x^775 + x^773 + x^771 + x^770 + x^768 + x^766 + x^758 + x^752 + x^749 + x^747 + x^740 + x^730 + x^724 + x^721 + x^719 + x^717 + x^716 + x^715 + x^714 + x^713 + x^711 + x^709 + x^708 + x^707 + x^704 + x^702 + x^700 + x^696 + x^693 + x^691 + x^689 + x^687 + x^686 + x^685 + x^683 + x^682 + x^680 + x^679 + x^677 + x^676 + x^674 + x^670 + x^669 + x^668 + x^665 + x^663 + x^661 + x^660 + x^659 + x^655 + x^653 + x^652 + x^651 + x^648 + x^647 + x^646 + x^645 + x^644 + x^642 + x^641 + x^640 + x^639 + x^638 + x^637 + x^635 + x^634 + x^633 + x^632 + x^631 + x^630 + x^625 + x^624 + x^620 + x^618 + x^615 + x^613 + x^611 + x^606 + x^605 + x^604 + x^602 + x^599 + x^597 + x^596 + x^593 + x^592 + x^591 + x^590 + x^589 + x^585 + x^584 + x^583 + x^580 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^571 + x^570 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^556 + x^554 + x^552 + x^549 + x^548 + x^547 + x^546 + x^544 + x^538 + x^536 + x^535 + x^534 + x^533 + x^530 + x^529 + x^528 + x^527 + x^526 + x^525 + x^524 + x^521 + x^519 + x^517 + x^516 + x^514 + x^513 + x^512 + x^510 + x^509 + x^507 + x^506 + x^504 + x^502 + x^500 + x^499 + x^498 + x^497 + x^493 + x^492 + x^490 + x^489 + x^485 + x^484 + x^481 + x^476 + x^475 + x^473 + x^467 + x^463 + x^462 + x^461 + x^459 + x^456 + x^453 + x^450 + x^449 + x^448 + x^445 + x^443 + x^442 + x^440 + x^438 + x^436 + x^433 + x^432 + x^431 + x^430 + x^429 + x^427 + x^421 + x^420 + x^419 + x^416 + x^415 + x^414 + x^413 + x^411 + x^410 + x^408 + x^407 + x^406 + x^405 + x^403 + x^400 + x^398 + x^397 + x^396 + x^394 + x^390 + x^389 + x^388 + x^385 + x^384 + x^383 + x^379 + x^376 + x^374 + x^373 + x^372 + x^370 + x^369 + x^368 + x^364 + x^362 + x^358 + x^355 + x^354 + x^353 + x^351 + x^348 + x^347 + x^344 + x^343 + x^339 + x^337 + x^336 + x^334 + x^333 + x^329 + x^328 + x^323 + x^321 + x^320 + x^319 + x^318 + x^317 + x^315 + x^314 + x^311 + x^309 + x^307 + x^306 + x^304 + x^302 + x^300 + x^297 + x^295 + x^294 + x^291 + x^289 + x^287 + x^285 + x^284 + x^283 + x^282 + x^281 + x^280 + x^278 + x^277 + x^276 + x^270 + x^269 + x^268 + x^267 + x^263 + x^261 + x^259 + x^257 + x^255 + x^253 + x^252 + x^250 + x^248 + x^247 + x^245 + x^244 + x^242 + x^241 + x^240 + x^238 + x^234 + x^233 + x^230 + x^227 + x^226 + x^224 + x^220 + x^219 + x^217 + x^216 + x^215 + x^209 + x^208 + x^207 + x^206 + x^205 + x^204 + x^203 + x^201 + x^199 + x^198 + x^197 + x^196 + x^193 + x^191 + x^187 + x^184 + x^183 + x^182 + x^173 + x^172 + x^169 + x^167 + x^166 + x^165 + x^162 + x^161 + x^160 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^151 + x^149 + x^147 + x^141 + x^138 + x^137 + x^136 + x^135 + x^134 + x^131 + x^129 + x^126 + x^125 + x^122 + x^121 + x^117 + x^116 + x^113 + x^110 + x^109 + x^108 + x^104 + x^102 + x^101 + x^100 + x^98 + x^97 + x^95 + x^94 + x^87 + x^83 + x^82 + x^78 + x^77 + x^74 + x^73 + x^72 + x^70 + x^69 + x^66 + x^65 + x^62 + x^60 + x^55 + x^54 + x^52 + x^51 + x^49 + x^46 + x^45 + x^41 + x^40 + x^37 + x^33 + x^31 + x^29 + x^27 + x^26 + x^24 + x^20 + x^18 + x^17 + x^15 + x^6 + 1
+
+40-7-11 401 x^928 + x^898 + x^897 + x^882 + x^870 + x^866 + x^860 + x^854 + x^852 + x^851 + x^836 + x^832 + x^830 + x^829 + x^826 + x^824 + x^820 + x^814 + x^812 + x^811 + x^808 + x^806 + x^804 + x^800 + x^796 + x^793 + x^792 + x^790 + x^786 + x^780 + x^778 + x^777 + x^774 + x^770 + x^769 + x^767 + x^762 + x^761 + x^760 + x^756 + x^749 + x^748 + x^746 + x^742 + x^736 + x^733 + x^730 + x^728 + x^726 + x^725 + x^724 + x^723 + x^719 + x^718 + x^717 + x^716 + x^715 + x^712 + x^709 + x^708 + x^707 + x^705 + x^701 + x^700 + x^699 + x^698 + x^695 + x^689 + x^688 + x^687 + x^684 + x^683 + x^680 + x^678 + x^675 + x^672 + x^670 + x^669 + x^666 + x^664 + x^663 + x^656 + x^655 + x^654 + x^651 + x^647 + x^641 + x^639 + x^638 + x^636 + x^635 + x^633 + x^632 + x^631 + x^630 + x^629 + x^627 + x^626 + x^625 + x^623 + x^621 + x^620 + x^619 + x^617 + x^613 + x^611 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^603 + x^600 + x^598 + x^596 + x^595 + x^592 + x^591 + x^590 + x^587 + x^586 + x^585 + x^584 + x^582 + x^581 + x^578 + x^577 + x^576 + x^575 + x^574 + x^569 + x^566 + x^565 + x^564 + x^560 + x^558 + x^557 + x^556 + x^554 + x^552 + x^550 + x^549 + x^548 + x^545 + x^539 + x^538 + x^536 + x^535 + x^534 + x^533 + x^532 + x^527 + x^524 + x^523 + x^522 + x^520 + x^518 + x^517 + x^514 + x^513 + x^512 + x^510 + x^507 + x^504 + x^501 + x^499 + x^497 + x^496 + x^494 + x^492 + x^491 + x^490 + x^489 + x^487 + x^485 + x^483 + x^479 + x^478 + x^477 + x^476 + x^475 + x^473 + x^472 + x^470 + x^469 + x^468 + x^465 + x^464 + x^462 + x^460 + x^457 + x^452 + x^449 + x^448 + x^447 + x^445 + x^443 + x^441 + x^440 + x^436 + x^434 + x^432 + x^430 + x^428 + x^426 + x^424 + x^420 + x^416 + x^415 + x^410 + x^408 + x^407 + x^406 + x^404 + x^397 + x^395 + x^394 + x^390 + x^389 + x^387 + x^384 + x^382 + x^380 + x^374 + x^370 + x^368 + x^366 + x^365 + x^364 + x^362 + x^360 + x^359 + x^358 + x^356 + x^352 + x^350 + x^349 + x^347 + x^346 + x^344 + x^342 + x^341 + x^337 + x^336 + x^332 + x^331 + x^327 + x^325 + x^323 + x^322 + x^320 + x^317 + x^316 + x^315 + x^314 + x^312 + x^309 + x^307 + x^306 + x^305 + x^304 + x^303 + x^301 + x^300 + x^298 + x^296 + x^294 + x^293 + x^290 + x^289 + x^287 + x^285 + x^282 + x^281 + x^279 + x^277 + x^273 + x^265 + x^264 + x^259 + x^258 + x^257 + x^255 + x^254 + x^253 + x^251 + x^250 + x^249 + x^248 + x^247 + x^246 + x^244 + x^237 + x^235 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^227 + x^225 + x^221 + x^215 + x^214 + x^211 + x^208 + x^206 + x^204 + x^200 + x^199 + x^198 + x^196 + x^192 + x^188 + x^186 + x^185 + x^184 + x^183 + x^181 + x^179 + x^176 + x^175 + x^173 + x^171 + x^170 + x^168 + x^165 + x^164 + x^160 + x^158 + x^155 + x^154 + x^152 + x^151 + x^149 + x^147 + x^144 + x^141 + x^140 + x^139 + x^137 + x^136 + x^133 + x^131 + x^130 + x^128 + x^127 + x^126 + x^125 + x^123 + x^122 + x^121 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^109 + x^106 + x^102 + x^101 + x^98 + x^92 + x^89 + x^87 + x^86 + x^81 + x^74 + x^72 + x^71 + x^69 + x^65 + x^61 + x^57 + x^55 + x^53 + x^51 + x^50 + x^47 + x^45 + x^44 + x^43 + x^42 + x^40 + x^39 + x^38 + x^37 + x^35 + x^31 + x^30 + x^29 + x^27 + x^24 + x^22 + x^21 + x^20 + x^19 + 1
+
+44-24-27 401 x^928 + x^898 + x^870 + x^858 + x^824 + x^821 + x^820 + x^798 + x^792 + x^791 + x^790 + x^789 + x^784 + x^776 + x^771 + x^770 + x^768 + x^764 + x^762 + x^761 + x^760 + x^759 + x^755 + x^754 + x^751 + x^742 + x^738 + x^735 + x^734 + x^731 + x^730 + x^729 + x^728 + x^725 + x^722 + x^721 + x^715 + x^711 + x^710 + x^706 + x^705 + x^701 + x^700 + x^698 + x^695 + x^692 + x^691 + x^689 + x^686 + x^685 + x^681 + x^676 + x^675 + x^674 + x^672 + x^671 + x^669 + x^668 + x^667 + x^666 + x^665 + x^658 + x^656 + x^654 + x^653 + x^651 + x^650 + x^648 + x^646 + x^644 + x^642 + x^635 + x^634 + x^633 + x^629 + x^626 + x^625 + x^624 + x^622 + x^621 + x^620 + x^618 + x^616 + x^614 + x^612 + x^608 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^594 + x^593 + x^590 + x^589 + x^588 + x^586 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^575 + x^574 + x^569 + x^568 + x^566 + x^565 + x^564 + x^561 + x^559 + x^556 + x^554 + x^553 + x^552 + x^547 + x^543 + x^542 + x^541 + x^540 + x^539 + x^538 + x^536 + x^535 + x^534 + x^531 + x^530 + x^529 + x^527 + x^526 + x^524 + x^519 + x^514 + x^512 + x^511 + x^507 + x^504 + x^503 + x^502 + x^499 + x^498 + x^494 + x^493 + x^491 + x^489 + x^488 + x^486 + x^485 + x^483 + x^482 + x^480 + x^478 + x^476 + x^473 + x^468 + x^465 + x^463 + x^461 + x^460 + x^459 + x^458 + x^457 + x^455 + x^454 + x^453 + x^452 + x^451 + x^450 + x^449 + x^447 + x^446 + x^445 + x^443 + x^442 + x^439 + x^437 + x^436 + x^435 + x^433 + x^432 + x^429 + x^424 + x^423 + x^421 + x^418 + x^416 + x^412 + x^411 + x^406 + x^404 + x^403 + x^401 + x^400 + x^399 + x^398 + x^397 + x^394 + x^390 + x^388 + x^384 + x^383 + x^382 + x^381 + x^380 + x^378 + x^377 + x^376 + x^374 + x^373 + x^372 + x^368 + x^367 + x^366 + x^363 + x^361 + x^360 + x^359 + x^355 + x^353 + x^351 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^342 + x^341 + x^340 + x^338 + x^337 + x^334 + x^329 + x^328 + x^326 + x^325 + x^319 + x^316 + x^314 + x^312 + x^311 + x^310 + x^308 + x^307 + x^305 + x^300 + x^296 + x^292 + x^291 + x^290 + x^287 + x^286 + x^284 + x^282 + x^280 + x^279 + x^277 + x^275 + x^274 + x^273 + x^272 + x^269 + x^268 + x^265 + x^264 + x^263 + x^262 + x^261 + x^258 + x^257 + x^256 + x^255 + x^254 + x^253 + x^252 + x^250 + x^249 + x^244 + x^242 + x^239 + x^238 + x^237 + x^235 + x^234 + x^232 + x^231 + x^228 + x^226 + x^225 + x^224 + x^221 + x^220 + x^219 + x^218 + x^216 + x^214 + x^213 + x^211 + x^210 + x^207 + x^205 + x^204 + x^203 + x^202 + x^200 + x^199 + x^198 + x^194 + x^186 + x^185 + x^184 + x^183 + x^182 + x^180 + x^179 + x^177 + x^174 + x^171 + x^169 + x^168 + x^165 + x^164 + x^163 + x^161 + x^159 + x^158 + x^157 + x^154 + x^152 + x^151 + x^148 + x^146 + x^145 + x^144 + x^142 + x^141 + x^139 + x^136 + x^135 + x^134 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^124 + x^123 + x^120 + x^119 + x^117 + x^116 + x^114 + x^112 + x^106 + x^103 + x^101 + x^100 + x^98 + x^94 + x^93 + x^91 + x^86 + x^83 + x^82 + x^78 + x^76 + x^74 + x^73 + x^71 + x^69 + x^66 + x^65 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^54 + x^47 + x^45 + x^44 + x^43 + x^42 + x^40 + x^39 + x^38 + x^34 + x^31 + x^29 + x^28 + x^19 + x^16 + x^12 + x^6 + 1
+
+10-49-23 403 x^928 + x^900 + x^898 + x^893 + x^872 + x^870 + x^865 + x^858 + x^842 + x^840 + x^835 + x^833 + x^826 + x^823 + x^821 + x^816 + x^814 + x^809 + x^808 + x^807 + x^805 + x^802 + x^796 + x^793 + x^782 + x^780 + x^778 + x^775 + x^772 + x^770 + x^767 + x^766 + x^765 + x^760 + x^758 + x^756 + x^754 + x^753 + x^751 + x^747 + x^744 + x^740 + x^739 + x^738 + x^736 + x^735 + x^732 + x^728 + x^724 + x^723 + x^722 + x^720 + x^718 + x^717 + x^714 + x^712 + x^709 + x^708 + x^707 + x^706 + x^705 + x^702 + x^701 + x^700 + x^698 + x^697 + x^696 + x^694 + x^693 + x^691 + x^689 + x^688 + x^684 + x^682 + x^681 + x^680 + x^679 + x^677 + x^676 + x^674 + x^673 + x^672 + x^670 + x^668 + x^667 + x^666 + x^664 + x^661 + x^658 + x^657 + x^655 + x^652 + x^649 + x^646 + x^645 + x^643 + x^641 + x^640 + x^639 + x^638 + x^636 + x^635 + x^634 + x^632 + x^631 + x^628 + x^623 + x^622 + x^620 + x^619 + x^615 + x^612 + x^610 + x^607 + x^604 + x^602 + x^599 + x^598 + x^596 + x^593 + x^590 + x^588 + x^587 + x^585 + x^582 + x^581 + x^578 + x^576 + x^575 + x^573 + x^571 + x^570 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^559 + x^557 + x^556 + x^552 + x^550 + x^549 + x^548 + x^546 + x^545 + x^543 + x^537 + x^536 + x^535 + x^534 + x^533 + x^532 + x^529 + x^526 + x^525 + x^523 + x^521 + x^520 + x^518 + x^515 + x^513 + x^512 + x^511 + x^508 + x^503 + x^502 + x^499 + x^498 + x^495 + x^494 + x^493 + x^492 + x^491 + x^480 + x^479 + x^475 + x^474 + x^472 + x^470 + x^469 + x^466 + x^465 + x^460 + x^453 + x^452 + x^451 + x^447 + x^444 + x^443 + x^438 + x^436 + x^431 + x^428 + x^426 + x^424 + x^423 + x^421 + x^420 + x^418 + x^417 + x^414 + x^413 + x^411 + x^410 + x^404 + x^401 + x^396 + x^395 + x^390 + x^389 + x^386 + x^384 + x^380 + x^378 + x^377 + x^376 + x^373 + x^372 + x^371 + x^369 + x^364 + x^361 + x^360 + x^359 + x^357 + x^356 + x^354 + x^353 + x^348 + x^347 + x^346 + x^342 + x^341 + x^339 + x^338 + x^333 + x^332 + x^331 + x^329 + x^328 + x^324 + x^322 + x^320 + x^315 + x^314 + x^312 + x^311 + x^310 + x^307 + x^306 + x^303 + x^295 + x^294 + x^292 + x^289 + x^288 + x^283 + x^281 + x^279 + x^274 + x^272 + x^271 + x^270 + x^268 + x^267 + x^266 + x^265 + x^264 + x^261 + x^258 + x^257 + x^256 + x^255 + x^252 + x^251 + x^248 + x^245 + x^243 + x^242 + x^238 + x^237 + x^236 + x^235 + x^233 + x^232 + x^231 + x^229 + x^228 + x^226 + x^225 + x^224 + x^222 + x^221 + x^220 + x^216 + x^215 + x^213 + x^212 + x^210 + x^209 + x^208 + x^202 + x^200 + x^199 + x^197 + x^194 + x^193 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^184 + x^183 + x^181 + x^179 + x^178 + x^177 + x^176 + x^174 + x^173 + x^172 + x^171 + x^169 + x^166 + x^164 + x^163 + x^160 + x^158 + x^157 + x^155 + x^152 + x^151 + x^150 + x^148 + x^146 + x^145 + x^143 + x^142 + x^137 + x^133 + x^129 + x^126 + x^118 + x^116 + x^114 + x^113 + x^112 + x^110 + x^106 + x^102 + x^99 + x^98 + x^97 + x^96 + x^92 + x^91 + x^88 + x^86 + x^85 + x^83 + x^82 + x^81 + x^79 + x^78 + x^77 + x^76 + x^73 + x^71 + x^67 + x^66 + x^65 + x^64 + x^63 + x^61 + x^60 + x^58 + x^53 + x^52 + x^51 + x^48 + x^47 + x^44 + x^43 + x^42 + x^41 + x^39 + x^37 + x^36 + x^35 + x^34 + x^33 + x^31 + x^26 + x^21 + x^20 + x^16 + x^10 + x^5 + 1
+
+16-2-49 403 x^928 + x^898 + x^870 + x^858 + x^855 + x^846 + x^831 + x^828 + x^822 + x^818 + x^808 + x^800 + x^798 + x^795 + x^788 + x^786 + x^784 + x^783 + x^776 + x^775 + x^770 + x^768 + x^764 + x^759 + x^753 + x^751 + x^750 + x^746 + x^743 + x^740 + x^736 + x^735 + x^734 + x^724 + x^723 + x^719 + x^712 + x^708 + x^706 + x^703 + x^699 + x^698 + x^696 + x^695 + x^694 + x^693 + x^691 + x^690 + x^688 + x^686 + x^684 + x^683 + x^676 + x^675 + x^673 + x^672 + x^671 + x^670 + x^668 + x^664 + x^663 + x^662 + x^660 + x^655 + x^654 + x^652 + x^649 + x^644 + x^642 + x^636 + x^634 + x^633 + x^623 + x^622 + x^620 + x^619 + x^616 + x^614 + x^613 + x^611 + x^609 + x^608 + x^606 + x^604 + x^603 + x^602 + x^601 + x^600 + x^599 + x^598 + x^596 + x^595 + x^594 + x^592 + x^591 + x^588 + x^586 + x^585 + x^584 + x^583 + x^579 + x^578 + x^577 + x^576 + x^575 + x^574 + x^572 + x^569 + x^562 + x^560 + x^555 + x^553 + x^550 + x^549 + x^548 + x^547 + x^546 + x^545 + x^544 + x^543 + x^542 + x^538 + x^536 + x^533 + x^532 + x^531 + x^530 + x^529 + x^528 + x^527 + x^526 + x^523 + x^518 + x^516 + x^515 + x^511 + x^509 + x^507 + x^503 + x^501 + x^500 + x^498 + x^497 + x^496 + x^494 + x^491 + x^490 + x^487 + x^485 + x^484 + x^483 + x^482 + x^478 + x^477 + x^475 + x^474 + x^472 + x^470 + x^468 + x^467 + x^466 + x^465 + x^464 + x^462 + x^461 + x^460 + x^458 + x^457 + x^456 + x^455 + x^454 + x^453 + x^448 + x^446 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^425 + x^422 + x^421 + x^420 + x^419 + x^417 + x^414 + x^413 + x^411 + x^410 + x^406 + x^405 + x^400 + x^399 + x^397 + x^395 + x^394 + x^393 + x^392 + x^391 + x^389 + x^387 + x^382 + x^380 + x^379 + x^377 + x^375 + x^371 + x^370 + x^366 + x^365 + x^364 + x^363 + x^362 + x^358 + x^356 + x^354 + x^353 + x^351 + x^348 + x^346 + x^344 + x^343 + x^342 + x^340 + x^339 + x^337 + x^334 + x^333 + x^332 + x^331 + x^328 + x^327 + x^326 + x^325 + x^324 + x^323 + x^322 + x^321 + x^320 + x^318 + x^317 + x^316 + x^315 + x^314 + x^312 + x^310 + x^306 + x^304 + x^303 + x^301 + x^297 + x^295 + x^293 + x^290 + x^285 + x^283 + x^282 + x^273 + x^271 + x^268 + x^266 + x^262 + x^260 + x^259 + x^258 + x^253 + x^252 + x^251 + x^249 + x^248 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^238 + x^237 + x^234 + x^233 + x^231 + x^229 + x^228 + x^227 + x^223 + x^222 + x^217 + x^216 + x^214 + x^213 + x^211 + x^209 + x^208 + x^203 + x^202 + x^201 + x^198 + x^197 + x^196 + x^194 + x^193 + x^189 + x^188 + x^187 + x^183 + x^182 + x^181 + x^177 + x^176 + x^174 + x^170 + x^166 + x^163 + x^162 + x^161 + x^160 + x^158 + x^157 + x^155 + x^153 + x^152 + x^151 + x^149 + x^148 + x^147 + x^146 + x^144 + x^142 + x^141 + x^140 + x^138 + x^132 + x^131 + x^129 + x^128 + x^126 + x^125 + x^123 + x^122 + x^120 + x^119 + x^117 + x^116 + x^115 + x^112 + x^109 + x^107 + x^105 + x^101 + x^97 + x^95 + x^94 + x^92 + x^91 + x^90 + x^87 + x^86 + x^85 + x^83 + x^82 + x^81 + x^79 + x^78 + x^77 + x^73 + x^72 + x^71 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^58 + x^54 + x^50 + x^45 + x^44 + x^43 + x^42 + x^39 + x^37 + x^26 + x^24 + x^20 + x^16 + x^14 + x^10 + 1
+
+17-2-46 405 x^928 + x^898 + x^870 + x^860 + x^848 + x^831 + x^830 + x^818 + x^812 + x^808 + x^804 + x^801 + x^800 + x^792 + x^791 + x^790 + x^784 + x^780 + x^778 + x^775 + x^774 + x^770 + x^763 + x^762 + x^761 + x^760 + x^756 + x^754 + x^750 + x^748 + x^746 + x^745 + x^736 + x^733 + x^732 + x^731 + x^729 + x^728 + x^726 + x^720 + x^719 + x^712 + x^710 + x^706 + x^703 + x^702 + x^701 + x^700 + x^690 + x^686 + x^682 + x^679 + x^676 + x^675 + x^673 + x^672 + x^671 + x^669 + x^668 + x^666 + x^664 + x^663 + x^658 + x^652 + x^651 + x^648 + x^647 + x^646 + x^645 + x^644 + x^643 + x^642 + x^638 + x^633 + x^628 + x^626 + x^624 + x^623 + x^621 + x^617 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^604 + x^599 + x^595 + x^594 + x^593 + x^592 + x^590 + x^589 + x^588 + x^584 + x^580 + x^579 + x^578 + x^577 + x^576 + x^574 + x^573 + x^569 + x^568 + x^567 + x^566 + x^564 + x^563 + x^561 + x^560 + x^559 + x^558 + x^557 + x^555 + x^549 + x^548 + x^547 + x^544 + x^543 + x^542 + x^540 + x^535 + x^534 + x^532 + x^531 + x^530 + x^528 + x^527 + x^526 + x^525 + x^520 + x^519 + x^516 + x^513 + x^510 + x^509 + x^500 + x^499 + x^498 + x^497 + x^496 + x^493 + x^492 + x^490 + x^489 + x^487 + x^484 + x^482 + x^480 + x^479 + x^476 + x^473 + x^471 + x^470 + x^468 + x^467 + x^465 + x^464 + x^463 + x^462 + x^461 + x^460 + x^457 + x^453 + x^452 + x^450 + x^448 + x^447 + x^443 + x^440 + x^439 + x^438 + x^437 + x^431 + x^430 + x^429 + x^428 + x^427 + x^426 + x^424 + x^423 + x^420 + x^418 + x^416 + x^415 + x^408 + x^407 + x^406 + x^405 + x^404 + x^403 + x^397 + x^395 + x^391 + x^389 + x^388 + x^386 + x^384 + x^382 + x^381 + x^380 + x^379 + x^378 + x^375 + x^374 + x^373 + x^372 + x^371 + x^369 + x^368 + x^365 + x^364 + x^363 + x^362 + x^360 + x^359 + x^358 + x^357 + x^353 + x^351 + x^350 + x^345 + x^341 + x^338 + x^336 + x^335 + x^334 + x^332 + x^331 + x^329 + x^328 + x^327 + x^323 + x^321 + x^320 + x^319 + x^317 + x^316 + x^314 + x^313 + x^312 + x^310 + x^308 + x^307 + x^304 + x^303 + x^300 + x^297 + x^295 + x^293 + x^291 + x^289 + x^288 + x^287 + x^285 + x^284 + x^282 + x^280 + x^279 + x^277 + x^273 + x^272 + x^269 + x^268 + x^267 + x^266 + x^265 + x^264 + x^262 + x^260 + x^259 + x^256 + x^255 + x^254 + x^253 + x^249 + x^247 + x^245 + x^243 + x^241 + x^240 + x^239 + x^238 + x^237 + x^236 + x^235 + x^234 + x^232 + x^228 + x^226 + x^225 + x^224 + x^223 + x^220 + x^219 + x^217 + x^209 + x^207 + x^206 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^195 + x^194 + x^189 + x^187 + x^186 + x^185 + x^184 + x^182 + x^180 + x^178 + x^174 + x^173 + x^172 + x^170 + x^167 + x^166 + x^165 + x^164 + x^162 + x^161 + x^160 + x^159 + x^158 + x^157 + x^156 + x^155 + x^154 + x^153 + x^152 + x^151 + x^147 + x^143 + x^141 + x^138 + x^131 + x^130 + x^129 + x^127 + x^122 + x^121 + x^120 + x^118 + x^117 + x^114 + x^111 + x^109 + x^106 + x^105 + x^104 + x^103 + x^102 + x^101 + x^100 + x^99 + x^98 + x^97 + x^93 + x^92 + x^91 + x^90 + x^88 + x^87 + x^86 + x^82 + x^81 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^73 + x^72 + x^71 + x^68 + x^59 + x^58 + x^51 + x^50 + x^43 + x^42 + x^40 + x^39 + x^34 + x^27 + x^25 + x^24 + x^23 + x^19 + x^18 + x^17 + x^15 + x^14 + x^13 + x^11 + x^10 + 1
+
+55-23-24 407 x^928 + x^898 + x^894 + x^870 + x^865 + x^849 + x^846 + x^842 + x^834 + x^833 + x^830 + x^826 + x^820 + x^819 + x^816 + x^813 + x^808 + x^804 + x^803 + x^794 + x^782 + x^778 + x^772 + x^769 + x^767 + x^765 + x^764 + x^762 + x^760 + x^759 + x^756 + x^751 + x^745 + x^743 + x^740 + x^739 + x^737 + x^733 + x^730 + x^729 + x^728 + x^726 + x^722 + x^720 + x^718 + x^717 + x^716 + x^713 + x^710 + x^709 + x^708 + x^707 + x^702 + x^699 + x^697 + x^694 + x^692 + x^691 + x^688 + x^687 + x^682 + x^680 + x^679 + x^678 + x^676 + x^675 + x^674 + x^670 + x^668 + x^666 + x^662 + x^661 + x^657 + x^652 + x^651 + x^649 + x^647 + x^646 + x^643 + x^640 + x^639 + x^637 + x^635 + x^634 + x^633 + x^630 + x^618 + x^616 + x^614 + x^613 + x^611 + x^610 + x^609 + x^608 + x^604 + x^603 + x^602 + x^597 + x^593 + x^591 + x^590 + x^585 + x^582 + x^579 + x^575 + x^574 + x^573 + x^572 + x^569 + x^567 + x^566 + x^564 + x^562 + x^561 + x^560 + x^557 + x^556 + x^555 + x^554 + x^551 + x^550 + x^547 + x^545 + x^542 + x^541 + x^539 + x^537 + x^534 + x^531 + x^530 + x^529 + x^528 + x^526 + x^525 + x^523 + x^522 + x^521 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^508 + x^506 + x^505 + x^500 + x^498 + x^492 + x^485 + x^484 + x^480 + x^479 + x^478 + x^477 + x^476 + x^471 + x^470 + x^469 + x^467 + x^465 + x^464 + x^462 + x^458 + x^457 + x^454 + x^453 + x^452 + x^451 + x^450 + x^445 + x^444 + x^443 + x^441 + x^439 + x^437 + x^436 + x^435 + x^433 + x^431 + x^430 + x^429 + x^425 + x^424 + x^421 + x^419 + x^414 + x^411 + x^410 + x^409 + x^408 + x^407 + x^406 + x^405 + x^396 + x^395 + x^394 + x^390 + x^388 + x^385 + x^383 + x^381 + x^379 + x^378 + x^377 + x^376 + x^375 + x^373 + x^371 + x^369 + x^368 + x^367 + x^360 + x^358 + x^353 + x^351 + x^350 + x^348 + x^347 + x^346 + x^344 + x^343 + x^341 + x^338 + x^336 + x^335 + x^334 + x^331 + x^330 + x^329 + x^327 + x^326 + x^324 + x^322 + x^318 + x^314 + x^313 + x^311 + x^307 + x^305 + x^304 + x^302 + x^299 + x^295 + x^294 + x^293 + x^289 + x^284 + x^282 + x^281 + x^277 + x^272 + x^271 + x^270 + x^268 + x^265 + x^262 + x^259 + x^257 + x^254 + x^252 + x^251 + x^250 + x^249 + x^244 + x^243 + x^240 + x^239 + x^237 + x^235 + x^234 + x^233 + x^231 + x^230 + x^227 + x^224 + x^223 + x^220 + x^219 + x^218 + x^217 + x^215 + x^214 + x^213 + x^212 + x^211 + x^210 + x^209 + x^208 + x^207 + x^205 + x^203 + x^201 + x^200 + x^197 + x^193 + x^190 + x^187 + x^185 + x^184 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^173 + x^172 + x^169 + x^168 + x^166 + x^165 + x^162 + x^159 + x^157 + x^156 + x^155 + x^154 + x^153 + x^152 + x^150 + x^146 + x^145 + x^143 + x^142 + x^141 + x^139 + x^138 + x^137 + x^136 + x^135 + x^134 + x^132 + x^129 + x^123 + x^119 + x^115 + x^114 + x^112 + x^108 + x^107 + x^102 + x^100 + x^98 + x^97 + x^95 + x^93 + x^91 + x^90 + x^87 + x^86 + x^85 + x^83 + x^80 + x^79 + x^78 + x^77 + x^75 + x^74 + x^72 + x^69 + x^68 + x^65 + x^64 + x^61 + x^60 + x^59 + x^58 + x^57 + x^56 + x^55 + x^52 + x^51 + x^50 + x^45 + x^44 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^34 + x^33 + x^31 + x^30 + x^29 + x^26 + x^25 + x^23 + x^21 + x^20 + x^19 + x^18 + x^17 + x^13 + x^12 + x^10 + x^8 + x^7 + 1
+
+15-3-26 409 x^928 + x^898 + x^892 + x^870 + x^863 + x^862 + x^858 + x^856 + x^852 + x^833 + x^828 + x^827 + x^826 + x^824 + x^823 + x^820 + x^818 + x^816 + x^812 + x^808 + x^803 + x^801 + x^799 + x^798 + x^797 + x^795 + x^794 + x^792 + x^791 + x^790 + x^788 + x^787 + x^784 + x^783 + x^782 + x^773 + x^772 + x^771 + x^768 + x^767 + x^763 + x^760 + x^757 + x^753 + x^750 + x^746 + x^744 + x^737 + x^732 + x^731 + x^730 + x^729 + x^728 + x^726 + x^725 + x^724 + x^721 + x^717 + x^716 + x^713 + x^711 + x^710 + x^707 + x^706 + x^705 + x^703 + x^702 + x^699 + x^698 + x^697 + x^696 + x^694 + x^692 + x^691 + x^690 + x^689 + x^688 + x^681 + x^678 + x^673 + x^668 + x^666 + x^662 + x^658 + x^657 + x^656 + x^653 + x^651 + x^650 + x^648 + x^644 + x^643 + x^642 + x^641 + x^640 + x^638 + x^636 + x^635 + x^634 + x^633 + x^632 + x^630 + x^628 + x^626 + x^625 + x^623 + x^622 + x^620 + x^618 + x^617 + x^616 + x^614 + x^611 + x^609 + x^607 + x^605 + x^603 + x^596 + x^595 + x^593 + x^592 + x^590 + x^587 + x^586 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^571 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^561 + x^560 + x^559 + x^558 + x^557 + x^556 + x^555 + x^554 + x^553 + x^552 + x^548 + x^547 + x^546 + x^545 + x^544 + x^542 + x^538 + x^537 + x^534 + x^533 + x^532 + x^529 + x^527 + x^526 + x^524 + x^523 + x^518 + x^517 + x^509 + x^505 + x^503 + x^501 + x^494 + x^493 + x^492 + x^488 + x^485 + x^484 + x^483 + x^480 + x^479 + x^477 + x^475 + x^474 + x^473 + x^472 + x^471 + x^469 + x^467 + x^466 + x^465 + x^464 + x^461 + x^458 + x^456 + x^453 + x^449 + x^446 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^436 + x^435 + x^432 + x^431 + x^427 + x^426 + x^423 + x^418 + x^415 + x^413 + x^412 + x^411 + x^410 + x^407 + x^406 + x^403 + x^400 + x^398 + x^396 + x^385 + x^383 + x^382 + x^381 + x^375 + x^374 + x^373 + x^364 + x^363 + x^362 + x^360 + x^358 + x^357 + x^355 + x^353 + x^352 + x^350 + x^349 + x^345 + x^344 + x^343 + x^342 + x^340 + x^337 + x^331 + x^329 + x^328 + x^325 + x^324 + x^323 + x^322 + x^315 + x^314 + x^312 + x^311 + x^308 + x^304 + x^303 + x^299 + x^297 + x^295 + x^289 + x^284 + x^282 + x^281 + x^279 + x^278 + x^275 + x^274 + x^273 + x^272 + x^271 + x^270 + x^264 + x^263 + x^262 + x^260 + x^259 + x^258 + x^256 + x^253 + x^252 + x^251 + x^250 + x^248 + x^247 + x^246 + x^245 + x^243 + x^242 + x^240 + x^238 + x^237 + x^234 + x^233 + x^232 + x^231 + x^230 + x^228 + x^221 + x^220 + x^218 + x^213 + x^212 + x^211 + x^210 + x^204 + x^201 + x^200 + x^196 + x^195 + x^194 + x^191 + x^190 + x^189 + x^185 + x^183 + x^181 + x^180 + x^178 + x^176 + x^175 + x^170 + x^168 + x^167 + x^165 + x^164 + x^163 + x^160 + x^159 + x^158 + x^157 + x^156 + x^153 + x^151 + x^150 + x^149 + x^146 + x^145 + x^141 + x^139 + x^138 + x^137 + x^133 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^125 + x^124 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^112 + x^110 + x^106 + x^103 + x^101 + x^100 + x^97 + x^96 + x^94 + x^93 + x^92 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^82 + x^80 + x^77 + x^73 + x^72 + x^71 + x^70 + x^68 + x^67 + x^65 + x^61 + x^60 + x^59 + x^56 + x^55 + x^48 + x^47 + x^42 + x^41 + x^36 + x^35 + x^33 + x^29 + x^27 + x^26 + x^25 + x^18 + x^14 + x^12 + x^10 + x^8 + x^4 + 1
+
+33-51-22 409 x^928 + x^898 + x^886 + x^870 + x^859 + x^858 + x^857 + x^844 + x^842 + x^832 + x^831 + x^830 + x^826 + x^815 + x^812 + x^808 + x^805 + x^804 + x^803 + x^799 + x^798 + x^789 + x^787 + x^786 + x^785 + x^782 + x^777 + x^776 + x^775 + x^771 + x^769 + x^766 + x^763 + x^758 + x^756 + x^752 + x^749 + x^745 + x^744 + x^743 + x^741 + x^739 + x^738 + x^735 + x^734 + x^731 + x^730 + x^721 + x^720 + x^715 + x^714 + x^711 + x^708 + x^705 + x^704 + x^703 + x^700 + x^698 + x^695 + x^693 + x^692 + x^690 + x^689 + x^684 + x^682 + x^681 + x^680 + x^677 + x^676 + x^673 + x^672 + x^671 + x^667 + x^666 + x^662 + x^661 + x^658 + x^656 + x^653 + x^652 + x^650 + x^649 + x^647 + x^646 + x^645 + x^644 + x^642 + x^641 + x^640 + x^638 + x^636 + x^634 + x^633 + x^632 + x^631 + x^629 + x^625 + x^624 + x^623 + x^621 + x^620 + x^619 + x^616 + x^615 + x^614 + x^612 + x^611 + x^609 + x^606 + x^605 + x^602 + x^601 + x^599 + x^596 + x^595 + x^592 + x^591 + x^588 + x^587 + x^586 + x^583 + x^582 + x^578 + x^577 + x^576 + x^574 + x^572 + x^570 + x^566 + x^562 + x^560 + x^555 + x^552 + x^550 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^537 + x^535 + x^534 + x^533 + x^532 + x^531 + x^530 + x^528 + x^525 + x^524 + x^523 + x^519 + x^516 + x^513 + x^511 + x^509 + x^508 + x^507 + x^506 + x^504 + x^500 + x^499 + x^497 + x^495 + x^494 + x^491 + x^488 + x^487 + x^484 + x^480 + x^479 + x^476 + x^474 + x^472 + x^471 + x^470 + x^469 + x^468 + x^464 + x^463 + x^462 + x^460 + x^459 + x^458 + x^457 + x^456 + x^455 + x^454 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^441 + x^440 + x^439 + x^437 + x^436 + x^435 + x^431 + x^430 + x^427 + x^423 + x^421 + x^419 + x^412 + x^410 + x^407 + x^406 + x^405 + x^404 + x^402 + x^400 + x^398 + x^396 + x^395 + x^394 + x^392 + x^389 + x^387 + x^386 + x^384 + x^382 + x^381 + x^379 + x^378 + x^377 + x^375 + x^372 + x^370 + x^369 + x^363 + x^361 + x^360 + x^351 + x^350 + x^347 + x^343 + x^342 + x^340 + x^336 + x^328 + x^327 + x^326 + x^325 + x^323 + x^322 + x^321 + x^319 + x^318 + x^315 + x^314 + x^313 + x^312 + x^311 + x^308 + x^307 + x^305 + x^301 + x^299 + x^298 + x^295 + x^293 + x^292 + x^290 + x^289 + x^288 + x^286 + x^284 + x^283 + x^282 + x^280 + x^279 + x^275 + x^273 + x^272 + x^269 + x^266 + x^265 + x^264 + x^255 + x^251 + x^249 + x^248 + x^246 + x^244 + x^243 + x^242 + x^238 + x^237 + x^235 + x^234 + x^232 + x^230 + x^229 + x^228 + x^226 + x^224 + x^222 + x^221 + x^218 + x^213 + x^210 + x^209 + x^208 + x^206 + x^203 + x^200 + x^195 + x^193 + x^189 + x^187 + x^186 + x^185 + x^182 + x^181 + x^179 + x^177 + x^174 + x^173 + x^170 + x^163 + x^160 + x^159 + x^155 + x^154 + x^153 + x^152 + x^151 + x^147 + x^146 + x^143 + x^141 + x^133 + x^130 + x^128 + x^125 + x^123 + x^118 + x^116 + x^115 + x^114 + x^110 + x^108 + x^106 + x^105 + x^104 + x^102 + x^100 + x^98 + x^97 + x^96 + x^95 + x^94 + x^93 + x^92 + x^91 + x^89 + x^85 + x^84 + x^83 + x^82 + x^81 + x^80 + x^78 + x^77 + x^74 + x^72 + x^71 + x^69 + x^67 + x^65 + x^64 + x^63 + x^61 + x^58 + x^56 + x^55 + x^53 + x^52 + x^51 + x^50 + x^48 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^37 + x^36 + x^35 + x^33 + x^32 + x^30 + x^29 + x^28 + x^27 + x^25 + x^23 + x^21 + x^16 + x^13 + x^11 + x^10 + x^8 + 1
+
+23-25-12 411 x^928 + x^898 + x^873 + x^870 + x^852 + x^847 + x^844 + x^842 + x^838 + x^836 + x^831 + x^828 + x^822 + x^821 + x^818 + x^817 + x^816 + x^814 + x^813 + x^812 + x^811 + x^801 + x^800 + x^798 + x^797 + x^796 + x^792 + x^791 + x^790 + x^787 + x^780 + x^776 + x^774 + x^770 + x^768 + x^766 + x^765 + x^762 + x^761 + x^759 + x^758 + x^757 + x^756 + x^755 + x^752 + x^749 + x^748 + x^747 + x^744 + x^741 + x^740 + x^739 + x^737 + x^735 + x^731 + x^730 + x^729 + x^728 + x^726 + x^725 + x^722 + x^720 + x^718 + x^714 + x^712 + x^711 + x^709 + x^708 + x^707 + x^706 + x^705 + x^704 + x^698 + x^694 + x^693 + x^691 + x^689 + x^686 + x^685 + x^682 + x^676 + x^674 + x^670 + x^669 + x^668 + x^667 + x^666 + x^665 + x^662 + x^661 + x^658 + x^655 + x^653 + x^652 + x^650 + x^647 + x^644 + x^643 + x^640 + x^638 + x^637 + x^635 + x^634 + x^632 + x^629 + x^627 + x^626 + x^625 + x^624 + x^619 + x^618 + x^614 + x^612 + x^611 + x^606 + x^604 + x^602 + x^601 + x^595 + x^592 + x^591 + x^590 + x^589 + x^586 + x^585 + x^581 + x^579 + x^578 + x^575 + x^574 + x^573 + x^568 + x^567 + x^565 + x^564 + x^562 + x^560 + x^559 + x^558 + x^555 + x^554 + x^553 + x^552 + x^549 + x^548 + x^546 + x^544 + x^543 + x^542 + x^541 + x^538 + x^533 + x^532 + x^529 + x^527 + x^526 + x^523 + x^522 + x^521 + x^517 + x^511 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^497 + x^496 + x^494 + x^490 + x^489 + x^486 + x^485 + x^483 + x^482 + x^481 + x^477 + x^475 + x^473 + x^472 + x^471 + x^468 + x^464 + x^462 + x^461 + x^460 + x^459 + x^455 + x^454 + x^453 + x^449 + x^448 + x^447 + x^446 + x^438 + x^437 + x^435 + x^432 + x^429 + x^427 + x^426 + x^424 + x^423 + x^421 + x^419 + x^418 + x^416 + x^415 + x^413 + x^412 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^401 + x^399 + x^397 + x^396 + x^394 + x^393 + x^390 + x^385 + x^384 + x^383 + x^380 + x^379 + x^378 + x^376 + x^375 + x^374 + x^372 + x^370 + x^368 + x^367 + x^366 + x^365 + x^363 + x^359 + x^357 + x^356 + x^355 + x^354 + x^353 + x^352 + x^351 + x^350 + x^348 + x^345 + x^341 + x^337 + x^335 + x^334 + x^333 + x^325 + x^319 + x^317 + x^316 + x^314 + x^305 + x^301 + x^298 + x^294 + x^293 + x^292 + x^289 + x^284 + x^281 + x^279 + x^272 + x^271 + x^269 + x^268 + x^267 + x^266 + x^264 + x^263 + x^262 + x^261 + x^256 + x^255 + x^254 + x^252 + x^251 + x^249 + x^248 + x^244 + x^242 + x^239 + x^235 + x^234 + x^233 + x^227 + x^226 + x^223 + x^221 + x^220 + x^216 + x^214 + x^211 + x^209 + x^207 + x^205 + x^204 + x^200 + x^198 + x^197 + x^196 + x^193 + x^188 + x^187 + x^185 + x^183 + x^182 + x^181 + x^179 + x^177 + x^175 + x^173 + x^172 + x^170 + x^169 + x^167 + x^163 + x^162 + x^158 + x^157 + x^156 + x^155 + x^154 + x^152 + x^151 + x^150 + x^149 + x^145 + x^144 + x^143 + x^142 + x^140 + x^139 + x^138 + x^136 + x^135 + x^133 + x^131 + x^130 + x^127 + x^126 + x^124 + x^122 + x^120 + x^118 + x^116 + x^114 + x^111 + x^110 + x^106 + x^105 + x^103 + x^102 + x^101 + x^100 + x^99 + x^98 + x^97 + x^95 + x^94 + x^93 + x^92 + x^91 + x^90 + x^86 + x^85 + x^82 + x^81 + x^78 + x^75 + x^70 + x^66 + x^64 + x^63 + x^61 + x^60 + x^55 + x^54 + x^53 + x^52 + x^50 + x^49 + x^46 + x^45 + x^44 + x^41 + x^38 + x^37 + x^36 + x^32 + x^30 + x^29 + x^27 + x^22 + x^18 + x^16 + x^13 + x^9 + x^8 + x^7 + x^5 + 1
+
+36-2-35 411 x^928 + x^898 + x^870 + x^860 + x^850 + x^842 + x^830 + x^824 + x^822 + x^812 + x^808 + x^806 + x^804 + x^794 + x^792 + x^790 + x^786 + x^782 + x^778 + x^776 + x^772 + x^768 + x^764 + x^754 + x^752 + x^747 + x^746 + x^745 + x^742 + x^738 + x^737 + x^736 + x^729 + x^728 + x^725 + x^724 + x^722 + x^721 + x^720 + x^718 + x^716 + x^715 + x^714 + x^712 + x^707 + x^706 + x^704 + x^703 + x^701 + x^699 + x^693 + x^691 + x^689 + x^688 + x^687 + x^684 + x^682 + x^680 + x^674 + x^672 + x^671 + x^669 + x^668 + x^663 + x^662 + x^661 + x^660 + x^659 + x^658 + x^654 + x^652 + x^651 + x^650 + x^649 + x^648 + x^644 + x^642 + x^640 + x^639 + x^638 + x^635 + x^633 + x^632 + x^624 + x^623 + x^620 + x^619 + x^618 + x^617 + x^611 + x^607 + x^606 + x^604 + x^602 + x^601 + x^600 + x^598 + x^596 + x^594 + x^593 + x^589 + x^585 + x^583 + x^580 + x^579 + x^577 + x^576 + x^575 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^560 + x^558 + x^556 + x^555 + x^553 + x^552 + x^551 + x^549 + x^548 + x^545 + x^542 + x^541 + x^539 + x^536 + x^534 + x^533 + x^530 + x^528 + x^526 + x^524 + x^521 + x^519 + x^517 + x^515 + x^511 + x^510 + x^508 + x^506 + x^505 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^494 + x^493 + x^492 + x^491 + x^490 + x^488 + x^487 + x^484 + x^480 + x^478 + x^474 + x^472 + x^471 + x^466 + x^465 + x^464 + x^463 + x^461 + x^459 + x^458 + x^457 + x^454 + x^453 + x^446 + x^445 + x^441 + x^440 + x^439 + x^438 + x^437 + x^436 + x^435 + x^433 + x^428 + x^427 + x^426 + x^425 + x^414 + x^407 + x^406 + x^405 + x^403 + x^402 + x^401 + x^399 + x^398 + x^397 + x^395 + x^393 + x^392 + x^391 + x^390 + x^387 + x^385 + x^384 + x^383 + x^382 + x^379 + x^378 + x^376 + x^374 + x^373 + x^371 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^359 + x^357 + x^355 + x^354 + x^353 + x^350 + x^346 + x^345 + x^344 + x^343 + x^340 + x^338 + x^337 + x^336 + x^335 + x^330 + x^322 + x^321 + x^320 + x^317 + x^316 + x^311 + x^310 + x^309 + x^308 + x^307 + x^306 + x^305 + x^303 + x^299 + x^296 + x^295 + x^294 + x^293 + x^292 + x^289 + x^288 + x^284 + x^283 + x^282 + x^281 + x^280 + x^278 + x^277 + x^275 + x^269 + x^265 + x^263 + x^260 + x^258 + x^256 + x^255 + x^254 + x^253 + x^252 + x^250 + x^247 + x^246 + x^245 + x^242 + x^241 + x^240 + x^239 + x^234 + x^233 + x^232 + x^230 + x^226 + x^224 + x^222 + x^218 + x^217 + x^216 + x^215 + x^214 + x^213 + x^212 + x^211 + x^208 + x^204 + x^203 + x^202 + x^201 + x^200 + x^199 + x^198 + x^197 + x^194 + x^192 + x^191 + x^184 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^170 + x^168 + x^166 + x^161 + x^160 + x^157 + x^156 + x^153 + x^149 + x^148 + x^147 + x^145 + x^144 + x^143 + x^139 + x^137 + x^136 + x^134 + x^132 + x^131 + x^130 + x^129 + x^128 + x^127 + x^126 + x^125 + x^118 + x^117 + x^116 + x^115 + x^114 + x^113 + x^111 + x^107 + x^105 + x^104 + x^103 + x^101 + x^99 + x^98 + x^97 + x^96 + x^92 + x^91 + x^90 + x^89 + x^87 + x^86 + x^85 + x^84 + x^83 + x^82 + x^81 + x^79 + x^78 + x^76 + x^72 + x^70 + x^69 + x^68 + x^67 + x^65 + x^64 + x^62 + x^61 + x^58 + x^54 + x^53 + x^52 + x^50 + x^49 + x^48 + x^46 + x^44 + x^43 + x^40 + x^39 + x^38 + x^35 + x^32 + x^31 + x^30 + x^29 + x^28 + x^27 + x^25 + x^24 + x^18 + x^14 + x^10 + 1
+
+55-5-54 411 x^928 + x^898 + x^883 + x^870 + x^867 + x^854 + x^853 + x^840 + x^838 + x^837 + x^836 + x^834 + x^824 + x^822 + x^820 + x^812 + x^811 + x^810 + x^808 + x^807 + x^800 + x^797 + x^796 + x^795 + x^793 + x^792 + x^783 + x^779 + x^777 + x^776 + x^774 + x^770 + x^769 + x^768 + x^764 + x^762 + x^760 + x^754 + x^753 + x^752 + x^751 + x^749 + x^747 + x^746 + x^741 + x^740 + x^739 + x^738 + x^735 + x^734 + x^733 + x^732 + x^730 + x^728 + x^723 + x^721 + x^717 + x^715 + x^712 + x^711 + x^710 + x^709 + x^708 + x^707 + x^706 + x^704 + x^702 + x^701 + x^698 + x^697 + x^696 + x^694 + x^692 + x^690 + x^687 + x^683 + x^682 + x^681 + x^675 + x^674 + x^670 + x^669 + x^667 + x^666 + x^664 + x^663 + x^662 + x^657 + x^655 + x^654 + x^653 + x^652 + x^650 + x^646 + x^645 + x^644 + x^642 + x^637 + x^636 + x^635 + x^630 + x^629 + x^627 + x^626 + x^620 + x^615 + x^614 + x^612 + x^611 + x^610 + x^607 + x^606 + x^605 + x^604 + x^603 + x^601 + x^597 + x^594 + x^592 + x^591 + x^586 + x^584 + x^583 + x^582 + x^579 + x^577 + x^574 + x^573 + x^568 + x^565 + x^564 + x^563 + x^562 + x^557 + x^554 + x^553 + x^552 + x^550 + x^548 + x^546 + x^544 + x^543 + x^542 + x^540 + x^537 + x^536 + x^532 + x^531 + x^530 + x^524 + x^521 + x^520 + x^519 + x^517 + x^516 + x^515 + x^513 + x^512 + x^510 + x^509 + x^507 + x^505 + x^503 + x^502 + x^501 + x^500 + x^497 + x^496 + x^488 + x^486 + x^484 + x^481 + x^480 + x^478 + x^476 + x^475 + x^467 + x^465 + x^464 + x^463 + x^459 + x^458 + x^457 + x^455 + x^453 + x^452 + x^446 + x^445 + x^444 + x^441 + x^440 + x^439 + x^438 + x^434 + x^433 + x^432 + x^431 + x^427 + x^425 + x^421 + x^414 + x^412 + x^411 + x^409 + x^407 + x^406 + x^405 + x^403 + x^401 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^389 + x^385 + x^383 + x^380 + x^377 + x^376 + x^375 + x^374 + x^373 + x^372 + x^370 + x^367 + x^366 + x^365 + x^364 + x^363 + x^362 + x^360 + x^358 + x^356 + x^352 + x^351 + x^350 + x^349 + x^346 + x^342 + x^340 + x^338 + x^336 + x^335 + x^330 + x^329 + x^325 + x^324 + x^323 + x^321 + x^317 + x^314 + x^312 + x^307 + x^304 + x^303 + x^301 + x^298 + x^296 + x^295 + x^294 + x^293 + x^290 + x^289 + x^288 + x^287 + x^286 + x^285 + x^278 + x^277 + x^274 + x^273 + x^272 + x^270 + x^267 + x^265 + x^261 + x^260 + x^259 + x^258 + x^257 + x^256 + x^255 + x^254 + x^252 + x^249 + x^243 + x^241 + x^240 + x^239 + x^238 + x^235 + x^232 + x^231 + x^230 + x^227 + x^226 + x^224 + x^222 + x^221 + x^220 + x^219 + x^215 + x^214 + x^213 + x^211 + x^210 + x^209 + x^207 + x^206 + x^205 + x^200 + x^198 + x^195 + x^193 + x^192 + x^190 + x^186 + x^185 + x^181 + x^178 + x^176 + x^175 + x^172 + x^170 + x^169 + x^168 + x^166 + x^164 + x^158 + x^153 + x^152 + x^150 + x^149 + x^148 + x^147 + x^146 + x^143 + x^142 + x^140 + x^139 + x^136 + x^134 + x^133 + x^128 + x^125 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^112 + x^111 + x^107 + x^106 + x^103 + x^101 + x^100 + x^99 + x^98 + x^96 + x^95 + x^94 + x^93 + x^92 + x^89 + x^88 + x^87 + x^86 + x^85 + x^84 + x^81 + x^79 + x^77 + x^76 + x^74 + x^72 + x^71 + x^70 + x^69 + x^65 + x^64 + x^62 + x^55 + x^53 + x^49 + x^48 + x^46 + x^44 + x^43 + x^39 + x^38 + x^37 + x^35 + x^33 + x^32 + x^31 + x^29 + x^27 + x^26 + x^24 + x^23 + x^22 + x^20 + x^18 + x^17 + x^8 + 1
+
+14-19-11 415 x^928 + x^898 + x^882 + x^870 + x^863 + x^862 + x^860 + x^854 + x^852 + x^844 + x^843 + x^833 + x^832 + x^825 + x^822 + x^819 + x^817 + x^816 + x^813 + x^811 + x^802 + x^798 + x^797 + x^795 + x^794 + x^790 + x^789 + x^787 + x^786 + x^781 + x^778 + x^776 + x^773 + x^772 + x^771 + x^768 + x^759 + x^754 + x^749 + x^746 + x^744 + x^743 + x^741 + x^740 + x^735 + x^734 + x^733 + x^730 + x^729 + x^725 + x^722 + x^717 + x^714 + x^711 + x^706 + x^705 + x^698 + x^697 + x^695 + x^691 + x^687 + x^686 + x^683 + x^681 + x^675 + x^674 + x^673 + x^672 + x^671 + x^670 + x^667 + x^665 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^652 + x^649 + x^648 + x^645 + x^643 + x^642 + x^638 + x^636 + x^635 + x^634 + x^633 + x^632 + x^630 + x^629 + x^627 + x^626 + x^625 + x^624 + x^623 + x^622 + x^620 + x^617 + x^616 + x^615 + x^613 + x^612 + x^611 + x^608 + x^604 + x^603 + x^602 + x^599 + x^598 + x^597 + x^595 + x^594 + x^593 + x^592 + x^591 + x^590 + x^587 + x^586 + x^585 + x^584 + x^582 + x^580 + x^579 + x^578 + x^577 + x^570 + x^569 + x^568 + x^567 + x^566 + x^563 + x^562 + x^560 + x^558 + x^552 + x^550 + x^549 + x^546 + x^544 + x^543 + x^540 + x^537 + x^536 + x^535 + x^533 + x^532 + x^531 + x^530 + x^529 + x^527 + x^526 + x^522 + x^521 + x^519 + x^517 + x^514 + x^513 + x^512 + x^511 + x^510 + x^509 + x^507 + x^506 + x^504 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^494 + x^492 + x^491 + x^489 + x^488 + x^487 + x^485 + x^480 + x^479 + x^478 + x^475 + x^472 + x^463 + x^458 + x^455 + x^453 + x^452 + x^448 + x^443 + x^438 + x^436 + x^435 + x^432 + x^429 + x^428 + x^427 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^412 + x^411 + x^410 + x^406 + x^405 + x^404 + x^402 + x^401 + x^400 + x^399 + x^393 + x^388 + x^387 + x^386 + x^385 + x^384 + x^380 + x^379 + x^378 + x^376 + x^375 + x^373 + x^370 + x^368 + x^367 + x^365 + x^363 + x^362 + x^359 + x^358 + x^357 + x^356 + x^353 + x^350 + x^347 + x^343 + x^342 + x^341 + x^339 + x^338 + x^334 + x^333 + x^327 + x^325 + x^323 + x^321 + x^318 + x^317 + x^314 + x^310 + x^309 + x^308 + x^307 + x^306 + x^305 + x^304 + x^301 + x^300 + x^298 + x^295 + x^292 + x^288 + x^286 + x^285 + x^283 + x^282 + x^281 + x^278 + x^277 + x^275 + x^270 + x^269 + x^263 + x^260 + x^256 + x^254 + x^253 + x^250 + x^249 + x^248 + x^245 + x^244 + x^241 + x^239 + x^237 + x^233 + x^227 + x^225 + x^223 + x^222 + x^220 + x^219 + x^218 + x^216 + x^214 + x^212 + x^207 + x^203 + x^201 + x^200 + x^198 + x^197 + x^196 + x^195 + x^191 + x^189 + x^188 + x^184 + x^183 + x^181 + x^180 + x^179 + x^176 + x^174 + x^173 + x^170 + x^169 + x^168 + x^167 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^158 + x^157 + x^155 + x^154 + x^152 + x^151 + x^150 + x^147 + x^144 + x^143 + x^142 + x^140 + x^139 + x^138 + x^134 + x^131 + x^130 + x^129 + x^124 + x^123 + x^122 + x^121 + x^120 + x^116 + x^115 + x^114 + x^111 + x^110 + x^108 + x^106 + x^104 + x^103 + x^99 + x^98 + x^95 + x^93 + x^91 + x^87 + x^84 + x^83 + x^80 + x^77 + x^76 + x^75 + x^74 + x^73 + x^70 + x^65 + x^64 + x^63 + x^62 + x^61 + x^57 + x^56 + x^55 + x^53 + x^51 + x^50 + x^49 + x^47 + x^46 + x^45 + x^43 + x^42 + x^41 + x^39 + x^37 + x^36 + x^33 + x^31 + x^29 + x^28 + x^24 + x^23 + x^22 + x^21 + x^18 + x^17 + x^16 + x^11 + x^10 + 1
+
+34-37-5 415 x^928 + x^898 + x^889 + x^874 + x^870 + x^861 + x^846 + x^844 + x^839 + x^835 + x^833 + x^831 + x^818 + x^816 + x^812 + x^809 + x^808 + x^805 + x^804 + x^794 + x^792 + x^790 + x^788 + x^787 + x^784 + x^783 + x^778 + x^776 + x^775 + x^773 + x^772 + x^770 + x^769 + x^768 + x^764 + x^760 + x^759 + x^757 + x^756 + x^755 + x^754 + x^749 + x^748 + x^744 + x^740 + x^737 + x^735 + x^730 + x^729 + x^728 + x^727 + x^726 + x^725 + x^721 + x^720 + x^719 + x^718 + x^716 + x^715 + x^713 + x^712 + x^710 + x^709 + x^706 + x^699 + x^695 + x^689 + x^686 + x^682 + x^681 + x^680 + x^677 + x^674 + x^673 + x^672 + x^671 + x^665 + x^664 + x^663 + x^662 + x^661 + x^660 + x^657 + x^656 + x^651 + x^649 + x^646 + x^640 + x^639 + x^635 + x^634 + x^633 + x^632 + x^629 + x^628 + x^624 + x^623 + x^621 + x^620 + x^616 + x^615 + x^614 + x^613 + x^611 + x^610 + x^609 + x^607 + x^606 + x^605 + x^604 + x^601 + x^599 + x^597 + x^596 + x^595 + x^593 + x^591 + x^590 + x^585 + x^584 + x^583 + x^582 + x^580 + x^577 + x^576 + x^573 + x^569 + x^567 + x^564 + x^560 + x^559 + x^558 + x^557 + x^556 + x^555 + x^552 + x^551 + x^550 + x^547 + x^545 + x^544 + x^542 + x^541 + x^540 + x^539 + x^538 + x^535 + x^534 + x^533 + x^526 + x^523 + x^520 + x^518 + x^517 + x^515 + x^514 + x^513 + x^511 + x^510 + x^509 + x^504 + x^503 + x^502 + x^501 + x^496 + x^495 + x^494 + x^493 + x^492 + x^489 + x^485 + x^484 + x^482 + x^481 + x^478 + x^475 + x^472 + x^469 + x^468 + x^467 + x^465 + x^464 + x^462 + x^460 + x^455 + x^453 + x^452 + x^451 + x^449 + x^448 + x^447 + x^446 + x^445 + x^443 + x^442 + x^441 + x^438 + x^435 + x^434 + x^432 + x^431 + x^430 + x^427 + x^424 + x^423 + x^422 + x^419 + x^412 + x^411 + x^409 + x^408 + x^406 + x^405 + x^404 + x^403 + x^401 + x^400 + x^399 + x^393 + x^390 + x^389 + x^387 + x^385 + x^384 + x^380 + x^378 + x^376 + x^374 + x^372 + x^371 + x^370 + x^369 + x^366 + x^365 + x^360 + x^359 + x^357 + x^350 + x^349 + x^347 + x^346 + x^345 + x^344 + x^342 + x^341 + x^340 + x^337 + x^335 + x^334 + x^332 + x^331 + x^330 + x^328 + x^327 + x^325 + x^323 + x^322 + x^321 + x^320 + x^316 + x^314 + x^310 + x^308 + x^306 + x^305 + x^304 + x^301 + x^300 + x^295 + x^291 + x^290 + x^289 + x^288 + x^287 + x^283 + x^281 + x^280 + x^279 + x^277 + x^274 + x^272 + x^271 + x^268 + x^266 + x^264 + x^263 + x^261 + x^259 + x^255 + x^254 + x^253 + x^250 + x^249 + x^246 + x^244 + x^242 + x^241 + x^237 + x^233 + x^230 + x^229 + x^227 + x^223 + x^222 + x^217 + x^216 + x^208 + x^207 + x^206 + x^205 + x^204 + x^203 + x^198 + x^196 + x^192 + x^191 + x^190 + x^189 + x^188 + x^187 + x^186 + x^185 + x^182 + x^181 + x^180 + x^178 + x^175 + x^171 + x^166 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^157 + x^156 + x^149 + x^148 + x^146 + x^145 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^136 + x^135 + x^131 + x^130 + x^129 + x^127 + x^125 + x^124 + x^117 + x^115 + x^113 + x^110 + x^108 + x^107 + x^106 + x^105 + x^103 + x^99 + x^98 + x^95 + x^93 + x^90 + x^87 + x^84 + x^83 + x^81 + x^80 + x^79 + x^78 + x^77 + x^72 + x^71 + x^68 + x^65 + x^64 + x^63 + x^62 + x^59 + x^58 + x^56 + x^55 + x^54 + x^53 + x^52 + x^51 + x^46 + x^45 + x^44 + x^43 + x^40 + x^39 + x^36 + x^35 + x^33 + x^32 + x^31 + x^30 + x^27 + x^25 + x^24 + x^22 + x^18 + x^17 + x^14 + x^13 + x^12 + x^10 + 1
+
+37-3-56 415 x^928 + x^898 + x^878 + x^870 + x^862 + x^860 + x^849 + x^840 + x^831 + x^822 + x^819 + x^818 + x^811 + x^802 + x^801 + x^796 + x^795 + x^794 + x^793 + x^790 + x^789 + x^784 + x^781 + x^780 + x^777 + x^775 + x^772 + x^766 + x^760 + x^758 + x^755 + x^753 + x^752 + x^747 + x^745 + x^744 + x^743 + x^740 + x^738 + x^737 + x^736 + x^732 + x^730 + x^729 + x^728 + x^726 + x^721 + x^716 + x^715 + x^713 + x^712 + x^711 + x^710 + x^709 + x^706 + x^705 + x^702 + x^700 + x^699 + x^698 + x^697 + x^696 + x^693 + x^692 + x^690 + x^687 + x^686 + x^684 + x^683 + x^682 + x^681 + x^680 + x^678 + x^675 + x^674 + x^673 + x^672 + x^670 + x^669 + x^667 + x^664 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^654 + x^653 + x^652 + x^650 + x^649 + x^648 + x^645 + x^644 + x^641 + x^639 + x^635 + x^634 + x^631 + x^630 + x^629 + x^628 + x^622 + x^621 + x^620 + x^617 + x^616 + x^614 + x^610 + x^609 + x^608 + x^606 + x^604 + x^601 + x^600 + x^598 + x^597 + x^596 + x^593 + x^592 + x^590 + x^588 + x^587 + x^586 + x^585 + x^584 + x^583 + x^579 + x^578 + x^575 + x^574 + x^573 + x^569 + x^568 + x^566 + x^564 + x^563 + x^561 + x^559 + x^557 + x^556 + x^553 + x^552 + x^550 + x^548 + x^546 + x^543 + x^542 + x^541 + x^540 + x^538 + x^537 + x^536 + x^533 + x^532 + x^529 + x^528 + x^527 + x^525 + x^522 + x^520 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^509 + x^507 + x^506 + x^504 + x^503 + x^502 + x^499 + x^495 + x^494 + x^493 + x^492 + x^490 + x^486 + x^482 + x^481 + x^480 + x^479 + x^477 + x^476 + x^475 + x^474 + x^473 + x^472 + x^470 + x^468 + x^467 + x^463 + x^457 + x^453 + x^451 + x^448 + x^446 + x^445 + x^440 + x^438 + x^437 + x^434 + x^433 + x^432 + x^431 + x^430 + x^425 + x^424 + x^423 + x^417 + x^414 + x^409 + x^407 + x^406 + x^405 + x^402 + x^400 + x^399 + x^398 + x^397 + x^396 + x^395 + x^394 + x^391 + x^389 + x^387 + x^386 + x^384 + x^383 + x^379 + x^377 + x^372 + x^371 + x^369 + x^368 + x^366 + x^365 + x^364 + x^361 + x^359 + x^357 + x^354 + x^351 + x^348 + x^347 + x^340 + x^339 + x^337 + x^336 + x^334 + x^329 + x^327 + x^326 + x^325 + x^322 + x^320 + x^318 + x^315 + x^314 + x^313 + x^312 + x^310 + x^309 + x^308 + x^306 + x^305 + x^301 + x^300 + x^298 + x^294 + x^293 + x^292 + x^291 + x^288 + x^285 + x^284 + x^282 + x^279 + x^275 + x^272 + x^271 + x^270 + x^269 + x^268 + x^266 + x^259 + x^257 + x^254 + x^253 + x^251 + x^250 + x^248 + x^246 + x^244 + x^243 + x^242 + x^238 + x^237 + x^234 + x^233 + x^232 + x^231 + x^230 + x^227 + x^223 + x^222 + x^221 + x^219 + x^216 + x^215 + x^212 + x^207 + x^205 + x^203 + x^200 + x^199 + x^198 + x^196 + x^195 + x^193 + x^191 + x^187 + x^185 + x^183 + x^181 + x^179 + x^178 + x^177 + x^174 + x^171 + x^170 + x^168 + x^166 + x^165 + x^163 + x^160 + x^156 + x^155 + x^154 + x^151 + x^150 + x^149 + x^146 + x^145 + x^142 + x^141 + x^136 + x^135 + x^134 + x^132 + x^128 + x^127 + x^125 + x^121 + x^118 + x^117 + x^116 + x^113 + x^112 + x^111 + x^108 + x^106 + x^105 + x^104 + x^102 + x^101 + x^100 + x^99 + x^96 + x^95 + x^94 + x^89 + x^85 + x^83 + x^81 + x^80 + x^79 + x^69 + x^65 + x^63 + x^62 + x^61 + x^59 + x^58 + x^57 + x^56 + x^52 + x^49 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^37 + x^36 + x^33 + x^32 + x^28 + x^24 + x^23 + x^20 + x^18 + x^17 + x^14 + x^11 + x^10 + x^9 + x^8 + 1
+
+55-11-54 417 x^928 + x^898 + x^896 + x^870 + x^867 + x^866 + x^864 + x^853 + x^846 + x^837 + x^836 + x^835 + x^828 + x^826 + x^824 + x^823 + x^817 + x^814 + x^812 + x^810 + x^808 + x^807 + x^806 + x^805 + x^804 + x^803 + x^802 + x^800 + x^796 + x^791 + x^789 + x^786 + x^784 + x^781 + x^780 + x^777 + x^772 + x^771 + x^770 + x^767 + x^762 + x^761 + x^757 + x^753 + x^747 + x^742 + x^740 + x^739 + x^737 + x^736 + x^735 + x^734 + x^733 + x^731 + x^730 + x^725 + x^723 + x^722 + x^717 + x^715 + x^708 + x^707 + x^705 + x^704 + x^703 + x^699 + x^698 + x^695 + x^690 + x^689 + x^686 + x^685 + x^684 + x^682 + x^681 + x^680 + x^678 + x^677 + x^675 + x^669 + x^667 + x^666 + x^665 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^655 + x^654 + x^651 + x^650 + x^646 + x^645 + x^643 + x^641 + x^640 + x^639 + x^637 + x^634 + x^633 + x^632 + x^631 + x^627 + x^624 + x^622 + x^620 + x^617 + x^616 + x^615 + x^614 + x^613 + x^608 + x^601 + x^600 + x^599 + x^595 + x^592 + x^591 + x^590 + x^586 + x^580 + x^579 + x^578 + x^577 + x^576 + x^575 + x^571 + x^570 + x^569 + x^567 + x^566 + x^565 + x^564 + x^563 + x^562 + x^561 + x^560 + x^558 + x^557 + x^555 + x^554 + x^553 + x^552 + x^551 + x^550 + x^549 + x^545 + x^543 + x^542 + x^539 + x^537 + x^532 + x^530 + x^526 + x^525 + x^520 + x^519 + x^517 + x^515 + x^513 + x^511 + x^510 + x^508 + x^504 + x^502 + x^501 + x^498 + x^493 + x^492 + x^490 + x^489 + x^488 + x^487 + x^485 + x^484 + x^483 + x^481 + x^480 + x^479 + x^477 + x^475 + x^473 + x^472 + x^469 + x^468 + x^467 + x^466 + x^463 + x^462 + x^461 + x^459 + x^455 + x^453 + x^451 + x^450 + x^449 + x^445 + x^444 + x^443 + x^442 + x^441 + x^440 + x^437 + x^435 + x^434 + x^431 + x^430 + x^429 + x^427 + x^426 + x^422 + x^421 + x^420 + x^413 + x^410 + x^409 + x^408 + x^407 + x^405 + x^403 + x^402 + x^401 + x^397 + x^396 + x^393 + x^389 + x^386 + x^384 + x^380 + x^379 + x^376 + x^373 + x^372 + x^370 + x^369 + x^367 + x^365 + x^364 + x^363 + x^358 + x^356 + x^355 + x^354 + x^353 + x^349 + x^345 + x^342 + x^334 + x^332 + x^331 + x^329 + x^325 + x^324 + x^322 + x^316 + x^315 + x^314 + x^312 + x^310 + x^307 + x^306 + x^298 + x^297 + x^296 + x^294 + x^293 + x^292 + x^288 + x^285 + x^284 + x^283 + x^282 + x^279 + x^273 + x^271 + x^267 + x^262 + x^257 + x^255 + x^253 + x^252 + x^251 + x^250 + x^248 + x^247 + x^245 + x^244 + x^243 + x^240 + x^238 + x^237 + x^236 + x^234 + x^232 + x^229 + x^224 + x^223 + x^222 + x^221 + x^218 + x^216 + x^215 + x^213 + x^211 + x^210 + x^209 + x^207 + x^205 + x^203 + x^202 + x^201 + x^198 + x^195 + x^194 + x^193 + x^192 + x^190 + x^189 + x^187 + x^186 + x^185 + x^184 + x^183 + x^182 + x^181 + x^179 + x^177 + x^176 + x^175 + x^174 + x^172 + x^170 + x^167 + x^160 + x^157 + x^156 + x^153 + x^151 + x^150 + x^149 + x^143 + x^140 + x^137 + x^136 + x^134 + x^133 + x^129 + x^128 + x^124 + x^123 + x^120 + x^118 + x^117 + x^116 + x^115 + x^114 + x^112 + x^111 + x^110 + x^108 + x^105 + x^104 + x^102 + x^101 + x^100 + x^98 + x^97 + x^93 + x^92 + x^91 + x^90 + x^88 + x^87 + x^85 + x^81 + x^79 + x^77 + x^76 + x^74 + x^73 + x^72 + x^70 + x^65 + x^63 + x^62 + x^61 + x^59 + x^55 + x^53 + x^51 + x^50 + x^47 + x^46 + x^45 + x^44 + x^43 + x^40 + x^38 + x^34 + x^32 + x^30 + x^29 + x^28 + x^27 + x^24 + x^22 + x^21 + x^18 + x^17 + x^14 + x^11 + x^4 + 1
+
+30-3-41 419 x^928 + x^906 + x^898 + x^884 + x^879 + x^876 + x^870 + x^862 + x^854 + x^852 + x^849 + x^844 + x^835 + x^832 + x^829 + x^825 + x^822 + x^819 + x^818 + x^813 + x^812 + x^807 + x^805 + x^803 + x^802 + x^798 + x^795 + x^794 + x^792 + x^790 + x^789 + x^788 + x^786 + x^785 + x^778 + x^777 + x^769 + x^768 + x^762 + x^760 + x^753 + x^751 + x^748 + x^747 + x^746 + x^742 + x^738 + x^735 + x^734 + x^733 + x^731 + x^729 + x^726 + x^725 + x^723 + x^719 + x^718 + x^716 + x^713 + x^706 + x^703 + x^702 + x^701 + x^700 + x^699 + x^696 + x^693 + x^690 + x^687 + x^686 + x^685 + x^684 + x^682 + x^679 + x^677 + x^673 + x^672 + x^671 + x^670 + x^664 + x^659 + x^656 + x^653 + x^651 + x^650 + x^647 + x^643 + x^642 + x^639 + x^637 + x^635 + x^633 + x^630 + x^627 + x^625 + x^624 + x^621 + x^616 + x^615 + x^614 + x^613 + x^612 + x^607 + x^604 + x^603 + x^600 + x^597 + x^596 + x^595 + x^593 + x^592 + x^591 + x^588 + x^586 + x^583 + x^581 + x^580 + x^578 + x^575 + x^574 + x^571 + x^569 + x^568 + x^567 + x^566 + x^565 + x^564 + x^562 + x^560 + x^559 + x^558 + x^557 + x^555 + x^554 + x^553 + x^552 + x^550 + x^546 + x^545 + x^543 + x^542 + x^537 + x^535 + x^534 + x^532 + x^530 + x^527 + x^525 + x^523 + x^521 + x^520 + x^512 + x^506 + x^505 + x^504 + x^503 + x^501 + x^500 + x^499 + x^498 + x^497 + x^495 + x^494 + x^493 + x^489 + x^487 + x^485 + x^484 + x^479 + x^478 + x^477 + x^475 + x^474 + x^471 + x^470 + x^469 + x^468 + x^467 + x^466 + x^464 + x^462 + x^459 + x^458 + x^457 + x^456 + x^451 + x^449 + x^448 + x^447 + x^446 + x^443 + x^441 + x^440 + x^439 + x^437 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^427 + x^425 + x^424 + x^423 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^412 + x^410 + x^409 + x^405 + x^404 + x^402 + x^401 + x^400 + x^396 + x^394 + x^393 + x^391 + x^390 + x^389 + x^388 + x^387 + x^386 + x^385 + x^380 + x^379 + x^369 + x^368 + x^363 + x^362 + x^361 + x^360 + x^359 + x^355 + x^354 + x^351 + x^347 + x^346 + x^345 + x^342 + x^337 + x^336 + x^332 + x^328 + x^324 + x^322 + x^321 + x^319 + x^318 + x^317 + x^315 + x^312 + x^310 + x^309 + x^307 + x^303 + x^302 + x^300 + x^298 + x^295 + x^289 + x^288 + x^287 + x^286 + x^285 + x^284 + x^283 + x^282 + x^281 + x^276 + x^275 + x^273 + x^272 + x^271 + x^268 + x^265 + x^263 + x^262 + x^260 + x^259 + x^255 + x^254 + x^253 + x^252 + x^249 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^239 + x^236 + x^235 + x^233 + x^232 + x^231 + x^230 + x^224 + x^223 + x^222 + x^221 + x^218 + x^215 + x^214 + x^213 + x^209 + x^206 + x^204 + x^199 + x^197 + x^196 + x^194 + x^190 + x^186 + x^185 + x^183 + x^182 + x^181 + x^180 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^168 + x^167 + x^166 + x^165 + x^164 + x^163 + x^162 + x^161 + x^159 + x^158 + x^156 + x^155 + x^153 + x^151 + x^148 + x^144 + x^143 + x^142 + x^141 + x^139 + x^136 + x^135 + x^131 + x^129 + x^128 + x^127 + x^126 + x^125 + x^124 + x^123 + x^121 + x^119 + x^118 + x^116 + x^113 + x^111 + x^109 + x^107 + x^106 + x^103 + x^102 + x^100 + x^99 + x^98 + x^96 + x^93 + x^92 + x^90 + x^86 + x^85 + x^83 + x^82 + x^80 + x^76 + x^73 + x^72 + x^71 + x^70 + x^67 + x^66 + x^64 + x^61 + x^60 + x^59 + x^56 + x^53 + x^50 + x^49 + x^45 + x^44 + x^42 + x^39 + x^36 + x^35 + x^30 + x^28 + x^25 + x^22 + x^19 + x^18 + x^17 + x^15 + x^14 + x^11 + x^10 + x^5 + 1
+
+11-45-50 423 x^928 + x^898 + x^891 + x^870 + x^862 + x^861 + x^858 + x^857 + x^854 + x^851 + x^828 + x^825 + x^824 + x^822 + x^818 + x^814 + x^811 + x^808 + x^802 + x^800 + x^798 + x^797 + x^787 + x^786 + x^785 + x^783 + x^782 + x^781 + x^776 + x^772 + x^771 + x^770 + x^768 + x^765 + x^760 + x^758 + x^756 + x^754 + x^750 + x^749 + x^746 + x^742 + x^738 + x^737 + x^736 + x^735 + x^734 + x^732 + x^729 + x^723 + x^719 + x^718 + x^716 + x^715 + x^714 + x^713 + x^708 + x^707 + x^705 + x^704 + x^703 + x^702 + x^701 + x^700 + x^698 + x^697 + x^696 + x^694 + x^692 + x^688 + x^684 + x^683 + x^681 + x^680 + x^678 + x^666 + x^664 + x^663 + x^662 + x^660 + x^659 + x^658 + x^656 + x^654 + x^653 + x^652 + x^651 + x^650 + x^649 + x^647 + x^645 + x^642 + x^641 + x^639 + x^638 + x^637 + x^636 + x^634 + x^632 + x^631 + x^626 + x^625 + x^623 + x^620 + x^617 + x^616 + x^614 + x^612 + x^610 + x^609 + x^607 + x^605 + x^603 + x^601 + x^600 + x^598 + x^597 + x^596 + x^595 + x^594 + x^591 + x^589 + x^588 + x^586 + x^585 + x^584 + x^581 + x^579 + x^578 + x^577 + x^576 + x^575 + x^573 + x^572 + x^570 + x^569 + x^568 + x^566 + x^561 + x^559 + x^558 + x^557 + x^554 + x^552 + x^551 + x^550 + x^549 + x^548 + x^546 + x^544 + x^543 + x^541 + x^540 + x^538 + x^533 + x^531 + x^529 + x^528 + x^523 + x^519 + x^515 + x^512 + x^511 + x^510 + x^508 + x^507 + x^506 + x^501 + x^498 + x^497 + x^496 + x^495 + x^494 + x^492 + x^490 + x^489 + x^488 + x^487 + x^486 + x^485 + x^483 + x^477 + x^476 + x^474 + x^472 + x^470 + x^469 + x^467 + x^465 + x^462 + x^460 + x^458 + x^452 + x^451 + x^449 + x^447 + x^446 + x^445 + x^442 + x^441 + x^440 + x^437 + x^436 + x^434 + x^433 + x^431 + x^428 + x^427 + x^426 + x^425 + x^423 + x^422 + x^420 + x^419 + x^418 + x^417 + x^415 + x^414 + x^413 + x^412 + x^411 + x^409 + x^407 + x^404 + x^403 + x^402 + x^399 + x^398 + x^396 + x^395 + x^392 + x^391 + x^389 + x^388 + x^387 + x^386 + x^385 + x^384 + x^381 + x^379 + x^378 + x^377 + x^375 + x^373 + x^369 + x^367 + x^365 + x^364 + x^362 + x^359 + x^358 + x^357 + x^355 + x^351 + x^348 + x^347 + x^346 + x^345 + x^344 + x^343 + x^335 + x^334 + x^332 + x^328 + x^325 + x^324 + x^321 + x^319 + x^318 + x^316 + x^314 + x^312 + x^311 + x^310 + x^304 + x^300 + x^297 + x^296 + x^294 + x^293 + x^292 + x^291 + x^289 + x^288 + x^285 + x^283 + x^277 + x^276 + x^274 + x^271 + x^270 + x^269 + x^268 + x^265 + x^264 + x^260 + x^259 + x^258 + x^257 + x^256 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^244 + x^242 + x^238 + x^236 + x^233 + x^232 + x^231 + x^230 + x^229 + x^228 + x^227 + x^222 + x^220 + x^218 + x^214 + x^212 + x^209 + x^208 + x^207 + x^204 + x^203 + x^202 + x^200 + x^193 + x^190 + x^189 + x^188 + x^186 + x^185 + x^183 + x^178 + x^176 + x^174 + x^171 + x^169 + x^168 + x^166 + x^165 + x^163 + x^162 + x^161 + x^158 + x^156 + x^155 + x^154 + x^153 + x^150 + x^147 + x^146 + x^145 + x^141 + x^136 + x^134 + x^132 + x^128 + x^127 + x^126 + x^123 + x^120 + x^119 + x^114 + x^112 + x^111 + x^105 + x^104 + x^101 + x^100 + x^98 + x^97 + x^96 + x^95 + x^94 + x^92 + x^91 + x^88 + x^87 + x^85 + x^84 + x^83 + x^80 + x^78 + x^77 + x^76 + x^74 + x^73 + x^72 + x^68 + x^64 + x^62 + x^61 + x^60 + x^56 + x^55 + x^54 + x^53 + x^50 + x^46 + x^42 + x^41 + x^40 + x^39 + x^36 + x^32 + x^31 + x^30 + x^28 + x^25 + x^24 + x^16 + x^15 + x^14 + x^13 + x^10 + x^9 + x^6 + x^3 + 1
+
+50-19-47 423 x^928 + x^906 + x^898 + x^897 + x^884 + x^876 + x^870 + x^862 + x^854 + x^840 + x^836 + x^835 + x^832 + x^831 + x^830 + x^821 + x^814 + x^813 + x^812 + x^810 + x^808 + x^805 + x^803 + x^796 + x^794 + x^792 + x^791 + x^786 + x^785 + x^783 + x^777 + x^774 + x^773 + x^767 + x^766 + x^764 + x^762 + x^761 + x^760 + x^759 + x^758 + x^754 + x^750 + x^748 + x^747 + x^746 + x^743 + x^742 + x^739 + x^734 + x^732 + x^728 + x^727 + x^724 + x^722 + x^720 + x^718 + x^716 + x^714 + x^713 + x^712 + x^711 + x^709 + x^708 + x^705 + x^704 + x^702 + x^699 + x^698 + x^695 + x^694 + x^693 + x^692 + x^691 + x^688 + x^686 + x^683 + x^682 + x^681 + x^679 + x^676 + x^674 + x^672 + x^671 + x^668 + x^664 + x^663 + x^661 + x^659 + x^657 + x^656 + x^654 + x^652 + x^646 + x^645 + x^641 + x^638 + x^635 + x^634 + x^632 + x^629 + x^628 + x^619 + x^618 + x^617 + x^615 + x^613 + x^612 + x^610 + x^609 + x^607 + x^606 + x^605 + x^604 + x^603 + x^602 + x^598 + x^597 + x^596 + x^595 + x^593 + x^591 + x^590 + x^589 + x^584 + x^583 + x^582 + x^581 + x^580 + x^579 + x^576 + x^575 + x^573 + x^569 + x^568 + x^567 + x^565 + x^564 + x^562 + x^556 + x^554 + x^552 + x^551 + x^550 + x^548 + x^547 + x^546 + x^545 + x^542 + x^541 + x^540 + x^539 + x^537 + x^535 + x^534 + x^532 + x^528 + x^526 + x^525 + x^524 + x^522 + x^521 + x^519 + x^515 + x^513 + x^510 + x^508 + x^507 + x^506 + x^505 + x^504 + x^502 + x^501 + x^500 + x^499 + x^496 + x^495 + x^494 + x^492 + x^490 + x^489 + x^486 + x^485 + x^484 + x^483 + x^481 + x^479 + x^478 + x^476 + x^474 + x^471 + x^469 + x^467 + x^465 + x^463 + x^458 + x^456 + x^455 + x^454 + x^451 + x^449 + x^448 + x^443 + x^442 + x^440 + x^439 + x^437 + x^436 + x^433 + x^432 + x^431 + x^430 + x^428 + x^427 + x^426 + x^425 + x^424 + x^421 + x^420 + x^416 + x^415 + x^413 + x^412 + x^411 + x^410 + x^409 + x^408 + x^406 + x^405 + x^403 + x^400 + x^399 + x^398 + x^396 + x^395 + x^393 + x^391 + x^388 + x^387 + x^386 + x^381 + x^380 + x^377 + x^376 + x^375 + x^374 + x^373 + x^371 + x^370 + x^369 + x^368 + x^361 + x^359 + x^358 + x^357 + x^355 + x^352 + x^350 + x^348 + x^347 + x^346 + x^343 + x^342 + x^339 + x^337 + x^335 + x^334 + x^332 + x^329 + x^325 + x^324 + x^323 + x^322 + x^318 + x^317 + x^315 + x^314 + x^311 + x^310 + x^306 + x^304 + x^300 + x^299 + x^297 + x^295 + x^294 + x^289 + x^286 + x^283 + x^279 + x^278 + x^276 + x^275 + x^273 + x^269 + x^268 + x^266 + x^264 + x^260 + x^258 + x^257 + x^254 + x^252 + x^250 + x^248 + x^247 + x^246 + x^245 + x^241 + x^239 + x^237 + x^236 + x^235 + x^234 + x^232 + x^228 + x^227 + x^226 + x^225 + x^218 + x^215 + x^214 + x^212 + x^211 + x^210 + x^208 + x^206 + x^205 + x^204 + x^203 + x^201 + x^198 + x^196 + x^193 + x^192 + x^190 + x^189 + x^188 + x^184 + x^181 + x^180 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^169 + x^168 + x^166 + x^165 + x^164 + x^162 + x^160 + x^159 + x^158 + x^153 + x^150 + x^148 + x^147 + x^146 + x^143 + x^142 + x^139 + x^136 + x^135 + x^134 + x^133 + x^132 + x^126 + x^124 + x^121 + x^118 + x^116 + x^112 + x^109 + x^108 + x^107 + x^104 + x^101 + x^98 + x^97 + x^95 + x^93 + x^88 + x^86 + x^85 + x^84 + x^83 + x^78 + x^77 + x^73 + x^70 + x^69 + x^68 + x^66 + x^64 + x^63 + x^62 + x^58 + x^57 + x^53 + x^52 + x^50 + x^48 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^33 + x^26 + x^22 + x^21 + x^20 + x^18 + x^17 + x^10 + x^8 + 1
+
+52-27-13 427 x^928 + x^898 + x^870 + x^866 + x^858 + x^855 + x^854 + x^847 + x^844 + x^836 + x^833 + x^832 + x^829 + x^828 + x^825 + x^822 + x^818 + x^817 + x^814 + x^811 + x^808 + x^807 + x^800 + x^799 + x^798 + x^796 + x^795 + x^792 + x^789 + x^781 + x^777 + x^774 + x^770 + x^769 + x^768 + x^767 + x^765 + x^762 + x^759 + x^756 + x^755 + x^754 + x^752 + x^751 + x^748 + x^746 + x^745 + x^744 + x^740 + x^739 + x^738 + x^736 + x^735 + x^734 + x^732 + x^730 + x^729 + x^728 + x^724 + x^721 + x^719 + x^718 + x^717 + x^716 + x^713 + x^712 + x^710 + x^709 + x^706 + x^705 + x^704 + x^702 + x^701 + x^699 + x^698 + x^697 + x^695 + x^693 + x^690 + x^689 + x^687 + x^686 + x^685 + x^683 + x^682 + x^681 + x^680 + x^677 + x^676 + x^675 + x^674 + x^671 + x^669 + x^668 + x^667 + x^666 + x^665 + x^663 + x^660 + x^659 + x^655 + x^654 + x^653 + x^652 + x^650 + x^648 + x^647 + x^643 + x^642 + x^640 + x^639 + x^638 + x^635 + x^634 + x^633 + x^632 + x^630 + x^629 + x^628 + x^626 + x^624 + x^620 + x^618 + x^617 + x^616 + x^615 + x^612 + x^610 + x^607 + x^606 + x^604 + x^603 + x^602 + x^598 + x^597 + x^593 + x^589 + x^588 + x^587 + x^585 + x^583 + x^581 + x^580 + x^579 + x^578 + x^570 + x^569 + x^566 + x^565 + x^564 + x^563 + x^561 + x^559 + x^558 + x^557 + x^556 + x^555 + x^551 + x^550 + x^548 + x^547 + x^545 + x^544 + x^540 + x^539 + x^538 + x^537 + x^536 + x^535 + x^534 + x^532 + x^529 + x^528 + x^527 + x^526 + x^525 + x^524 + x^523 + x^522 + x^519 + x^517 + x^516 + x^515 + x^513 + x^512 + x^511 + x^507 + x^504 + x^502 + x^495 + x^493 + x^492 + x^491 + x^490 + x^489 + x^484 + x^483 + x^481 + x^480 + x^478 + x^466 + x^464 + x^463 + x^460 + x^459 + x^457 + x^455 + x^454 + x^451 + x^450 + x^448 + x^447 + x^435 + x^434 + x^433 + x^432 + x^431 + x^428 + x^424 + x^423 + x^422 + x^421 + x^420 + x^419 + x^414 + x^413 + x^412 + x^411 + x^410 + x^409 + x^407 + x^404 + x^401 + x^396 + x^395 + x^394 + x^391 + x^390 + x^389 + x^388 + x^385 + x^382 + x^379 + x^377 + x^372 + x^370 + x^367 + x^365 + x^362 + x^361 + x^357 + x^355 + x^354 + x^351 + x^349 + x^348 + x^345 + x^343 + x^342 + x^340 + x^338 + x^334 + x^330 + x^328 + x^324 + x^323 + x^320 + x^319 + x^318 + x^317 + x^315 + x^313 + x^310 + x^309 + x^307 + x^303 + x^302 + x^301 + x^300 + x^299 + x^298 + x^297 + x^296 + x^295 + x^292 + x^289 + x^288 + x^287 + x^285 + x^283 + x^280 + x^274 + x^273 + x^271 + x^267 + x^265 + x^264 + x^261 + x^259 + x^258 + x^256 + x^254 + x^253 + x^248 + x^247 + x^244 + x^239 + x^238 + x^237 + x^233 + x^232 + x^230 + x^229 + x^228 + x^227 + x^224 + x^221 + x^217 + x^216 + x^215 + x^214 + x^209 + x^207 + x^206 + x^205 + x^203 + x^201 + x^200 + x^199 + x^196 + x^195 + x^194 + x^192 + x^191 + x^190 + x^189 + x^187 + x^186 + x^182 + x^180 + x^177 + x^176 + x^174 + x^173 + x^170 + x^169 + x^168 + x^167 + x^164 + x^160 + x^154 + x^153 + x^152 + x^148 + x^144 + x^143 + x^142 + x^141 + x^140 + x^139 + x^135 + x^134 + x^133 + x^132 + x^129 + x^125 + x^124 + x^122 + x^121 + x^120 + x^118 + x^117 + x^116 + x^115 + x^112 + x^111 + x^110 + x^109 + x^108 + x^107 + x^106 + x^104 + x^103 + x^101 + x^96 + x^95 + x^93 + x^90 + x^87 + x^86 + x^82 + x^79 + x^77 + x^75 + x^70 + x^68 + x^67 + x^66 + x^62 + x^60 + x^57 + x^54 + x^53 + x^52 + x^51 + x^49 + x^46 + x^45 + x^43 + x^42 + x^41 + x^40 + x^39 + x^38 + x^36 + x^33 + x^31 + x^30 + x^29 + x^27 + x^26 + x^24 + x^22 + x^18 + x^7 + x^6 + 1
+
+54-9-25 433 x^928 + x^898 + x^875 + x^870 + x^860 + x^850 + x^847 + x^840 + x^835 + x^832 + x^822 + x^819 + x^815 + x^812 + x^808 + x^807 + x^805 + x^804 + x^800 + x^797 + x^794 + x^792 + x^791 + x^790 + x^787 + x^785 + x^782 + x^778 + x^777 + x^776 + x^771 + x^770 + x^767 + x^766 + x^764 + x^763 + x^760 + x^759 + x^757 + x^755 + x^754 + x^753 + x^752 + x^748 + x^743 + x^742 + x^739 + x^738 + x^737 + x^735 + x^734 + x^733 + x^731 + x^730 + x^729 + x^725 + x^724 + x^723 + x^720 + x^719 + x^717 + x^716 + x^714 + x^713 + x^711 + x^710 + x^709 + x^706 + x^705 + x^700 + x^699 + x^697 + x^696 + x^695 + x^693 + x^692 + x^691 + x^688 + x^687 + x^686 + x^685 + x^683 + x^682 + x^680 + x^676 + x^671 + x^670 + x^664 + x^663 + x^662 + x^661 + x^660 + x^658 + x^657 + x^656 + x^654 + x^653 + x^649 + x^648 + x^646 + x^645 + x^642 + x^637 + x^635 + x^633 + x^632 + x^630 + x^627 + x^624 + x^623 + x^621 + x^620 + x^619 + x^617 + x^615 + x^614 + x^613 + x^610 + x^609 + x^608 + x^607 + x^604 + x^602 + x^601 + x^600 + x^599 + x^593 + x^592 + x^591 + x^589 + x^585 + x^584 + x^580 + x^576 + x^575 + x^574 + x^570 + x^569 + x^566 + x^565 + x^564 + x^563 + x^562 + x^561 + x^559 + x^558 + x^554 + x^552 + x^551 + x^547 + x^546 + x^545 + x^543 + x^541 + x^540 + x^535 + x^532 + x^531 + x^530 + x^529 + x^525 + x^524 + x^523 + x^521 + x^520 + x^519 + x^518 + x^517 + x^516 + x^515 + x^513 + x^512 + x^510 + x^509 + x^504 + x^503 + x^502 + x^501 + x^500 + x^497 + x^496 + x^494 + x^493 + x^488 + x^487 + x^486 + x^484 + x^482 + x^481 + x^480 + x^479 + x^475 + x^472 + x^465 + x^464 + x^462 + x^461 + x^460 + x^457 + x^456 + x^455 + x^454 + x^452 + x^451 + x^450 + x^449 + x^448 + x^446 + x^445 + x^444 + x^443 + x^441 + x^438 + x^437 + x^436 + x^434 + x^432 + x^430 + x^427 + x^425 + x^424 + x^421 + x^420 + x^419 + x^418 + x^417 + x^414 + x^413 + x^410 + x^409 + x^407 + x^404 + x^403 + x^402 + x^401 + x^400 + x^399 + x^398 + x^396 + x^393 + x^392 + x^391 + x^390 + x^389 + x^385 + x^382 + x^381 + x^380 + x^379 + x^378 + x^375 + x^373 + x^372 + x^367 + x^366 + x^362 + x^358 + x^356 + x^355 + x^354 + x^353 + x^349 + x^348 + x^347 + x^342 + x^340 + x^339 + x^336 + x^334 + x^331 + x^329 + x^328 + x^327 + x^326 + x^325 + x^323 + x^319 + x^317 + x^316 + x^314 + x^313 + x^312 + x^310 + x^309 + x^308 + x^307 + x^302 + x^299 + x^298 + x^297 + x^296 + x^293 + x^291 + x^289 + x^288 + x^286 + x^285 + x^284 + x^282 + x^279 + x^274 + x^272 + x^271 + x^268 + x^266 + x^263 + x^261 + x^258 + x^255 + x^252 + x^251 + x^249 + x^248 + x^247 + x^246 + x^243 + x^242 + x^240 + x^237 + x^236 + x^234 + x^233 + x^232 + x^231 + x^228 + x^226 + x^223 + x^222 + x^221 + x^220 + x^219 + x^217 + x^216 + x^215 + x^213 + x^212 + x^210 + x^205 + x^203 + x^202 + x^199 + x^197 + x^195 + x^194 + x^193 + x^191 + x^189 + x^188 + x^187 + x^184 + x^182 + x^178 + x^173 + x^172 + x^170 + x^169 + x^167 + x^165 + x^162 + x^159 + x^158 + x^157 + x^156 + x^154 + x^149 + x^148 + x^145 + x^144 + x^141 + x^140 + x^135 + x^134 + x^133 + x^131 + x^130 + x^129 + x^127 + x^126 + x^123 + x^120 + x^119 + x^118 + x^117 + x^115 + x^110 + x^108 + x^106 + x^105 + x^104 + x^99 + x^97 + x^95 + x^89 + x^86 + x^84 + x^82 + x^78 + x^75 + x^71 + x^70 + x^69 + x^68 + x^65 + x^63 + x^62 + x^61 + x^59 + x^58 + x^51 + x^50 + x^49 + x^48 + x^47 + x^44 + x^43 + x^42 + x^39 + x^38 + x^37 + x^35 + x^30 + x^27 + x^25 + x^21 + x^19 + x^17 + x^16 + x^13 + x^12 + x^10 + x^8 + x^6 + 1
+
+56-43-35 433 x^928 + x^898 + x^896 + x^871 + x^870 + x^864 + x^848 + x^847 + x^846 + x^841 + x^840 + x^834 + x^833 + x^832 + x^829 + x^821 + x^814 + x^811 + x^808 + x^806 + x^803 + x^798 + x^797 + x^796 + x^792 + x^788 + x^786 + x^784 + x^783 + x^781 + x^779 + x^777 + x^776 + x^774 + x^773 + x^770 + x^769 + x^766 + x^762 + x^760 + x^756 + x^754 + x^752 + x^751 + x^749 + x^746 + x^745 + x^740 + x^737 + x^736 + x^734 + x^730 + x^727 + x^723 + x^721 + x^720 + x^718 + x^716 + x^714 + x^712 + x^709 + x^707 + x^706 + x^705 + x^704 + x^703 + x^702 + x^701 + x^700 + x^699 + x^697 + x^696 + x^695 + x^690 + x^689 + x^687 + x^685 + x^684 + x^682 + x^678 + x^675 + x^672 + x^670 + x^669 + x^668 + x^666 + x^665 + x^663 + x^662 + x^661 + x^659 + x^657 + x^655 + x^651 + x^650 + x^648 + x^646 + x^641 + x^639 + x^634 + x^632 + x^631 + x^630 + x^629 + x^626 + x^625 + x^623 + x^620 + x^619 + x^614 + x^612 + x^610 + x^609 + x^608 + x^607 + x^606 + x^604 + x^603 + x^602 + x^601 + x^600 + x^597 + x^596 + x^595 + x^594 + x^593 + x^591 + x^588 + x^585 + x^584 + x^583 + x^582 + x^581 + x^580 + x^578 + x^576 + x^574 + x^573 + x^572 + x^571 + x^570 + x^569 + x^563 + x^561 + x^560 + x^558 + x^556 + x^553 + x^552 + x^551 + x^550 + x^549 + x^546 + x^545 + x^544 + x^543 + x^542 + x^539 + x^538 + x^537 + x^536 + x^534 + x^532 + x^531 + x^529 + x^523 + x^519 + x^518 + x^517 + x^515 + x^514 + x^513 + x^512 + x^510 + x^509 + x^508 + x^503 + x^502 + x^501 + x^500 + x^499 + x^498 + x^496 + x^495 + x^494 + x^491 + x^490 + x^489 + x^487 + x^486 + x^484 + x^482 + x^481 + x^473 + x^471 + x^468 + x^466 + x^465 + x^464 + x^461 + x^460 + x^457 + x^456 + x^455 + x^453 + x^450 + x^448 + x^444 + x^442 + x^436 + x^435 + x^434 + x^433 + x^432 + x^431 + x^430 + x^429 + x^422 + x^421 + x^420 + x^419 + x^418 + x^417 + x^416 + x^414 + x^413 + x^412 + x^411 + x^409 + x^408 + x^407 + x^406 + x^404 + x^403 + x^402 + x^401 + x^398 + x^395 + x^392 + x^391 + x^389 + x^387 + x^385 + x^380 + x^377 + x^374 + x^372 + x^371 + x^369 + x^366 + x^363 + x^362 + x^361 + x^359 + x^358 + x^356 + x^355 + x^354 + x^353 + x^352 + x^350 + x^349 + x^348 + x^347 + x^345 + x^344 + x^343 + x^336 + x^334 + x^331 + x^330 + x^327 + x^325 + x^324 + x^322 + x^317 + x^310 + x^308 + x^307 + x^304 + x^301 + x^300 + x^299 + x^298 + x^297 + x^293 + x^290 + x^286 + x^284 + x^283 + x^282 + x^281 + x^279 + x^277 + x^275 + x^274 + x^270 + x^269 + x^267 + x^264 + x^262 + x^259 + x^254 + x^253 + x^248 + x^247 + x^245 + x^243 + x^242 + x^241 + x^237 + x^236 + x^232 + x^231 + x^230 + x^229 + x^228 + x^226 + x^225 + x^224 + x^223 + x^221 + x^218 + x^215 + x^214 + x^213 + x^212 + x^210 + x^208 + x^204 + x^202 + x^201 + x^199 + x^196 + x^195 + x^193 + x^192 + x^191 + x^190 + x^186 + x^184 + x^179 + x^178 + x^177 + x^176 + x^175 + x^174 + x^173 + x^171 + x^169 + x^167 + x^166 + x^165 + x^160 + x^158 + x^155 + x^154 + x^153 + x^152 + x^151 + x^150 + x^149 + x^148 + x^147 + x^145 + x^143 + x^140 + x^139 + x^138 + x^134 + x^132 + x^130 + x^129 + x^128 + x^127 + x^120 + x^118 + x^117 + x^115 + x^113 + x^112 + x^109 + x^108 + x^107 + x^106 + x^105 + x^101 + x^100 + x^96 + x^95 + x^94 + x^93 + x^91 + x^89 + x^88 + x^87 + x^85 + x^84 + x^83 + x^82 + x^81 + x^79 + x^77 + x^75 + x^74 + x^73 + x^72 + x^70 + x^68 + x^67 + x^65 + x^64 + x^63 + x^60 + x^58 + x^57 + x^56 + x^54 + x^53 + x^52 + x^50 + x^45 + x^44 + x^43 + x^41 + x^35 + x^30 + x^23 + x^20 + x^18 + x^15 + x^6 + 1
+
+44-9-45 441 x^928 + x^898 + x^890 + x^885 + x^880 + x^872 + x^870 + x^867 + x^860 + x^850 + x^847 + x^842 + x^837 + x^834 + x^830 + x^825 + x^824 + x^817 + x^816 + x^811 + x^808 + x^806 + x^802 + x^800 + x^798 + x^797 + x^794 + x^792 + x^790 + x^787 + x^786 + x^782 + x^778 + x^777 + x^776 + x^774 + x^773 + x^772 + x^771 + x^769 + x^768 + x^767 + x^765 + x^760 + x^759 + x^758 + x^757 + x^754 + x^750 + x^749 + x^747 + x^746 + x^745 + x^743 + x^741 + x^738 + x^737 + x^736 + x^734 + x^732 + x^725 + x^724 + x^722 + x^721 + x^720 + x^717 + x^716 + x^714 + x^713 + x^710 + x^708 + x^707 + x^705 + x^704 + x^702 + x^701 + x^699 + x^698 + x^696 + x^694 + x^692 + x^691 + x^690 + x^686 + x^683 + x^681 + x^679 + x^676 + x^674 + x^673 + x^672 + x^671 + x^668 + x^667 + x^665 + x^664 + x^663 + x^662 + x^661 + x^659 + x^658 + x^657 + x^655 + x^654 + x^652 + x^651 + x^648 + x^644 + x^643 + x^641 + x^640 + x^635 + x^634 + x^633 + x^632 + x^631 + x^630 + x^629 + x^628 + x^624 + x^621 + x^619 + x^618 + x^617 + x^616 + x^614 + x^611 + x^610 + x^608 + x^607 + x^599 + x^598 + x^596 + x^594 + x^590 + x^589 + x^588 + x^587 + x^586 + x^584 + x^581 + x^579 + x^578 + x^577 + x^575 + x^573 + x^572 + x^570 + x^569 + x^568 + x^567 + x^565 + x^564 + x^563 + x^562 + x^561 + x^559 + x^558 + x^554 + x^553 + x^552 + x^551 + x^549 + x^546 + x^544 + x^541 + x^537 + x^536 + x^535 + x^532 + x^531 + x^529 + x^526 + x^517 + x^516 + x^514 + x^511 + x^509 + x^507 + x^502 + x^501 + x^498 + x^497 + x^495 + x^494 + x^493 + x^491 + x^487 + x^486 + x^485 + x^484 + x^483 + x^482 + x^481 + x^480 + x^477 + x^474 + x^473 + x^470 + x^469 + x^467 + x^466 + x^465 + x^463 + x^462 + x^461 + x^460 + x^459 + x^457 + x^455 + x^454 + x^453 + x^451 + x^449 + x^448 + x^446 + x^443 + x^442 + x^440 + x^437 + x^436 + x^435 + x^434 + x^433 + x^431 + x^430 + x^427 + x^423 + x^419 + x^418 + x^414 + x^412 + x^411 + x^410 + x^409 + x^407 + x^406 + x^405 + x^402 + x^397 + x^395 + x^394 + x^389 + x^388 + x^384 + x^381 + x^380 + x^379 + x^378 + x^376 + x^373 + x^372 + x^371 + x^370 + x^368 + x^367 + x^366 + x^365 + x^364 + x^362 + x^361 + x^355 + x^354 + x^352 + x^350 + x^347 + x^345 + x^344 + x^343 + x^342 + x^339 + x^337 + x^335 + x^333 + x^332 + x^329 + x^327 + x^323 + x^322 + x^321 + x^320 + x^319 + x^316 + x^312 + x^310 + x^309 + x^308 + x^307 + x^305 + x^303 + x^302 + x^301 + x^298 + x^294 + x^293 + x^283 + x^282 + x^276 + x^275 + x^274 + x^271 + x^267 + x^264 + x^262 + x^261 + x^259 + x^258 + x^257 + x^256 + x^253 + x^252 + x^251 + x^250 + x^246 + x^245 + x^244 + x^243 + x^242 + x^241 + x^240 + x^238 + x^237 + x^236 + x^235 + x^233 + x^232 + x^229 + x^228 + x^225 + x^224 + x^223 + x^220 + x^216 + x^211 + x^210 + x^207 + x^205 + x^204 + x^202 + x^201 + x^200 + x^197 + x^196 + x^195 + x^194 + x^190 + x^189 + x^185 + x^183 + x^182 + x^181 + x^180 + x^179 + x^177 + x^176 + x^174 + x^173 + x^172 + x^171 + x^168 + x^167 + x^164 + x^163 + x^157 + x^156 + x^152 + x^151 + x^150 + x^148 + x^147 + x^146 + x^143 + x^142 + x^141 + x^140 + x^139 + x^138 + x^137 + x^135 + x^134 + x^133 + x^132 + x^129 + x^128 + x^127 + x^125 + x^122 + x^120 + x^119 + x^113 + x^112 + x^110 + x^109 + x^108 + x^107 + x^106 + x^105 + x^104 + x^101 + x^98 + x^97 + x^96 + x^93 + x^92 + x^91 + x^87 + x^83 + x^80 + x^78 + x^77 + x^74 + x^72 + x^66 + x^64 + x^63 + x^60 + x^59 + x^56 + x^51 + x^50 + x^49 + x^46 + x^43 + x^42 + x^41 + x^39 + x^38 + x^32 + x^31 + x^29 + x^28 + x^26 + x^24 + x^23 + x^21 + x^20 + x^19 + x^18 + x^15 + x^10 + 1
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput2 b/lib/stdlib/test/re_SUITE_data/testoutput2
index 811bbefc84..61ed8d9d4e 100644
--- a/lib/stdlib/test/re_SUITE_data/testoutput2
+++ b/lib/stdlib/test/re_SUITE_data/testoutput2
@@ -14705,4 +14705,20 @@ No options
No first char
No need char
+"(?<=(a))\1?b"
+ ab
+ 0: b
+ 1: a
+ aaab
+ 0: ab
+ 1: a
+
+"(?=(a))\1?b"
+ ab
+ 0: ab
+ 1: a
+ aaab
+ 0: ab
+ 1: a
+
/-- End of testinput2 --/
diff --git a/lib/stdlib/test/re_SUITE_data/testoutput5 b/lib/stdlib/test/re_SUITE_data/testoutput5
index bab989ca7e..090e1e1c85 100644
--- a/lib/stdlib/test/re_SUITE_data/testoutput5
+++ b/lib/stdlib/test/re_SUITE_data/testoutput5
@@ -1942,4 +1942,12 @@ Need char = 'z'
0: \x{17f}
0+
+/\C[^\v]+\x80/8
+ [AΏBŀC]
+No match
+
+/\C[^\d]+\x80/8
+ [AΏBŀC]
+No match
+
/-- End of testinput5 --/
diff --git a/lib/stdlib/test/stdlib.spec b/lib/stdlib/test/stdlib.spec
index 9c625091a8..4de7c1a0eb 100644
--- a/lib/stdlib/test/stdlib.spec
+++ b/lib/stdlib/test/stdlib.spec
@@ -1,4 +1,4 @@
{suites,"../stdlib_test",all}.
{skip_groups,"../stdlib_test",stdlib_bench_SUITE,
- [base64,gen_server,gen_statem,unicode],
+ [binary,base64,gen_server,gen_statem,unicode],
"Benchmark only"}.
diff --git a/lib/stdlib/test/stdlib_bench_SUITE.erl b/lib/stdlib/test/stdlib_bench_SUITE.erl
index 2364e8376f..b937eeb06a 100644
--- a/lib/stdlib/test/stdlib_bench_SUITE.erl
+++ b/lib/stdlib/test/stdlib_bench_SUITE.erl
@@ -29,7 +29,7 @@ suite() -> [{ct_hooks,[{ts_install_cth,[{nodenames,2}]}]}].
all() ->
- [{group,unicode},{group,base64},
+ [{group,unicode},{group,base64},{group,binary},
{group,gen_server},{group,gen_statem},
{group,gen_server_comparison},{group,gen_statem_comparison}].
@@ -38,6 +38,11 @@ groups() ->
[norm_nfc_list, norm_nfc_deep_l, norm_nfc_binary,
string_lexemes_list, string_lexemes_binary
]},
+ {binary, [{repeat, 5}],
+ [match_single_pattern_no_match,
+ matches_single_pattern_no_match,
+ matches_single_pattern_eventual_match,
+ matches_single_pattern_frequent_match]},
{base64,[{repeat,5}],
[decode_binary, decode_binary_to_string,
decode_list, decode_list_to_string,
@@ -157,41 +162,59 @@ norm_data(Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+match_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(binary, match, [Binary, <<"o">>])).
+
+matches_single_pattern_no_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsalp">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"o">>])).
+
+matches_single_pattern_eventual_match(_Config) ->
+ Binary = binary:copy(<<"ugbcfuysabfuqyfikgfsdalpaskfhgjsdgfjwsal\n">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"\n">>])).
+
+matches_single_pattern_frequent_match(_Config) ->
+ Binary = binary:copy(<<"abc\n">>, 1000000),
+ comment(test(binary, matches, [Binary, <<"abc">>])).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
decode_binary(_Config) ->
- comment(test(decode, encoded_binary())).
+ comment(test(base64, decode, [encoded_binary()])).
decode_binary_to_string(_Config) ->
- comment(test(decode_to_string, encoded_binary())).
+ comment(test(base64, decode_to_string, [encoded_binary()])).
decode_list(_Config) ->
- comment(test(decode, encoded_list())).
+ comment(test(base64, decode, [encoded_list()])).
decode_list_to_string(_Config) ->
- comment(test(decode_to_string, encoded_list())).
+ comment(test(base64, decode_to_string, [encoded_list()])).
encode_binary(_Config) ->
- comment(test(encode, binary())).
+ comment(test(base64, encode, [binary()])).
encode_binary_to_string(_Config) ->
- comment(test(encode_to_string, binary())).
+ comment(test(base64, encode_to_string, [binary()])).
encode_list(_Config) ->
- comment(test(encode, list())).
+ comment(test(base64, encode, [list()])).
encode_list_to_string(_Config) ->
- comment(test(encode_to_string, list())).
+ comment(test(base64, encode_to_string, [list()])).
mime_binary_decode(_Config) ->
- comment(test(mime_decode, encoded_binary())).
+ comment(test(base64, mime_decode, [encoded_binary()])).
mime_binary_decode_to_string(_Config) ->
- comment(test(mime_decode_to_string, encoded_binary())).
+ comment(test(base64, mime_decode_to_string, [encoded_binary()])).
mime_list_decode(_Config) ->
- comment(test(mime_decode, encoded_list())).
+ comment(test(base64, mime_decode, [encoded_list()])).
mime_list_decode_to_string(_Config) ->
- comment(test(mime_decode_to_string, encoded_list())).
+ comment(test(base64, mime_decode_to_string, [encoded_list()])).
-define(SIZE, 10000).
-define(N, 1000).
@@ -209,15 +232,15 @@ binary() ->
list() ->
random_byte_list(?SIZE).
-test(Func, Data) ->
- F = fun() -> loop(?N, Func, Data) end,
+test(Mod, Fun, Args) ->
+ F = fun() -> loop(?N, Mod, Fun, Args) end,
{Time, ok} = timer:tc(fun() -> lspawn(F) end),
- report_base64(Time).
+ report_mfa(Time, Mod).
-loop(0, _F, _D) -> garbage_collect(), ok;
-loop(N, F, D) ->
- _ = base64:F(D),
- loop(N - 1, F, D).
+loop(0, _M, _F, _A) -> garbage_collect(), ok;
+loop(N, M, F, A) ->
+ _ = apply(M, F, A),
+ loop(N - 1, M, F, A).
lspawn(Fun) ->
{Pid, Ref} = spawn_monitor(fun() -> exit(Fun()) end),
@@ -225,10 +248,10 @@ lspawn(Fun) ->
{'DOWN', Ref, process, Pid, Rep} -> Rep
end.
-report_base64(Time) ->
+report_mfa(Time, Mod) ->
Tps = round((?N*1000000)/Time),
ct_event:notify(#event{name = benchmark_data,
- data = [{suite, "stdlib_base64"},
+ data = [{suite, "stdlib_" ++ atom_to_list(Mod)},
{value, Tps}]}),
Tps.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index ed7dd04171..9370067910 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -2339,6 +2339,13 @@ order_of_children(_Config) ->
%% Test that a non-simple supervisor scales well for starting and
%% stopping many children.
scale_start_stop_many_children(_Config) ->
+ case erlang:system_info(build_type) of
+ opt -> scale_start_stop_many_children();
+ Other -> {skip,"Run on build type 'opt' only (current: '" ++
+ atom_to_list(Other)++"')"}
+ end.
+
+scale_start_stop_many_children() ->
process_flag(trap_exit, true),
{ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
N1 = 1000,
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index 3278eb0eb0..fcc4419569 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -219,7 +219,7 @@ spec_proc(Mod) ->
{Mod,system_get_state},{throw,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal),
+ ok = sync_terminate(Mod),
{ok,_} = Mod:start_link(4),
ok = case catch sys:replace_state(Mod, fun(_) -> {} end) of
{} ->
@@ -228,7 +228,7 @@ spec_proc(Mod) ->
{Mod,system_replace_state},{throw,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal),
+ ok = sync_terminate(Mod),
{ok,_} = Mod:start_link(4),
StateFun = fun(_) -> error(fail) end,
ok = case catch sys:replace_state(Mod, StateFun) of
@@ -240,7 +240,18 @@ spec_proc(Mod) ->
{'EXIT',{{callback_failed,StateFun,{error,fail}},_}} ->
ok
end,
- ok = sys:terminate(Mod, normal).
+ ok = sync_terminate(Mod).
+
+sync_terminate(Mod) ->
+ P = whereis(Mod),
+ MRef = erlang:monitor(process,P),
+ ok = sys:terminate(Mod, normal),
+ receive
+ {'DOWN',MRef,_,_,normal} ->
+ ok
+ end,
+ undefined = whereis(Mod),
+ ok.
%%%%%%%%%%%%%%%%%%%%
%% Dummy server
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
index d7d8f90de0..6847953c23 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/GraphemeBreakTest.txt
@@ -1,6 +1,6 @@
-# GraphemeBreakTest-10.0.0.txt
-# Date: 2017-04-14, 05:40:29 GMT
-# © 2017 Unicode®, Inc.
+# GraphemeBreakTest-11.0.0.txt
+# Date: 2018-03-18, 13:30:33 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -23,828 +23,678 @@
# These samples may be extended or changed in the future.
#
÷ 0020 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0020 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0020 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0020 × 0308 ÷ 000D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0020 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0020 × 0308 ÷ 000A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0020 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0001 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0020 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0020 × 0308 × 034F ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0020 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0600 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0020 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0020 × 0308 × 0903 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0020 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1100 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0020 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0020 × 0308 ÷ 1160 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0020 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0020 × 0308 ÷ 11A8 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0020 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0020 × 0308 ÷ AC00 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0020 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0020 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0020 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0020 × 0308 ÷ 261D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0020 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0020 ÷ 2640 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0020 × 0308 ÷ 2640 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0020 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0020 × 0308 ÷ 1F466 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0020 × 0308 ÷ AC01 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0020 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0020 × 0308 ÷ 231A ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0020 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 0308 × 0300 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 0308 × 200D ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0020 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0020 × 0308 ÷ 0378 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0020 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0020 × 0308 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0020 × 0308 ÷ D800 ÷ # ÷ [0.2] SPACE (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 000D ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 000D ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 000D × 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 000D ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 000D ÷ 034F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000D ÷ 0308 × 034F ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 000D ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 000D ÷ 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 000D ÷ 0308 × 0903 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 000D ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 000D ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 000D ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 000D ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 000D ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000D ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000D ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000D ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000D ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 000D ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 000D ÷ 231A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000D ÷ 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 0308 × 0300 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 000D ÷ 0308 × 200D ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 000D ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 000D ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000D ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000D ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 000A ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 000A ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 000A ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 000A ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 000A ÷ 034F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000A ÷ 0308 × 034F ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 000A ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 000A ÷ 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 000A ÷ 0308 × 0903 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 000A ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 000A ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 000A ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 000A ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 000A ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 000A ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 000A ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 000A ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 000A ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 000A ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 000A ÷ 231A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 000A ÷ 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 0308 × 0300 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 000A ÷ 0308 × 200D ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 000A ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 000A ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000A ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000A ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0001 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0001 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0001 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0001 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0001 ÷ 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0001 ÷ 034F ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0001 ÷ 0308 × 034F ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0001 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0001 ÷ 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0001 ÷ 0308 × 0903 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0001 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0001 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0001 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0001 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0001 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0001 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0001 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0001 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0001 ÷ 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0001 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0001 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0001 ÷ 231A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0001 ÷ 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 0308 × 0300 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0001 ÷ 0308 × 200D ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0001 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0001 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0001 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0300 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0300 × 0308 ÷ 261D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0300 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0300 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0300 × 0308 ÷ 2640 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0300 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0300 × 0308 ÷ 1F466 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0001 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <START OF HEADING> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 034F ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 034F × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 034F ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 034F × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 034F ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 034F × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 034F ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 034F × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 034F × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 034F × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 034F ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 034F × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 034F ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 034F × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 034F × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 034F × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 034F ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 034F × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 034F ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 034F × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 034F ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 034F × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 034F ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 034F × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 034F ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 034F × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 034F ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 034F × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 034F × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 034F × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 034F × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 034F × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 034F ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 034F × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 034F ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 034F × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAPHEME JOINER (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1F1E6 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1F1E6 × 0308 × 034F ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1F1E6 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 231A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0600 × 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] SPACE (Other) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0020 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0600 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0600 × 0308 ÷ 000D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0600 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0600 × 0308 ÷ 000A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0600 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0001 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0600 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0600 × 0308 × 034F ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0600 × 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0600 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0600 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0600 × 0308 × 0903 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0600 × 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1100 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0600 × 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0600 × 0308 ÷ 1160 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0600 × 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0600 × 0308 ÷ 11A8 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0600 × AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0600 × 0308 ÷ AC00 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0600 × AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0600 × 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0600 × 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0600 × 0308 ÷ 261D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0600 × 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0600 × 2640 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0600 × 0308 ÷ 2640 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0600 × 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] BOY (EBG) ÷ [0.3]
-÷ 0600 × 0308 ÷ 1F466 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0600 × 0308 ÷ AC01 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0600 × 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] WATCH (ExtPict) ÷ [0.3]
+÷ 0600 × 0308 ÷ 231A ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0600 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 0308 × 0300 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0600 × 0308 × 200D ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0600 × 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.2] <reserved-0378> (Other) ÷ [0.3]
-÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0600 × 0308 ÷ 0378 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0600 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0600 × 0308 ÷ D800 ÷ # ÷ [0.2] ARABIC NUMBER SIGN (Prepend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0903 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0020 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0903 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0903 × 0308 ÷ 000D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0903 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0903 × 0308 ÷ 000A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0903 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0001 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0903 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0903 × 0308 × 034F ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0903 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0600 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0903 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0903 × 0308 × 0903 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0903 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1100 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0903 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0903 × 0308 ÷ 1160 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0903 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0903 × 0308 ÷ 11A8 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0903 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0903 × 0308 ÷ AC00 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0903 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0903 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0903 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0903 × 0308 ÷ 261D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0903 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0903 ÷ 2640 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0903 × 0308 ÷ 2640 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0903 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0903 × 0308 ÷ 1F466 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0903 × 0308 ÷ AC01 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0903 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0903 × 0308 ÷ 231A ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0903 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 0308 × 0300 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0903 × 0308 × 200D ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0903 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0903 × 0308 ÷ 0378 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0903 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0903 × 0308 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0903 × 0308 ÷ D800 ÷ # ÷ [0.2] DEVANAGARI SIGN VISARGA (SpacingMark) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 1100 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1100 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1100 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 1100 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1100 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 1100 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1100 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1100 × 0308 × 034F ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 1100 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 1100 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1100 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1100 × 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1100 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 1100 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1100 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 1100 × AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1100 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 1100 × AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1100 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1100 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1100 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1100 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1100 ÷ 2640 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1100 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1100 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1100 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1100 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1100 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1100 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1100 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1100 × 0308 × 200D ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 1100 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1100 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 1100 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1100 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1100 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 1160 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1160 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 1160 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 1160 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 1160 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 1160 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 1160 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1160 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 1160 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 1160 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 1160 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 1160 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1160 × 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 1160 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 1160 × 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 1160 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 1160 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 1160 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 1160 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1160 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1160 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1160 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1160 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1160 ÷ 2640 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1160 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1160 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1160 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1160 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 1160 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1160 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 1160 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 1160 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 1160 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 1160 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 1160 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1160 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 1160 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JUNGSEONG FILLER (V) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 11A8 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 11A8 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 11A8 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 11A8 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 11A8 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 11A8 × 0308 × 034F ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 11A8 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 11A8 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 11A8 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 11A8 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 11A8 × 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 11A8 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 11A8 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 11A8 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 11A8 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 11A8 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 11A8 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 11A8 ÷ 2640 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 11A8 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 11A8 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 11A8 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 11A8 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 11A8 × 0308 × 200D ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 11A8 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 11A8 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 11A8 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 11A8 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 11A8 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL JONGSEONG KIYEOK (T) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ AC00 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ AC00 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ AC00 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ AC00 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ AC00 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ AC00 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ AC00 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC00 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ AC00 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ AC00 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ AC00 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ AC00 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC00 × 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ AC00 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ AC00 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ AC00 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ AC00 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ AC00 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ AC00 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC00 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC00 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC00 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC00 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC00 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ AC00 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ AC00 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ AC00 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ AC00 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ AC00 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC00 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC00 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ AC00 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ AC00 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ AC00 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ AC00 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ AC00 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ AC00 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ AC01 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0020 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ AC01 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ AC01 × 0308 ÷ 000D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ AC01 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ AC01 × 0308 ÷ 000A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ AC01 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0001 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ AC01 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC01 × 0308 × 034F ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ AC01 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0600 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ AC01 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ AC01 × 0308 × 0903 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ AC01 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC01 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ AC01 × 0308 ÷ 1160 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ AC01 × 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ AC01 × 0308 ÷ 11A8 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ AC01 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ AC01 × 0308 ÷ AC00 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ AC01 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ AC01 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ AC01 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC01 × 0308 ÷ 261D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ AC01 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ AC01 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ AC01 × 0308 ÷ 2640 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ AC01 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ AC01 × 0308 ÷ 1F466 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ AC01 × 0308 ÷ AC01 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ AC01 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC01 × 0308 ÷ 231A ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ AC01 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 0308 × 0300 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ AC01 × 0308 × 200D ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ AC01 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ AC01 × 0308 ÷ 0378 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ AC01 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F1E6 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0020 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F1E6 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 000D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F1E6 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 000A ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F1E6 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0001 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F1E6 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F1E6 × 0308 × 0300 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F1E6 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0600 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F1E6 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F1E6 × 0308 × 0903 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F1E6 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1100 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F1E6 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1160 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F1E6 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 11A8 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F1E6 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ AC00 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F1E6 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ AC01 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F1E6 × 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F1E6 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 261D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F1E6 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F1E6 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F1E6 × 0308 × 200D ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F1E6 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 2640 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F1E6 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 1F466 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F1E6 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ 0378 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F1E6 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F1E6 × 0308 ÷ D800 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 261D ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 261D × 0308 ÷ 0020 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 261D ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 261D × 0308 ÷ 000D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 261D ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 261D × 0308 ÷ 000A ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 261D ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 261D × 0308 ÷ 0001 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 261D × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 261D × 0308 × 0300 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 261D ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 261D × 0308 ÷ 0600 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 261D × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 261D × 0308 × 0903 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 261D ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 261D × 0308 ÷ 1100 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 261D ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 261D × 0308 ÷ 1160 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 261D ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 261D × 0308 ÷ 11A8 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 261D ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 261D × 0308 ÷ AC00 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 261D ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 261D × 0308 ÷ AC01 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 261D ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 261D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 261D ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 261D × 0308 ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 261D × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 261D × 0308 × 1F3FB ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 261D × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 261D × 0308 × 200D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 261D ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 261D × 0308 ÷ 2640 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 261D ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 261D × 0308 ÷ 1F466 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 261D ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 261D × 0308 ÷ 0378 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 261D ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 261D × 0308 ÷ D800 ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F3FB ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0020 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F3FB ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 000D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F3FB ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 000A ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F3FB ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0001 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F3FB × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F3FB × 0308 × 0300 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F3FB ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0600 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F3FB × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F3FB × 0308 × 0903 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F3FB ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1100 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F3FB ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1160 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F3FB ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 11A8 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F3FB ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ AC00 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F3FB ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ AC01 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F3FB ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F3FB ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 261D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F3FB ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F3FB ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F3FB × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F3FB × 0308 × 200D ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F3FB ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 2640 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F3FB ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 1F466 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F3FB ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ 0378 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F3FB ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F3FB × 0308 ÷ D800 ÷ # ÷ [0.2] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 200D ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 200D × 0308 ÷ 261D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 200D ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 0308 ÷ 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3]
-÷ 200D × 0308 ÷ 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 2640 ÷ 0020 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 2640 × 0308 ÷ 0020 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 2640 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 2640 × 0308 ÷ 000D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 2640 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 2640 × 0308 ÷ 000A ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 2640 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 2640 × 0308 ÷ 0001 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 2640 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 2640 × 0308 × 0300 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 2640 ÷ 0600 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 2640 × 0308 ÷ 0600 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 2640 × 0903 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 2640 × 0308 × 0903 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 2640 ÷ 1100 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 2640 × 0308 ÷ 1100 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 2640 ÷ 1160 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 2640 × 0308 ÷ 1160 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 2640 ÷ 11A8 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 2640 × 0308 ÷ 11A8 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 2640 ÷ AC00 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 2640 × 0308 ÷ AC00 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 2640 ÷ AC01 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 2640 × 0308 ÷ AC01 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 2640 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 2640 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 2640 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 2640 × 0308 ÷ 261D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 2640 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 2640 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 2640 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 2640 × 0308 × 200D ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 2640 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 2640 × 0308 ÷ 2640 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 2640 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 2640 × 0308 ÷ 1F466 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 2640 ÷ 0378 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 2640 × 0308 ÷ 0378 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 2640 ÷ D800 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 2640 × 0308 ÷ D800 ÷ # ÷ [0.2] FEMALE SIGN (Glue_After_Zwj) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F466 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0020 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 1F466 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 000D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 1F466 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 000A ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 1F466 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0001 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 1F466 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F466 × 0308 × 0300 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 1F466 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0600 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 1F466 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F466 × 0308 × 0903 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 1F466 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1100 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 1F466 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1160 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 1F466 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 11A8 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 1F466 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F466 × 0308 ÷ AC00 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 1F466 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F466 × 0308 ÷ AC01 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 1F466 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 1F466 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 261D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F466 × 0308 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 1F466 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F466 × 0308 × 200D ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 1F466 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 2640 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F466 × 0308 ÷ 0378 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 1F466 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 1F466 × 0308 ÷ D800 ÷ # ÷ [0.2] BOY (EBG) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ AC01 × 0308 ÷ D800 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 231A ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 231A × 0308 ÷ 0020 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 231A ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 231A × 0308 ÷ 000D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 231A ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 231A × 0308 ÷ 000A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 231A ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 231A × 0308 ÷ 0001 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 231A × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 231A × 0308 × 034F ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 231A ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 231A × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 231A ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 231A × 0308 ÷ 0600 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 231A × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 231A × 0308 × 0903 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 231A ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 231A × 0308 ÷ 1100 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 231A ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 231A × 0308 ÷ 1160 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 231A ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 231A × 0308 ÷ 11A8 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 231A ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 231A × 0308 ÷ AC00 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 231A ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 231A × 0308 ÷ AC01 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 231A ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 231A × 0308 ÷ 231A ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 231A × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 231A × 0308 × 0300 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 231A × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 231A × 0308 × 200D ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 231A ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 231A × 0308 ÷ 0378 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 231A ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 231A × 0308 ÷ D800 ÷ # ÷ [0.2] WATCH (ExtPict) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0300 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0020 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0300 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0300 × 0308 ÷ 000D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0300 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0300 × 0308 ÷ 000A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0300 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0001 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0300 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0300 × 0308 × 034F ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0300 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0300 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0600 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0300 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0300 × 0308 × 0903 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0300 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1100 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0300 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0300 × 0308 ÷ 1160 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0300 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0300 × 0308 ÷ 11A8 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0300 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0300 × 0308 ÷ AC00 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0300 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0300 × 0308 ÷ AC01 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0300 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0300 × 0308 ÷ 231A ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0300 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 0308 × 0300 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0300 × 0308 × 200D ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0300 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0300 × 0308 ÷ 0378 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0300 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0300 × 0308 ÷ D800 ÷ # ÷ [0.2] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 200D ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 200D × 0308 ÷ 0020 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 200D ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 200D × 0308 ÷ 000D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 200D ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 200D × 0308 ÷ 000A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 200D ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 200D × 0308 ÷ 0001 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 200D × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 200D × 0308 × 034F ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 200D ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 200D × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 200D ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 200D × 0308 ÷ 0600 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 200D × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 200D × 0308 × 0903 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 200D ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 200D × 0308 ÷ 1100 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 200D ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 200D × 0308 ÷ 1160 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 200D ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 200D × 0308 ÷ 11A8 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 200D ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 200D × 0308 ÷ AC00 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 200D ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 200D × 0308 ÷ AC01 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 200D ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 200D × 0308 ÷ 231A ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 200D × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 200D × 0308 × 0300 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 200D × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 200D × 0308 × 200D ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 200D ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 200D × 0308 ÷ 0378 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 200D ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 200D × 0308 ÷ D800 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ 0378 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] SPACE (Other) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0020 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 0378 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ 0378 × 0308 ÷ 000D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ 0378 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ 0378 × 0308 ÷ 000A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ 0378 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ 0378 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0001 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ 0378 × 034F ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0378 × 0308 × 034F ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ 0378 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0600 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ 0378 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ 0378 × 0308 × 0903 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ 0378 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1100 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 0378 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ 0378 × 0308 ÷ 1160 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ 0378 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ 0378 × 0308 ÷ 11A8 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ 0378 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ 0378 × 0308 ÷ AC00 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ 0378 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ 0378 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ 0378 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0378 × 0308 ÷ 261D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 0378 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F3FB ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 0378 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0378 ÷ 2640 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0378 × 0308 ÷ 2640 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 0378 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] BOY (EBG) ÷ [0.3]
-÷ 0378 × 0308 ÷ 1F466 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 0378 × 0308 ÷ AC01 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ 0378 ÷ 231A ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0378 × 0308 ÷ 231A ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ 0378 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 0308 × 0300 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0378 × 0308 × 200D ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ 0378 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
-÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ 0378 × 0308 ÷ 0378 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ 0378 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 0378 × 0308 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 0378 × 0308 ÷ D800 ÷ # ÷ [0.2] <reserved-0378> (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
÷ D800 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] SPACE (Other) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0020 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ D800 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 000D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
÷ D800 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 000A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [0.3]
÷ D800 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
-÷ D800 ÷ 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
-÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] COMBINING GRAVE ACCENT (Extend) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0001 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <START OF HEADING> (Control) ÷ [0.3]
+÷ D800 ÷ 034F ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ D800 ÷ 0308 × 034F ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAPHEME JOINER (Extend) ÷ [0.3]
+÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
÷ D800 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0600 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) ÷ [0.3]
÷ D800 ÷ 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
-÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
+÷ D800 ÷ 0308 × 0903 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [0.3]
÷ D800 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1100 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ D800 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 1160 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JUNGSEONG FILLER (V) ÷ [0.3]
÷ D800 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 11A8 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL JONGSEONG KIYEOK (T) ÷ [0.3]
÷ D800 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ AC00 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GA (LV) ÷ [0.3]
÷ D800 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
-÷ D800 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F1E6 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-÷ D800 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 261D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ D800 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F3FB ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ D800 ÷ 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ D800 ÷ 2640 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 2640 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ D800 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] BOY (EBG) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 1F466 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ AC01 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] HANGUL SYLLABLE GAG (LVT) ÷ [0.3]
+÷ D800 ÷ 231A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] WATCH (ExtPict) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 231A ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] WATCH (ExtPict) ÷ [0.3]
+÷ D800 ÷ 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 0308 × 0300 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] COMBINING GRAVE ACCENT (Extend_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ D800 ÷ 0308 × 200D ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
÷ D800 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <reserved-0378> (Other) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ 0378 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] <reserved-0378> (Other) ÷ [0.3]
÷ D800 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
-÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend) ÷ [0.3]
-÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [0.3]
-÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3]
-÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] SPACE (Other) ÷ [0.3]
+÷ D800 ÷ 0308 ÷ D800 ÷ # ÷ [0.2] <surrogate-D800> (Control) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [5.0] <surrogate-D800> (Control) ÷ [0.3]
+÷ 000D × 000A ÷ 0061 ÷ 000A ÷ 0308 ÷ # ÷ [0.2] <CARRIAGE RETURN (CR)> (CR) × [3.0] <LINE FEED (LF)> (LF) ÷ [4.0] LATIN SMALL LETTER A (Other) ÷ [5.0] <LINE FEED (LF)> (LF) ÷ [4.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0061 × 0308 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [0.3]
+÷ 0020 × 200D ÷ 0646 ÷ # ÷ [0.2] SPACE (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] ARABIC LETTER NOON (Other) ÷ [0.3]
+÷ 0646 × 200D ÷ 0020 ÷ # ÷ [0.2] ARABIC LETTER NOON (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] SPACE (Other) ÷ [0.3]
÷ 1100 × 1100 ÷ # ÷ [0.2] HANGUL CHOSEONG KIYEOK (L) × [6.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC00 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GA (LV) × [7.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ AC01 × 11A8 ÷ 1100 ÷ # ÷ [0.2] HANGUL SYLLABLE GAG (LVT) × [8.0] HANGUL JONGSEONG KIYEOK (T) ÷ [999.0] HANGUL CHOSEONG KIYEOK (L) ÷ [0.3]
÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [12.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 ÷ 1F1E6 × 1F1E7 × 200D ÷ 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 ÷ 1F1E6 × 200D ÷ 1F1E7 × 1F1E8 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 1F1E6 × 1F1E7 ÷ 1F1E8 × 1F1E9 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER B (RI) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER C (RI) × [13.0] REGIONAL INDICATOR SYMBOL LETTER D (RI) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ) ÷ [0.3]
-÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
+÷ 0061 × 200D ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [0.3]
+÷ 0061 × 0308 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 × 0903 ÷ 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.1] DEVANAGARI SIGN VISARGA (SpacingMark) ÷ [999.0] LATIN SMALL LETTER B (Other) ÷ [0.3]
÷ 0061 ÷ 0600 × 0062 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) ÷ [999.0] ARABIC NUMBER SIGN (Prepend) × [9.2] LATIN SMALL LETTER B (Other) ÷ [0.3]
-÷ 261D × 1F3FB ÷ 261D ÷ # ÷ [0.2] WHITE UP POINTING INDEX (E_Base) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [999.0] WHITE UP POINTING INDEX (E_Base) ÷ [0.3]
-÷ 1F466 × 1F3FB ÷ # ÷ [0.2] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 1F466 × 1F3FB ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) × [10.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (E_Modifier) ÷ [0.3]
-÷ 200D × 2640 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] FEMALE SIGN (Glue_After_Zwj) ÷ [0.3]
-÷ 200D × 1F466 ÷ # ÷ [0.2] ZERO WIDTH JOINER (ZWJ) × [11.0] BOY (EBG) ÷ [0.3]
-÷ 1F466 ÷ 1F466 ÷ # ÷ [0.2] BOY (EBG) ÷ [999.0] BOY (EBG) ÷ [0.3]
+÷ 1F476 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3]
+÷ 0061 × 1F3FF ÷ 1F476 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) ÷ [0.3]
+÷ 0061 × 1F3FF ÷ 1F476 × 200D × 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [999.0] BABY (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 1F476 × 1F3FF × 0308 × 200D × 1F476 × 1F3FF ÷ # ÷ [0.2] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) × [9.0] COMBINING DIAERESIS (Extend_ExtCccZwj) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] BABY (ExtPict) × [9.0] EMOJI MODIFIER FITZPATRICK TYPE-6 (Extend) ÷ [0.3]
+÷ 1F6D1 × 200D × 1F6D1 ÷ # ÷ [0.2] OCTAGONAL SIGN (ExtPict) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 0061 × 200D ÷ 1F6D1 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] OCTAGONAL SIGN (ExtPict) ÷ [0.3]
+÷ 2701 × 200D × 2701 ÷ # ÷ [0.2] UPPER BLADE SCISSORS (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) × [11.0] UPPER BLADE SCISSORS (Other) ÷ [0.3]
+÷ 0061 × 200D ÷ 2701 ÷ # ÷ [0.2] LATIN SMALL LETTER A (Other) × [9.0] ZERO WIDTH JOINER (ZWJ_ExtCccZwj) ÷ [999.0] UPPER BLADE SCISSORS (Other) ÷ [0.3]
#
-# Lines: 822
+# Lines: 672
#
# EOF
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
index 6715446aba..0e9e678a85 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/LineBreakTest.txt
@@ -1,6 +1,6 @@
-# LineBreakTest-10.0.0.txt
-# Date: 2017-04-14, 05:40:30 GMT
-# © 2017 Unicode®, Inc.
+# LineBreakTest-11.0.0.txt
+# Date: 2018-05-20, 09:03:09 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -6242,174 +6242,174 @@
× 0001 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 0001 × 0308 × 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 0001 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] <START OF HEADING> (CM1_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NUMBER SIGN (AL) ÷ [0.3]
× 200D × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D × 0308 × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
-× 200D ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0308 × 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0023 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
+× 200D × 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EM DASH (B2) ÷ [0.3]
× 200D × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
-× 200D × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 0308 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 2014 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EM DASH (B2) ÷ [0.3]
+× 200D × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <CHARACTER TABULATION> (BA) ÷ [0.3]
× 200D × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D × 0308 × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
-× 200D ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 × 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.01] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0009 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <CHARACTER TABULATION> (BA) ÷ [0.3]
+× 200D × 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ACUTE ACCENT (BB) ÷ [0.3]
× 200D × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
-× 200D × 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] ACUTE ACCENT (BB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00B4 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ACUTE ACCENT (BB) ÷ [0.3]
× 200D × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
× 200D × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D × 0308 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D × 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
-× 200D ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 0308 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
+× 200D × 0308 × 0020 × 000B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE TABULATION> (BK) ÷ [0.3]
+× 200D × FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
× 200D × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
-× 200D × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0308 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ FFFC ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
+× 200D × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] RIGHT CURLY BRACKET (CL) ÷ [0.3]
× 200D × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0308 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
-× 200D × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0308 × 0020 × 007D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT CURLY BRACKET (CL) ÷ [0.3]
+× 200D × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] RIGHT PARENTHESIS (CP) ÷ [0.3]
× 200D × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
-× 200D × 0308 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
-× 200D × 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] RIGHT PARENTHESIS (CP) ÷ [0.3]
+× 200D × 0308 × 0020 × 0029 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] RIGHT PARENTHESIS (CP) ÷ [0.3]
× 200D × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
× 200D × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0308 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
-× 200D × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 0308 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+× 200D × 0308 × 0020 × 000D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <CARRIAGE RETURN (CR)> (CR) ÷ [0.3]
+× 200D × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EXCLAMATION MARK (EX) ÷ [0.3]
× 200D × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 0308 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
-× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 0308 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 0308 × 0020 × 0021 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.01] EXCLAMATION MARK (EX) ÷ [0.3]
+× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NO-BREAK SPACE (GL) ÷ [0.3]
× 200D × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × 0308 × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL SYLLABLE GA (H2) ÷ [0.3]
× 200D × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D × 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
-× 200D ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 0308 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ AC00 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GA (H2) ÷ [0.3]
+× 200D × AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
× 200D × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
-× 200D × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 0308 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ AC01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL SYLLABLE GAG (H3) ÷ [0.3]
+× 200D × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HEBREW LETTER ALEF (HL) ÷ [0.3]
× 200D × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
-× 200D × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 05D0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HEBREW LETTER ALEF (HL) ÷ [0.3]
+× 200D × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HYPHEN-MINUS (HY) ÷ [0.3]
× 200D × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
-× 200D × 0308 × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.02] HYPHEN-MINUS (HY) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 002D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HYPHEN-MINUS (HY) ÷ [0.3]
× 200D × 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WATCH (ID) ÷ [0.3]
× 200D × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
-× 200D × 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
-× 200D × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 0308 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WATCH (ID) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 231A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WATCH (ID) ÷ [0.3]
+× 200D × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ONE DOT LEADER (IN) ÷ [0.3]
× 200D × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 0308 × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
-× 200D × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] COMMA (IS) ÷ [0.3]
+× 200D × 0308 × 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [22.01] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 2024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ONE DOT LEADER (IN) ÷ [0.3]
+× 200D × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMMA (IS) ÷ [0.3]
× 200D × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
-× 200D × 0308 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3]
-× 200D × 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
-× 200D ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 0308 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] COMMA (IS) ÷ [0.3]
+× 200D × 0308 × 0020 × 002C ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] COMMA (IS) ÷ [0.3]
+× 200D × 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
× 200D × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D × 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
-× 200D ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 0308 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1100 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL CHOSEONG KIYEOK (JL) ÷ [0.3]
+× 200D × 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
× 200D × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D × 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
-× 200D ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 11A8 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JONGSEONG KIYEOK (JT) ÷ [0.3]
+× 200D × 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
× 200D × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
-× 200D × 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1160 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HANGUL JUNGSEONG FILLER (JV) ÷ [0.3]
× 200D × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
× 200D × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-× 200D × 0308 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
-× 200D × 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+× 200D × 0308 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
+× 200D × 0308 × 0020 × 000A ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <LINE FEED (LF)> (LF) ÷ [0.3]
× 200D × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
× 200D × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 0308 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
-× 200D × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0308 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
+× 200D × 0308 × 0020 × 0085 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [6.0] <NEXT LINE (NEL)> (NL) ÷ [0.3]
+× 200D × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
× 200D × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
-× 200D × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0308 × 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.03] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 17D6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] KHMER SIGN CAMNUC PII KUUH (NS) ÷ [0.3]
+× 200D × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] DIGIT ZERO (NU) ÷ [0.3]
× 200D × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0308 × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
-× 200D × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0308 × 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [23.02] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0030 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DIGIT ZERO (NU) ÷ [0.3]
+× 200D × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] LEFT PARENTHESIS (OP) ÷ [0.3]
× 200D × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0308 × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
-× 200D × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0308 × 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [30.01] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0028 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] LEFT PARENTHESIS (OP) ÷ [0.3]
+× 200D × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] PERCENT SIGN (PO) ÷ [0.3]
× 200D × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0308 × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
-× 200D × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0308 × 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [24.03] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0025 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] PERCENT SIGN (PO) ÷ [0.3]
+× 200D × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] DOLLAR SIGN (PR) ÷ [0.3]
× 200D × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0308 × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
-× 200D × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [24.03] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0024 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] DOLLAR SIGN (PR) ÷ [0.3]
+× 200D × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] QUOTATION MARK (QU) ÷ [0.3]
× 200D × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
-× 200D × 0308 × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [19.01] QUOTATION MARK (QU) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0022 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] QUOTATION MARK (QU) ÷ [0.3]
× 200D × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3]
× 200D × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
-× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [0.3]
+× 200D × 0308 × 0020 × 0020 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.01] SPACE (SP) ÷ [0.3]
+× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SOLIDUS (SY) ÷ [0.3]
× 200D × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
-× 200D × 0308 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
-× 200D × 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
-× 200D × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 0308 × 0020 × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [13.02] SOLIDUS (SY) ÷ [0.3]
+× 200D × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WORD JOINER (WJ) ÷ [0.3]
× 200D × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
-× 200D × 0308 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
-× 200D × 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [11.01] WORD JOINER (WJ) ÷ [0.3]
+× 200D × 0308 × 0020 × 2060 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [11.01] WORD JOINER (WJ) ÷ [0.3]
× 200D × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
× 200D × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D × 0308 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D × 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
-× 200D ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
+× 200D × 0308 × 0020 × 200B ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) × [7.02] ZERO WIDTH SPACE (ZW) ÷ [0.3]
+× 200D × 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
× 200D × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-× 200D × 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1F1E6 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] REGIONAL INDICATOR SYMBOL LETTER A (RI) ÷ [0.3]
× 200D × 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] WHITE UP POINTING INDEX (EB) ÷ [0.3]
× 200D × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
-× 200D × 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
+× 200D × 0308 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 261D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] WHITE UP POINTING INDEX (EB) ÷ [0.3]
× 200D × 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
× 200D × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
-× 200D × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 0308 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) ÷ [999.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 1F3FB ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] EMOJI MODIFIER FITZPATRICK TYPE-1-2 (EM) ÷ [0.3]
+× 200D × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <START OF HEADING> (CM1_CM) ÷ [0.3]
× 200D × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 0308 × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
-× 200D × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 0308 × 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [9.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0001 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <START OF HEADING> (CM1_CM) ÷ [0.3]
+× 200D × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
× 200D × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 0308 × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
-× 200D × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 0308 × 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 200D ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) ÷ [0.3]
+× 200D × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SECTION SIGN (AI_AL) ÷ [0.3]
× 200D × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
-× 200D × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0308 × 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 00A7 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] SECTION SIGN (AI_AL) ÷ [0.3]
+× 200D × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] <reserved-50005> (XX_AL) ÷ [0.3]
× 200D × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0308 × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
-× 200D × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 0308 × 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 50005 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] <reserved-50005> (XX_AL) ÷ [0.3]
+× 200D × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
× 200D × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
-× 200D × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [28.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 0E01 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] THAI CHARACTER KO KAI (SA_AL) ÷ [0.3]
+× 200D × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 200D × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0308 × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
-× 200D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [21.03] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
+× 200D × 0308 × 0020 ÷ 3041 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 00A7 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
× 00A7 × 0020 ÷ 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [7.01] SPACE (SP) ÷ [18.0] NUMBER SIGN (AL) ÷ [0.3]
× 00A7 × 0308 × 0023 ÷ # × [0.3] SECTION SIGN (AI_AL) × [9.0] COMBINING DIAERESIS (CM1_CM) × [28.0] NUMBER SIGN (AL) ÷ [0.3]
@@ -7084,7 +7084,7 @@
× 3041 × 0308 × 0020 ÷ 3041 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [7.01] SPACE (SP) ÷ [18.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 000D × 000A ÷ 0061 × 000A ÷ 0308 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) × [5.01] <LINE FEED (LF)> (LF) ÷ [5.03] LATIN SMALL LETTER A (AL) × [6.0] <LINE FEED (LF)> (LF) ÷ [5.03] COMBINING DIAERESIS (CM1_CM) ÷ [0.3]
× 0061 × 0308 ÷ # × [0.3] LATIN SMALL LETTER A (AL) × [9.0] COMBINING DIAERESIS (CM1_CM) ÷ [0.3]
-× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [28.0] ARABIC LETTER NOON (AL) ÷ [0.3]
+× 0020 ÷ 200D × 0646 ÷ # × [0.3] SPACE (SP) ÷ [18.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] ARABIC LETTER NOON (AL) ÷ [0.3]
× 0646 × 200D × 0020 ÷ # × [0.3] ARABIC LETTER NOON (AL) × [9.0] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [7.01] SPACE (SP) ÷ [0.3]
× 000B ÷ 3041 ÷ # × [0.3] <LINE TABULATION> (BK) ÷ [4.0] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 000D ÷ 3041 ÷ # × [0.3] <CARRIAGE RETURN (CR)> (CR) ÷ [5.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
@@ -7093,8 +7093,8 @@
× 3041 × 2060 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [11.01] WORD JOINER (WJ) ÷ [0.3]
× 2060 × 3041 ÷ # × [0.3] WORD JOINER (WJ) × [11.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
× 3041 × 0308 × 00A0 ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) × [9.0] COMBINING DIAERESIS (CM1_CM) × [12.2] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [12.3] NO-BREAK SPACE (GL) ÷ [0.3]
-× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [13.04] SOLIDUS (SY) ÷ [0.3]
+× 200D × 00A0 ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] NO-BREAK SPACE (GL) ÷ [0.3]
+× 200D × 002F ÷ # × [0.3] ZERO WIDTH JOINER (ZWJ_O_ZWJ_CM) × [8.1] SOLIDUS (SY) ÷ [0.3]
× 2014 × 2014 ÷ # × [0.3] EM DASH (B2) × [17.0] EM DASH (B2) ÷ [0.3]
× 3041 ÷ FFFC ÷ # × [0.3] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [20.01] OBJECT REPLACEMENT CHARACTER (CB) ÷ [0.3]
× FFFC ÷ 3041 ÷ # × [0.3] OBJECT REPLACEMENT CHARACTER (CB) ÷ [20.02] HIRAGANA LETTER SMALL A (CJ_NS) ÷ [0.3]
diff --git a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
index 71f2371c5e..72a31bcdf1 100644
--- a/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
+++ b/lib/stdlib/test/unicode_util_SUITE_data/NormalizationTest.txt
@@ -1,6 +1,6 @@
-# NormalizationTest-10.0.0.txt
-# Date: 2017-03-08, 08:41:55 GMT
-# © 2017 Unicode®, Inc.
+# NormalizationTest-11.0.0.txt
+# Date: 2018-02-19, 18:33:08 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -17479,6 +17479,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 07F2 059A 0316 302A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062;0061 302A 07F2 0316 059A 0062; # (a◌߲◌֚◌̖◌〪b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; a◌〪◌߲◌̖◌֚b; ) LATIN SMALL LETTER A, NKO COMBINING NASALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 07F3 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062;00E0 05AE 07F3 0315 0062;0061 05AE 0300 07F3 0315 0062; # (a◌̕◌̀◌֮◌߳b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; à◌֮◌߳◌̕b; a◌֮◌̀◌߳◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NKO COMBINING DOUBLE DOT ABOVE, LATIN SMALL LETTER B
0061 07F3 0315 0300 05AE 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062;0061 05AE 07F3 0300 0315 0062; # (a◌߳◌̕◌̀◌֮b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; a◌֮◌߳◌̀◌̕b; ) LATIN SMALL LETTER A, NKO COMBINING DOUBLE DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 07FD 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062;0061 302A 0316 07FD 059A 0062; # (a◌֚◌̖◌〪◌߽b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; a◌〪◌̖◌߽◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, NKO DANTAYALAN, LATIN SMALL LETTER B
+0061 07FD 059A 0316 302A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062;0061 302A 07FD 0316 059A 0062; # (a◌߽◌֚◌̖◌〪b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; a◌〪◌߽◌̖◌֚b; ) LATIN SMALL LETTER A, NKO DANTAYALAN, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 0816 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062;00E0 05AE 0816 0315 0062;0061 05AE 0300 0816 0315 0062; # (a◌̕◌̀◌֮◌ࠖb; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; à◌֮◌ࠖ◌̕b; a◌֮◌̀◌ࠖ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN, LATIN SMALL LETTER B
0061 0816 0315 0300 05AE 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062;0061 05AE 0816 0300 0315 0062; # (a◌ࠖ◌̕◌̀◌֮b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; a◌֮◌ࠖ◌̀◌̕b; ) LATIN SMALL LETTER A, SAMARITAN MARK IN, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 0315 0300 05AE 0817 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062;00E0 05AE 0817 0315 0062;0061 05AE 0300 0817 0315 0062; # (a◌̕◌̀◌֮◌ࠗb; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; à◌֮◌ࠗ◌̕b; a◌֮◌̀◌ࠗ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SAMARITAN MARK IN-ALAF, LATIN SMALL LETTER B
@@ -17527,6 +17529,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 085A 059A 0316 302A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062;0061 302A 085A 0316 059A 0062; # (a◌࡚◌֚◌̖◌〪b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; a◌〪◌࡚◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC VOCALIZATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 059A 0316 302A 085B 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062;0061 302A 0316 085B 059A 0062; # (a◌֚◌̖◌〪◌࡛b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; a◌〪◌̖◌࡛◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANDAIC GEMINATION MARK, LATIN SMALL LETTER B
0061 085B 059A 0316 302A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062;0061 302A 085B 0316 059A 0062; # (a◌࡛◌֚◌̖◌〪b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; a◌〪◌࡛◌̖◌֚b; ) LATIN SMALL LETTER A, MANDAIC GEMINATION MARK, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 08D3 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062;0061 302A 0316 08D3 059A 0062; # (a◌֚◌̖◌〪◌࣓b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; a◌〪◌̖◌࣓◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, ARABIC SMALL LOW WAW, LATIN SMALL LETTER B
+0061 08D3 059A 0316 302A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062;0061 302A 08D3 0316 059A 0062; # (a◌࣓◌֚◌̖◌〪b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; a◌〪◌࣓◌̖◌֚b; ) LATIN SMALL LETTER A, ARABIC SMALL LOW WAW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 0315 0300 05AE 08D4 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062;00E0 05AE 08D4 0315 0062;0061 05AE 0300 08D4 0315 0062; # (a◌̕◌̀◌֮◌ࣔb; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; à◌֮◌ࣔ◌̕b; a◌֮◌̀◌ࣔ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH WORD AR-RUB, LATIN SMALL LETTER B
0061 08D4 0315 0300 05AE 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062;0061 05AE 08D4 0300 0315 0062; # (a◌ࣔ◌̕◌̀◌֮b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; a◌֮◌ࣔ◌̀◌̕b; ) LATIN SMALL LETTER A, ARABIC SMALL HIGH WORD AR-RUB, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 0315 0300 05AE 08D5 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062;00E0 05AE 08D5 0315 0062;0061 05AE 0300 08D5 0315 0062; # (a◌̕◌̀◌֮◌ࣕb; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; à◌֮◌ࣕ◌̕b; a◌֮◌̀◌ࣕ◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, ARABIC SMALL HIGH SAD, LATIN SMALL LETTER B
@@ -17629,6 +17633,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 09BC 3099 093C 0334 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062;0061 0334 09BC 093C 3099 0062; # (a◌়◌゙◌़◌̴b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; a◌̴◌়◌़◌゙b; ) LATIN SMALL LETTER A, BENGALI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 09CD 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062;0061 3099 094D 09CD 05B0 0062; # (a◌ְ◌्◌゙◌্b; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; a◌゙◌्◌্◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BENGALI SIGN VIRAMA, LATIN SMALL LETTER B
0061 09CD 05B0 094D 3099 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062;0061 3099 09CD 094D 05B0 0062; # (a◌্◌ְ◌्◌゙b; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; a◌゙◌্◌्◌ְb; ) LATIN SMALL LETTER A, BENGALI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 09FE 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062;00E0 05AE 09FE 0315 0062;0061 05AE 0300 09FE 0315 0062; # (a◌̕◌̀◌֮◌৾b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; à◌֮◌৾◌̕b; a◌֮◌̀◌৾◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, BENGALI SANDHI MARK, LATIN SMALL LETTER B
+0061 09FE 0315 0300 05AE 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062;0061 05AE 09FE 0300 0315 0062; # (a◌৾◌̕◌̀◌֮b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; a◌֮◌৾◌̀◌̕b; ) LATIN SMALL LETTER A, BENGALI SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 3099 093C 0334 0A3C 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062;0061 0334 093C 0A3C 3099 0062; # (a◌゙◌़◌̴◌਼b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; a◌̴◌़◌਼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GURMUKHI SIGN NUKTA, LATIN SMALL LETTER B
0061 0A3C 3099 093C 0334 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062;0061 0334 0A3C 093C 3099 0062; # (a◌਼◌゙◌़◌̴b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; a◌̴◌਼◌़◌゙b; ) LATIN SMALL LETTER A, GURMUKHI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 0A4D 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062;0061 3099 094D 0A4D 05B0 0062; # (a◌ְ◌्◌゙◌੍b; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; a◌゙◌्◌੍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GURMUKHI SIGN VIRAMA, LATIN SMALL LETTER B
@@ -18329,6 +18335,36 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 10AE5 0315 0300 05AE 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062;0061 05AE 10AE5 0300 0315 0062; # (a◌𐫥◌̕◌̀◌֮b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; a◌֮◌𐫥◌̀◌̕b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 059A 0316 302A 10AE6 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062;0061 302A 0316 10AE6 059A 0062; # (a◌֚◌̖◌〪◌𐫦b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; a◌〪◌̖◌𐫦◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, MANICHAEAN ABBREVIATION MARK BELOW, LATIN SMALL LETTER B
0061 10AE6 059A 0316 302A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062;0061 302A 10AE6 0316 059A 0062; # (a◌𐫦◌֚◌̖◌〪b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; a◌〪◌𐫦◌̖◌֚b; ) LATIN SMALL LETTER A, MANICHAEAN ABBREVIATION MARK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D24 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062;00E0 05AE 10D24 0315 0062;0061 05AE 0300 10D24 0315 0062; # (a◌̕◌̀◌֮◌𐴤b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; à◌֮◌𐴤◌̕b; a◌֮◌̀◌𐴤◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN HARBAHAY, LATIN SMALL LETTER B
+0061 10D24 0315 0300 05AE 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062;0061 05AE 10D24 0300 0315 0062; # (a◌𐴤◌̕◌̀◌֮b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; a◌֮◌𐴤◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN HARBAHAY, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D25 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062;00E0 05AE 10D25 0315 0062;0061 05AE 0300 10D25 0315 0062; # (a◌̕◌̀◌֮◌𐴥b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; à◌֮◌𐴥◌̕b; a◌֮◌̀◌𐴥◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TAHALA, LATIN SMALL LETTER B
+0061 10D25 0315 0300 05AE 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062;0061 05AE 10D25 0300 0315 0062; # (a◌𐴥◌̕◌̀◌֮b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; a◌֮◌𐴥◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TAHALA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D26 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062;00E0 05AE 10D26 0315 0062;0061 05AE 0300 10D26 0315 0062; # (a◌̕◌̀◌֮◌𐴦b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; à◌֮◌𐴦◌̕b; a◌֮◌̀◌𐴦◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TANA, LATIN SMALL LETTER B
+0061 10D26 0315 0300 05AE 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062;0061 05AE 10D26 0300 0315 0062; # (a◌𐴦◌̕◌̀◌֮b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; a◌֮◌𐴦◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TANA, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10D27 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062;00E0 05AE 10D27 0315 0062;0061 05AE 0300 10D27 0315 0062; # (a◌̕◌̀◌֮◌𐴧b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; à◌֮◌𐴧◌̕b; a◌֮◌̀◌𐴧◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, HANIFI ROHINGYA SIGN TASSI, LATIN SMALL LETTER B
+0061 10D27 0315 0300 05AE 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062;0061 05AE 10D27 0300 0315 0062; # (a◌𐴧◌̕◌̀◌֮b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; a◌֮◌𐴧◌̀◌̕b; ) LATIN SMALL LETTER A, HANIFI ROHINGYA SIGN TASSI, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F46 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062;0061 302A 0316 10F46 059A 0062; # (a◌֚◌̖◌〪◌𐽆b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; a◌〪◌̖◌𐽆◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING DOT BELOW, LATIN SMALL LETTER B
+0061 10F46 059A 0316 302A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062;0061 302A 10F46 0316 059A 0062; # (a◌𐽆◌֚◌̖◌〪b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; a◌〪◌𐽆◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F47 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062;0061 302A 0316 10F47 059A 0062; # (a◌֚◌̖◌〪◌𐽇b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; a◌〪◌̖◌𐽇◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING TWO DOTS BELOW, LATIN SMALL LETTER B
+0061 10F47 059A 0316 302A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062;0061 302A 10F47 0316 059A 0062; # (a◌𐽇◌֚◌̖◌〪b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; a◌〪◌𐽇◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F48 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062;00E0 05AE 10F48 0315 0062;0061 05AE 0300 10F48 0315 0062; # (a◌̕◌̀◌֮◌𐽈b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; à◌֮◌𐽈◌̕b; a◌֮◌̀◌𐽈◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING DOT ABOVE, LATIN SMALL LETTER B
+0061 10F48 0315 0300 05AE 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062;0061 05AE 10F48 0300 0315 0062; # (a◌𐽈◌̕◌̀◌֮b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; a◌֮◌𐽈◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING DOT ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F49 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062;00E0 05AE 10F49 0315 0062;0061 05AE 0300 10F49 0315 0062; # (a◌̕◌̀◌֮◌𐽉b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; à◌֮◌𐽉◌̕b; a◌֮◌̀◌𐽉◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING TWO DOTS ABOVE, LATIN SMALL LETTER B
+0061 10F49 0315 0300 05AE 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062;0061 05AE 10F49 0300 0315 0062; # (a◌𐽉◌̕◌̀◌֮b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; a◌֮◌𐽉◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING TWO DOTS ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F4A 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062;00E0 05AE 10F4A 0315 0062;0061 05AE 0300 10F4A 0315 0062; # (a◌̕◌̀◌֮◌𐽊b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; à◌֮◌𐽊◌̕b; a◌֮◌̀◌𐽊◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING CURVE ABOVE, LATIN SMALL LETTER B
+0061 10F4A 0315 0300 05AE 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062;0061 05AE 10F4A 0300 0315 0062; # (a◌𐽊◌̕◌̀◌֮b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; a◌֮◌𐽊◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4B 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062;0061 302A 0316 10F4B 059A 0062; # (a◌֚◌̖◌〪◌𐽋b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; a◌〪◌̖◌𐽋◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING CURVE BELOW, LATIN SMALL LETTER B
+0061 10F4B 059A 0316 302A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062;0061 302A 10F4B 0316 059A 0062; # (a◌𐽋◌֚◌̖◌〪b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; a◌〪◌𐽋◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING CURVE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 0315 0300 05AE 10F4C 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062;00E0 05AE 10F4C 0315 0062;0061 05AE 0300 10F4C 0315 0062; # (a◌̕◌̀◌֮◌𐽌b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; à◌֮◌𐽌◌̕b; a◌֮◌̀◌𐽌◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, SOGDIAN COMBINING HOOK ABOVE, LATIN SMALL LETTER B
+0061 10F4C 0315 0300 05AE 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062;0061 05AE 10F4C 0300 0315 0062; # (a◌𐽌◌̕◌̀◌֮b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; a◌֮◌𐽌◌̀◌̕b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK ABOVE, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4D 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062;0061 302A 0316 10F4D 059A 0062; # (a◌֚◌̖◌〪◌𐽍b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; a◌〪◌̖◌𐽍◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING HOOK BELOW, LATIN SMALL LETTER B
+0061 10F4D 059A 0316 302A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062;0061 302A 10F4D 0316 059A 0062; # (a◌𐽍◌֚◌̖◌〪b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; a◌〪◌𐽍◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4E 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062;0061 302A 0316 10F4E 059A 0062; # (a◌֚◌̖◌〪◌𐽎b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; a◌〪◌̖◌𐽎◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING LONG HOOK BELOW, LATIN SMALL LETTER B
+0061 10F4E 059A 0316 302A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062;0061 302A 10F4E 0316 059A 0062; # (a◌𐽎◌֚◌̖◌〪b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; a◌〪◌𐽎◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING LONG HOOK BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F4F 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062;0061 302A 0316 10F4F 059A 0062; # (a◌֚◌̖◌〪◌𐽏b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; a◌〪◌̖◌𐽏◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING RESH BELOW, LATIN SMALL LETTER B
+0061 10F4F 059A 0316 302A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062;0061 302A 10F4F 0316 059A 0062; # (a◌𐽏◌֚◌̖◌〪b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; a◌〪◌𐽏◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING RESH BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
+0061 059A 0316 302A 10F50 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062;0061 302A 0316 10F50 059A 0062; # (a◌֚◌̖◌〪◌𐽐b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; a◌〪◌̖◌𐽐◌֚b; ) LATIN SMALL LETTER A, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, SOGDIAN COMBINING STROKE BELOW, LATIN SMALL LETTER B
+0061 10F50 059A 0316 302A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062;0061 302A 10F50 0316 059A 0062; # (a◌𐽐◌֚◌̖◌〪b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; a◌〪◌𐽐◌̖◌֚b; ) LATIN SMALL LETTER A, SOGDIAN COMBINING STROKE BELOW, HEBREW ACCENT YETIV, COMBINING GRAVE ACCENT BELOW, IDEOGRAPHIC LEVEL TONE MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 11046 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062;0061 3099 094D 11046 05B0 0062; # (a◌ְ◌्◌゙◌𑁆b; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; a◌゙◌्◌𑁆◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI VIRAMA, LATIN SMALL LETTER B
0061 11046 05B0 094D 3099 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062;0061 3099 11046 094D 05B0 0062; # (a◌𑁆◌ְ◌्◌゙b; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; a◌゙◌𑁆◌्◌ְb; ) LATIN SMALL LETTER A, BRAHMI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 1107F 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062;0061 3099 094D 1107F 05B0 0062; # (a◌ְ◌्◌゙◌𑁿b; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; a◌゙◌्◌𑁿◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, BRAHMI NUMBER JOINER, LATIN SMALL LETTER B
@@ -18361,6 +18397,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 112E9 3099 093C 0334 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062;0061 0334 112E9 093C 3099 0062; # (a◌𑋩◌゙◌़◌̴b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; a◌̴◌𑋩◌़◌゙b; ) LATIN SMALL LETTER A, KHUDAWADI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 112EA 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062;0061 3099 094D 112EA 05B0 0062; # (a◌ְ◌्◌゙◌𑋪b; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; a◌゙◌्◌𑋪◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, KHUDAWADI SIGN VIRAMA, LATIN SMALL LETTER B
0061 112EA 05B0 094D 3099 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062;0061 3099 112EA 094D 05B0 0062; # (a◌𑋪◌ְ◌्◌゙b; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; a◌゙◌𑋪◌्◌ְb; ) LATIN SMALL LETTER A, KHUDAWADI SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 3099 093C 0334 1133B 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062;0061 0334 093C 1133B 3099 0062; # (a◌゙◌़◌̴◌𑌻b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; a◌̴◌़◌𑌻◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, COMBINING BINDU BELOW, LATIN SMALL LETTER B
+0061 1133B 3099 093C 0334 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062;0061 0334 1133B 093C 3099 0062; # (a◌𑌻◌゙◌़◌̴b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; a◌̴◌𑌻◌़◌゙b; ) LATIN SMALL LETTER A, COMBINING BINDU BELOW, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 3099 093C 0334 1133C 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062;0061 0334 093C 1133C 3099 0062; # (a◌゙◌़◌̴◌𑌼b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; a◌̴◌़◌𑌼◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, GRANTHA SIGN NUKTA, LATIN SMALL LETTER B
0061 1133C 3099 093C 0334 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062;0061 0334 1133C 093C 3099 0062; # (a◌𑌼◌゙◌़◌̴b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; a◌̴◌𑌼◌़◌゙b; ) LATIN SMALL LETTER A, GRANTHA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 1134D 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062;0061 3099 094D 1134D 05B0 0062; # (a◌ְ◌्◌゙𑍍b; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; a◌゙◌्𑍍◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GRANTHA SIGN VIRAMA, LATIN SMALL LETTER B
@@ -18393,6 +18431,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 11442 05B0 094D 3099 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062;0061 3099 11442 094D 05B0 0062; # (a◌𑑂◌ְ◌्◌゙b; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; a◌゙◌𑑂◌्◌ְb; ) LATIN SMALL LETTER A, NEWA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 3099 093C 0334 11446 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062;0061 0334 093C 11446 3099 0062; # (a◌゙◌़◌̴◌𑑆b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; a◌̴◌़◌𑑆◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, NEWA SIGN NUKTA, LATIN SMALL LETTER B
0061 11446 3099 093C 0334 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062;0061 0334 11446 093C 3099 0062; # (a◌𑑆◌゙◌़◌̴b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; a◌̴◌𑑆◌़◌゙b; ) LATIN SMALL LETTER A, NEWA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
+0061 0315 0300 05AE 1145E 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062;00E0 05AE 1145E 0315 0062;0061 05AE 0300 1145E 0315 0062; # (a◌̕◌̀◌֮◌𑑞b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; à◌֮◌𑑞◌̕b; a◌֮◌̀◌𑑞◌̕b; ) LATIN SMALL LETTER A, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, NEWA SANDHI MARK, LATIN SMALL LETTER B
+0061 1145E 0315 0300 05AE 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062;0061 05AE 1145E 0300 0315 0062; # (a◌𑑞◌̕◌̀◌֮b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; a◌֮◌𑑞◌̀◌̕b; ) LATIN SMALL LETTER A, NEWA SANDHI MARK, COMBINING COMMA ABOVE RIGHT, COMBINING GRAVE ACCENT, HEBREW ACCENT ZINOR, LATIN SMALL LETTER B
0061 05B0 094D 3099 114C2 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062;0061 3099 094D 114C2 05B0 0062; # (a◌ְ◌्◌゙◌𑓂b; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; a◌゙◌्◌𑓂◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, TIRHUTA SIGN VIRAMA, LATIN SMALL LETTER B
0061 114C2 05B0 094D 3099 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062;0061 3099 114C2 094D 05B0 0062; # (a◌𑓂◌ְ◌्◌゙b; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; a◌゙◌𑓂◌्◌ְb; ) LATIN SMALL LETTER A, TIRHUTA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 3099 093C 0334 114C3 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062;0061 0334 093C 114C3 3099 0062; # (a◌゙◌़◌̴◌𑓃b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; a◌̴◌़◌𑓃◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, TIRHUTA SIGN NUKTA, LATIN SMALL LETTER B
@@ -18409,6 +18449,10 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 116B7 3099 093C 0334 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062;0061 0334 116B7 093C 3099 0062; # (a◌𑚷◌゙◌़◌̴b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; a◌̴◌𑚷◌़◌゙b; ) LATIN SMALL LETTER A, TAKRI SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 1172B 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062;0061 3099 094D 1172B 05B0 0062; # (a◌ְ◌्◌゙◌𑜫b; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; a◌゙◌्◌𑜫◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, AHOM SIGN KILLER, LATIN SMALL LETTER B
0061 1172B 05B0 094D 3099 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062;0061 3099 1172B 094D 05B0 0062; # (a◌𑜫◌ְ◌्◌゙b; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; a◌゙◌𑜫◌्◌ְb; ) LATIN SMALL LETTER A, AHOM SIGN KILLER, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11839 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062;0061 3099 094D 11839 05B0 0062; # (a◌ְ◌्◌゙◌𑠹b; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; a◌゙◌्◌𑠹◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DOGRA SIGN VIRAMA, LATIN SMALL LETTER B
+0061 11839 05B0 094D 3099 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062;0061 3099 11839 094D 05B0 0062; # (a◌𑠹◌ְ◌्◌゙b; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; a◌゙◌𑠹◌्◌ְb; ) LATIN SMALL LETTER A, DOGRA SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 3099 093C 0334 1183A 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062;0061 0334 093C 1183A 3099 0062; # (a◌゙◌़◌̴◌𑠺b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; a◌̴◌़◌𑠺◌゙b; ) LATIN SMALL LETTER A, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, DOGRA SIGN NUKTA, LATIN SMALL LETTER B
+0061 1183A 3099 093C 0334 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062;0061 0334 1183A 093C 3099 0062; # (a◌𑠺◌゙◌़◌̴b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; a◌̴◌𑠺◌़◌゙b; ) LATIN SMALL LETTER A, DOGRA SIGN NUKTA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 05B0 094D 3099 11A34 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062;0061 3099 094D 11A34 05B0 0062; # (a◌ְ◌्◌゙◌𑨴b; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; a◌゙◌्◌𑨴◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SIGN VIRAMA, LATIN SMALL LETTER B
0061 11A34 05B0 094D 3099 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062;0061 3099 11A34 094D 05B0 0062; # (a◌𑨴◌ְ◌्◌゙b; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; a◌゙◌𑨴◌्◌ְb; ) LATIN SMALL LETTER A, ZANABAZAR SQUARE SIGN VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 11A47 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062;0061 3099 094D 11A47 05B0 0062; # (a◌ְ◌्◌゙◌𑩇b; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; a◌゙◌्◌𑩇◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, ZANABAZAR SQUARE SUBJOINER, LATIN SMALL LETTER B
@@ -18423,6 +18467,8 @@ FFEE;FFEE;FFEE;25CB;25CB; # (○; ○; ○; ○; ○; ) HALFWIDTH WHITE CIRCLE
0061 11D44 05B0 094D 3099 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062;0061 3099 11D44 094D 05B0 0062; # (a◌𑵄◌ְ◌्◌゙b; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; a◌゙◌𑵄◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI SIGN HALANTA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 05B0 094D 3099 11D45 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062;0061 3099 094D 11D45 05B0 0062; # (a◌ְ◌्◌゙◌𑵅b; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; a◌゙◌्◌𑵅◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, MASARAM GONDI VIRAMA, LATIN SMALL LETTER B
0061 11D45 05B0 094D 3099 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062;0061 3099 11D45 094D 05B0 0062; # (a◌𑵅◌ְ◌्◌゙b; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; a◌゙◌𑵅◌्◌ְb; ) LATIN SMALL LETTER A, MASARAM GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
+0061 05B0 094D 3099 11D97 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062;0061 3099 094D 11D97 05B0 0062; # (a◌ְ◌्◌゙◌𑶗b; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; a◌゙◌्◌𑶗◌ְb; ) LATIN SMALL LETTER A, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, GUNJALA GONDI VIRAMA, LATIN SMALL LETTER B
+0061 11D97 05B0 094D 3099 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062;0061 3099 11D97 094D 05B0 0062; # (a◌𑶗◌ְ◌्◌゙b; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; a◌゙◌𑶗◌्◌ְb; ) LATIN SMALL LETTER A, GUNJALA GONDI VIRAMA, HEBREW POINT SHEVA, DEVANAGARI SIGN VIRAMA, COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK, LATIN SMALL LETTER B
0061 093C 0334 16AF0 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062;0061 0334 16AF0 093C 0062; # (a◌़◌̴◌𖫰b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; a◌̴◌𖫰◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING HIGH TONE, LATIN SMALL LETTER B
0061 16AF0 093C 0334 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062;0061 16AF0 0334 093C 0062; # (a◌𖫰◌़◌̴b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; a◌𖫰◌̴◌़b; ) LATIN SMALL LETTER A, BASSA VAH COMBINING HIGH TONE, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, LATIN SMALL LETTER B
0061 093C 0334 16AF1 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062;0061 0334 16AF1 093C 0062; # (a◌़◌̴◌𖫱b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; a◌̴◌𖫱◌़b; ) LATIN SMALL LETTER A, DEVANAGARI SIGN NUKTA, COMBINING TILDE OVERLAY, BASSA VAH COMBINING LOW TONE, LATIN SMALL LETTER B
diff --git a/lib/stdlib/uc_spec/CaseFolding.txt b/lib/stdlib/uc_spec/CaseFolding.txt
index efdf18e441..cce350f49c 100644
--- a/lib/stdlib/uc_spec/CaseFolding.txt
+++ b/lib/stdlib/uc_spec/CaseFolding.txt
@@ -1,6 +1,6 @@
-# CaseFolding-10.0.0.txt
-# Date: 2017-04-14, 05:40:18 GMT
-# © 2017 Unicode®, Inc.
+# CaseFolding-11.0.0.txt
+# Date: 2018-01-31, 08:20:09 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -603,6 +603,52 @@
1C86; C; 044A; # CYRILLIC SMALL LETTER TALL HARD SIGN
1C87; C; 0463; # CYRILLIC SMALL LETTER TALL YAT
1C88; C; A64B; # CYRILLIC SMALL LETTER UNBLENDED UK
+1C90; C; 10D0; # GEORGIAN MTAVRULI CAPITAL LETTER AN
+1C91; C; 10D1; # GEORGIAN MTAVRULI CAPITAL LETTER BAN
+1C92; C; 10D2; # GEORGIAN MTAVRULI CAPITAL LETTER GAN
+1C93; C; 10D3; # GEORGIAN MTAVRULI CAPITAL LETTER DON
+1C94; C; 10D4; # GEORGIAN MTAVRULI CAPITAL LETTER EN
+1C95; C; 10D5; # GEORGIAN MTAVRULI CAPITAL LETTER VIN
+1C96; C; 10D6; # GEORGIAN MTAVRULI CAPITAL LETTER ZEN
+1C97; C; 10D7; # GEORGIAN MTAVRULI CAPITAL LETTER TAN
+1C98; C; 10D8; # GEORGIAN MTAVRULI CAPITAL LETTER IN
+1C99; C; 10D9; # GEORGIAN MTAVRULI CAPITAL LETTER KAN
+1C9A; C; 10DA; # GEORGIAN MTAVRULI CAPITAL LETTER LAS
+1C9B; C; 10DB; # GEORGIAN MTAVRULI CAPITAL LETTER MAN
+1C9C; C; 10DC; # GEORGIAN MTAVRULI CAPITAL LETTER NAR
+1C9D; C; 10DD; # GEORGIAN MTAVRULI CAPITAL LETTER ON
+1C9E; C; 10DE; # GEORGIAN MTAVRULI CAPITAL LETTER PAR
+1C9F; C; 10DF; # GEORGIAN MTAVRULI CAPITAL LETTER ZHAR
+1CA0; C; 10E0; # GEORGIAN MTAVRULI CAPITAL LETTER RAE
+1CA1; C; 10E1; # GEORGIAN MTAVRULI CAPITAL LETTER SAN
+1CA2; C; 10E2; # GEORGIAN MTAVRULI CAPITAL LETTER TAR
+1CA3; C; 10E3; # GEORGIAN MTAVRULI CAPITAL LETTER UN
+1CA4; C; 10E4; # GEORGIAN MTAVRULI CAPITAL LETTER PHAR
+1CA5; C; 10E5; # GEORGIAN MTAVRULI CAPITAL LETTER KHAR
+1CA6; C; 10E6; # GEORGIAN MTAVRULI CAPITAL LETTER GHAN
+1CA7; C; 10E7; # GEORGIAN MTAVRULI CAPITAL LETTER QAR
+1CA8; C; 10E8; # GEORGIAN MTAVRULI CAPITAL LETTER SHIN
+1CA9; C; 10E9; # GEORGIAN MTAVRULI CAPITAL LETTER CHIN
+1CAA; C; 10EA; # GEORGIAN MTAVRULI CAPITAL LETTER CAN
+1CAB; C; 10EB; # GEORGIAN MTAVRULI CAPITAL LETTER JIL
+1CAC; C; 10EC; # GEORGIAN MTAVRULI CAPITAL LETTER CIL
+1CAD; C; 10ED; # GEORGIAN MTAVRULI CAPITAL LETTER CHAR
+1CAE; C; 10EE; # GEORGIAN MTAVRULI CAPITAL LETTER XAN
+1CAF; C; 10EF; # GEORGIAN MTAVRULI CAPITAL LETTER JHAN
+1CB0; C; 10F0; # GEORGIAN MTAVRULI CAPITAL LETTER HAE
+1CB1; C; 10F1; # GEORGIAN MTAVRULI CAPITAL LETTER HE
+1CB2; C; 10F2; # GEORGIAN MTAVRULI CAPITAL LETTER HIE
+1CB3; C; 10F3; # GEORGIAN MTAVRULI CAPITAL LETTER WE
+1CB4; C; 10F4; # GEORGIAN MTAVRULI CAPITAL LETTER HAR
+1CB5; C; 10F5; # GEORGIAN MTAVRULI CAPITAL LETTER HOE
+1CB6; C; 10F6; # GEORGIAN MTAVRULI CAPITAL LETTER FI
+1CB7; C; 10F7; # GEORGIAN MTAVRULI CAPITAL LETTER YN
+1CB8; C; 10F8; # GEORGIAN MTAVRULI CAPITAL LETTER ELIFI
+1CB9; C; 10F9; # GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN
+1CBA; C; 10FA; # GEORGIAN MTAVRULI CAPITAL LETTER AIN
+1CBD; C; 10FD; # GEORGIAN MTAVRULI CAPITAL LETTER AEN
+1CBE; C; 10FE; # GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN
+1CBF; C; 10FF; # GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN
1E00; C; 1E01; # LATIN CAPITAL LETTER A WITH RING BELOW
1E02; C; 1E03; # LATIN CAPITAL LETTER B WITH DOT ABOVE
1E04; C; 1E05; # LATIN CAPITAL LETTER B WITH DOT BELOW
@@ -1180,6 +1226,7 @@ A7B2; C; 029D; # LATIN CAPITAL LETTER J WITH CROSSED-TAIL
A7B3; C; AB53; # LATIN CAPITAL LETTER CHI
A7B4; C; A7B5; # LATIN CAPITAL LETTER BETA
A7B6; C; A7B7; # LATIN CAPITAL LETTER OMEGA
+A7B8; C; A7B9; # LATIN CAPITAL LETTER U WITH STROKE
AB70; C; 13A0; # CHEROKEE SMALL LETTER A
AB71; C; 13A1; # CHEROKEE SMALL LETTER E
AB72; C; 13A2; # CHEROKEE SMALL LETTER I
@@ -1457,6 +1504,38 @@ FF3A; C; FF5A; # FULLWIDTH LATIN CAPITAL LETTER Z
118BD; C; 118DD; # WARANG CITI CAPITAL LETTER SSUU
118BE; C; 118DE; # WARANG CITI CAPITAL LETTER SII
118BF; C; 118DF; # WARANG CITI CAPITAL LETTER VIYO
+16E40; C; 16E60; # MEDEFAIDRIN CAPITAL LETTER M
+16E41; C; 16E61; # MEDEFAIDRIN CAPITAL LETTER S
+16E42; C; 16E62; # MEDEFAIDRIN CAPITAL LETTER V
+16E43; C; 16E63; # MEDEFAIDRIN CAPITAL LETTER W
+16E44; C; 16E64; # MEDEFAIDRIN CAPITAL LETTER ATIU
+16E45; C; 16E65; # MEDEFAIDRIN CAPITAL LETTER Z
+16E46; C; 16E66; # MEDEFAIDRIN CAPITAL LETTER KP
+16E47; C; 16E67; # MEDEFAIDRIN CAPITAL LETTER P
+16E48; C; 16E68; # MEDEFAIDRIN CAPITAL LETTER T
+16E49; C; 16E69; # MEDEFAIDRIN CAPITAL LETTER G
+16E4A; C; 16E6A; # MEDEFAIDRIN CAPITAL LETTER F
+16E4B; C; 16E6B; # MEDEFAIDRIN CAPITAL LETTER I
+16E4C; C; 16E6C; # MEDEFAIDRIN CAPITAL LETTER K
+16E4D; C; 16E6D; # MEDEFAIDRIN CAPITAL LETTER A
+16E4E; C; 16E6E; # MEDEFAIDRIN CAPITAL LETTER J
+16E4F; C; 16E6F; # MEDEFAIDRIN CAPITAL LETTER E
+16E50; C; 16E70; # MEDEFAIDRIN CAPITAL LETTER B
+16E51; C; 16E71; # MEDEFAIDRIN CAPITAL LETTER C
+16E52; C; 16E72; # MEDEFAIDRIN CAPITAL LETTER U
+16E53; C; 16E73; # MEDEFAIDRIN CAPITAL LETTER YU
+16E54; C; 16E74; # MEDEFAIDRIN CAPITAL LETTER L
+16E55; C; 16E75; # MEDEFAIDRIN CAPITAL LETTER Q
+16E56; C; 16E76; # MEDEFAIDRIN CAPITAL LETTER HP
+16E57; C; 16E77; # MEDEFAIDRIN CAPITAL LETTER NY
+16E58; C; 16E78; # MEDEFAIDRIN CAPITAL LETTER X
+16E59; C; 16E79; # MEDEFAIDRIN CAPITAL LETTER D
+16E5A; C; 16E7A; # MEDEFAIDRIN CAPITAL LETTER OE
+16E5B; C; 16E7B; # MEDEFAIDRIN CAPITAL LETTER N
+16E5C; C; 16E7C; # MEDEFAIDRIN CAPITAL LETTER R
+16E5D; C; 16E7D; # MEDEFAIDRIN CAPITAL LETTER O
+16E5E; C; 16E7E; # MEDEFAIDRIN CAPITAL LETTER AI
+16E5F; C; 16E7F; # MEDEFAIDRIN CAPITAL LETTER Y
1E900; C; 1E922; # ADLAM CAPITAL LETTER ALIF
1E901; C; 1E923; # ADLAM CAPITAL LETTER DAALI
1E902; C; 1E924; # ADLAM CAPITAL LETTER LAAM
diff --git a/lib/stdlib/uc_spec/CompositionExclusions.txt b/lib/stdlib/uc_spec/CompositionExclusions.txt
index ff42508686..ea63595bd3 100644
--- a/lib/stdlib/uc_spec/CompositionExclusions.txt
+++ b/lib/stdlib/uc_spec/CompositionExclusions.txt
@@ -1,5 +1,5 @@
-# CompositionExclusions-10.0.0.txt
-# Date: 2017-02-15, 00:00:00 GMT [KW, LI]
+# CompositionExclusions-11.0.0.txt
+# Date: 2017-12-06, 00:00:00 GMT [KW, LI]
# © 2017 Unicode®, Inc.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
diff --git a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
index 32bb12e47e..52052e6e33 100644
--- a/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
+++ b/lib/stdlib/uc_spec/GraphemeBreakProperty.txt
@@ -1,6 +1,6 @@
-# GraphemeBreakProperty-10.0.0.txt
-# Date: 2017-03-12, 07:03:41 GMT
-# © 2017 Unicode®, Inc.
+# GraphemeBreakProperty-11.0.0.txt
+# Date: 2018-03-16, 20:34:02 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -24,12 +24,13 @@
08E2 ; Prepend # Cf ARABIC DISPUTED END OF AYAH
0D4E ; Prepend # Lo MALAYALAM LETTER DOT REPH
110BD ; Prepend # Cf KAITHI NUMBER SIGN
+110CD ; Prepend # Cf KAITHI NUMBER SIGN ABOVE
111C2..111C3 ; Prepend # Lo [2] SHARADA SIGN JIHVAMULIYA..SHARADA SIGN UPADHMANIYA
11A3A ; Prepend # Lo ZANABAZAR SQUARE CLUSTER-INITIAL LETTER RA
11A86..11A89 ; Prepend # Lo [4] SOYOMBO CLUSTER-INITIAL LETTER RA..SOYOMBO CLUSTER-INITIAL LETTER SA
11D46 ; Prepend # Lo MASARAM GONDI REPHA
-# Total code points: 19
+# Total code points: 20
# ================================================
@@ -95,12 +96,13 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0730..074A ; Extend # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH
07A6..07B0 ; Extend # Mn [11] THAANA ABAFILI..THAANA SUKUN
07EB..07F3 ; Extend # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
+07FD ; Extend # Mn NKO DANTAYALAN
0816..0819 ; Extend # Mn [4] SAMARITAN MARK IN..SAMARITAN MARK DAGESH
081B..0823 ; Extend # Mn [9] SAMARITAN MARK EPENTHETIC YUT..SAMARITAN VOWEL SIGN A
0825..0827 ; Extend # Mn [3] SAMARITAN VOWEL SIGN SHORT A..SAMARITAN VOWEL SIGN U
0829..082D ; Extend # Mn [5] SAMARITAN VOWEL SIGN LONG I..SAMARITAN MARK NEQUDAA
0859..085B ; Extend # Mn [3] MANDAIC AFFRICATION MARK..MANDAIC GEMINATION MARK
-08D4..08E1 ; Extend # Mn [14] ARABIC SMALL HIGH WORD AR-RUB..ARABIC SMALL HIGH SIGN SAFHA
+08D3..08E1 ; Extend # Mn [15] ARABIC SMALL LOW WAW..ARABIC SMALL HIGH SIGN SAFHA
08E3..0902 ; Extend # Mn [32] ARABIC TURNED DAMMA BELOW..DEVANAGARI SIGN ANUSVARA
093A ; Extend # Mn DEVANAGARI VOWEL SIGN OE
093C ; Extend # Mn DEVANAGARI SIGN NUKTA
@@ -115,6 +117,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
09CD ; Extend # Mn BENGALI SIGN VIRAMA
09D7 ; Extend # Mc BENGALI AU LENGTH MARK
09E2..09E3 ; Extend # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL
+09FE ; Extend # Mn BENGALI SANDHI MARK
0A01..0A02 ; Extend # Mn [2] GURMUKHI SIGN ADAK BINDI..GURMUKHI SIGN BINDI
0A3C ; Extend # Mn GURMUKHI SIGN NUKTA
0A41..0A42 ; Extend # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU
@@ -145,6 +148,7 @@ E01F0..E0FFF ; Control # Cn [3600] <reserved-E01F0>..<reserved-E0FFF>
0BCD ; Extend # Mn TAMIL SIGN VIRAMA
0BD7 ; Extend # Mc TAMIL AU LENGTH MARK
0C00 ; Extend # Mn TELUGU SIGN COMBINING CANDRABINDU ABOVE
+0C04 ; Extend # Mn TELUGU SIGN COMBINING ANUSVARA ABOVE
0C3E..0C40 ; Extend # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II
0C46..0C48 ; Extend # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI
0C4A..0C4D ; Extend # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA
@@ -273,6 +277,7 @@ A80B ; Extend # Mn SYLOTI NAGRI SIGN ANUSVARA
A825..A826 ; Extend # Mn [2] SYLOTI NAGRI VOWEL SIGN U..SYLOTI NAGRI VOWEL SIGN E
A8C4..A8C5 ; Extend # Mn [2] SAURASHTRA SIGN VIRAMA..SAURASHTRA SIGN CANDRABINDU
A8E0..A8F1 ; Extend # Mn [18] COMBINING DEVANAGARI DIGIT ZERO..COMBINING DEVANAGARI SIGN AVAGRAHA
+A8FF ; Extend # Mn DEVANAGARI VOWEL SIGN AY
A926..A92D ; Extend # Mn [8] KAYAH LI VOWEL UE..KAYAH LI TONE CALYA PLOPHU
A947..A951 ; Extend # Mn [11] REJANG VOWEL SIGN I..REJANG CONSONANT SIGN R
A980..A982 ; Extend # Mn [3] JAVANESE SIGN PANYANGGA..JAVANESE SIGN LAYAR
@@ -309,6 +314,8 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
10A38..10A3A ; Extend # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
10A3F ; Extend # Mn KHAROSHTHI VIRAMA
10AE5..10AE6 ; Extend # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10D24..10D27 ; Extend # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10F46..10F50 ; Extend # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
11001 ; Extend # Mn BRAHMI SIGN ANUSVARA
11038..11046 ; Extend # Mn [15] BRAHMI VOWEL SIGN AA..BRAHMI VIRAMA
1107F..11081 ; Extend # Mn [3] BRAHMI NUMBER JOINER..KAITHI SIGN ANUSVARA
@@ -320,7 +327,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11173 ; Extend # Mn MAHAJANI SIGN NUKTA
11180..11181 ; Extend # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
111B6..111BE ; Extend # Mn [9] SHARADA VOWEL SIGN U..SHARADA VOWEL SIGN O
-111CA..111CC ; Extend # Mn [3] SHARADA SIGN NUKTA..SHARADA EXTRA SHORT VOWEL MARK
+111C9..111CC ; Extend # Mn [4] SHARADA SANDHI MARK..SHARADA EXTRA SHORT VOWEL MARK
1122F..11231 ; Extend # Mn [3] KHOJKI VOWEL SIGN U..KHOJKI VOWEL SIGN AI
11234 ; Extend # Mn KHOJKI SIGN ANUSVARA
11236..11237 ; Extend # Mn [2] KHOJKI SIGN NUKTA..KHOJKI SIGN SHADDA
@@ -328,7 +335,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
112DF ; Extend # Mn KHUDAWADI SIGN ANUSVARA
112E3..112EA ; Extend # Mn [8] KHUDAWADI VOWEL SIGN U..KHUDAWADI SIGN VIRAMA
11300..11301 ; Extend # Mn [2] GRANTHA SIGN COMBINING ANUSVARA ABOVE..GRANTHA SIGN CANDRABINDU
-1133C ; Extend # Mn GRANTHA SIGN NUKTA
+1133B..1133C ; Extend # Mn [2] COMBINING BINDU BELOW..GRANTHA SIGN NUKTA
1133E ; Extend # Mc GRANTHA VOWEL SIGN AA
11340 ; Extend # Mn GRANTHA VOWEL SIGN II
11357 ; Extend # Mc GRANTHA AU LENGTH MARK
@@ -337,6 +344,7 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11438..1143F ; Extend # Mn [8] NEWA VOWEL SIGN U..NEWA VOWEL SIGN AI
11442..11444 ; Extend # Mn [3] NEWA SIGN VIRAMA..NEWA SIGN ANUSVARA
11446 ; Extend # Mn NEWA SIGN NUKTA
+1145E ; Extend # Mn NEWA SANDHI MARK
114B0 ; Extend # Mc TIRHUTA VOWEL SIGN AA
114B3..114B8 ; Extend # Mn [6] TIRHUTA VOWEL SIGN U..TIRHUTA VOWEL SIGN VOCALIC LL
114BA ; Extend # Mn TIRHUTA VOWEL SIGN SHORT E
@@ -358,8 +366,9 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
1171D..1171F ; Extend # Mn [3] AHOM CONSONANT SIGN MEDIAL LA..AHOM CONSONANT SIGN MEDIAL LIGATING RA
11722..11725 ; Extend # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
11727..1172B ; Extend # Mn [5] AHOM VOWEL SIGN AW..AHOM SIGN KILLER
-11A01..11A06 ; Extend # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O
-11A09..11A0A ; Extend # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+1182F..11837 ; Extend # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+11839..1183A ; Extend # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
+11A01..11A0A ; Extend # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
11A33..11A38 ; Extend # Mn [6] ZANABAZAR SQUARE FINAL CONSONANT MARK..ZANABAZAR SQUARE SIGN ANUSVARA
11A3B..11A3E ; Extend # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
11A47 ; Extend # Mn ZANABAZAR SQUARE SUBJOINER
@@ -379,6 +388,10 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
11D3C..11D3D ; Extend # Mn [2] MASARAM GONDI VOWEL SIGN AI..MASARAM GONDI VOWEL SIGN O
11D3F..11D45 ; Extend # Mn [7] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI VIRAMA
11D47 ; Extend # Mn MASARAM GONDI RA-KARA
+11D90..11D91 ; Extend # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+11D95 ; Extend # Mn GUNJALA GONDI SIGN ANUSVARA
+11D97 ; Extend # Mn GUNJALA GONDI VIRAMA
+11EF3..11EF4 ; Extend # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
16AF0..16AF4 ; Extend # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16B30..16B36 ; Extend # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16F8F..16F92 ; Extend # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
@@ -403,10 +416,11 @@ FF9E..FF9F ; Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDT
1E026..1E02A ; Extend # Mn [5] COMBINING GLAGOLITIC LETTER YO..COMBINING GLAGOLITIC LETTER FITA
1E8D0..1E8D6 ; Extend # Mn [7] MENDE KIKAKUI COMBINING NUMBER TEENS..MENDE KIKAKUI COMBINING NUMBER MILLIONS
1E944..1E94A ; Extend # Mn [7] ADLAM ALIF LENGTHENER..ADLAM NUKTA
+1F3FB..1F3FF ; Extend # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
E0020..E007F ; Extend # Cf [96] TAG SPACE..CANCEL TAG
E0100..E01EF ; Extend # Mn [240] VARIATION SELECTOR-17..VARIATION SELECTOR-256
-# Total code points: 1901
+# Total code points: 1948
# ================================================
@@ -517,6 +531,7 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
110B0..110B2 ; SpacingMark # Mc [3] KAITHI VOWEL SIGN AA..KAITHI VOWEL SIGN II
110B7..110B8 ; SpacingMark # Mc [2] KAITHI VOWEL SIGN O..KAITHI VOWEL SIGN AU
1112C ; SpacingMark # Mc CHAKMA VOWEL SIGN E
+11145..11146 ; SpacingMark # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
11182 ; SpacingMark # Mc SHARADA SIGN VISARGA
111B3..111B5 ; SpacingMark # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
111BF..111C0 ; SpacingMark # Mc [2] SHARADA VOWEL SIGN AU..SHARADA SIGN VIRAMA
@@ -549,7 +564,8 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
116B6 ; SpacingMark # Mc TAKRI SIGN VIRAMA
11720..11721 ; SpacingMark # Mc [2] AHOM VOWEL SIGN A..AHOM VOWEL SIGN AA
11726 ; SpacingMark # Mc AHOM VOWEL SIGN E
-11A07..11A08 ; SpacingMark # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU
+1182C..1182E ; SpacingMark # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+11838 ; SpacingMark # Mc DOGRA SIGN VISARGA
11A39 ; SpacingMark # Mc ZANABAZAR SQUARE SIGN VISARGA
11A57..11A58 ; SpacingMark # Mc [2] SOYOMBO VOWEL SIGN AI..SOYOMBO VOWEL SIGN AU
11A97 ; SpacingMark # Mc SOYOMBO SIGN VISARGA
@@ -558,11 +574,15 @@ ABEC ; SpacingMark # Mc MEETEI MAYEK LUM IYEK
11CA9 ; SpacingMark # Mc MARCHEN SUBJOINED LETTER YA
11CB1 ; SpacingMark # Mc MARCHEN VOWEL SIGN I
11CB4 ; SpacingMark # Mc MARCHEN VOWEL SIGN O
+11D8A..11D8E ; SpacingMark # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+11D93..11D94 ; SpacingMark # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+11D96 ; SpacingMark # Mc GUNJALA GONDI SIGN VISARGA
+11EF5..11EF6 ; SpacingMark # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
16F51..16F7E ; SpacingMark # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
1D166 ; SpacingMark # Mc MUSICAL SYMBOL COMBINING SPRECHGESANG STEM
1D16D ; SpacingMark # Mc MUSICAL SYMBOL COMBINING AUGMENTATION DOT
-# Total code points: 348
+# Total code points: 362
# ================================================
@@ -1395,81 +1415,8 @@ D789..D7A3 ; LVT # Lo [27] HANGUL SYLLABLE HIG..HANGUL SYLLABLE HIH
# ================================================
-261D ; E_Base # So WHITE UP POINTING INDEX
-26F9 ; E_Base # So PERSON WITH BALL
-270A..270D ; E_Base # So [4] RAISED FIST..WRITING HAND
-1F385 ; E_Base # So FATHER CHRISTMAS
-1F3C2..1F3C4 ; E_Base # So [3] SNOWBOARDER..SURFER
-1F3C7 ; E_Base # So HORSE RACING
-1F3CA..1F3CC ; E_Base # So [3] SWIMMER..GOLFER
-1F442..1F443 ; E_Base # So [2] EAR..NOSE
-1F446..1F450 ; E_Base # So [11] WHITE UP POINTING BACKHAND INDEX..OPEN HANDS SIGN
-1F46E ; E_Base # So POLICE OFFICER
-1F470..1F478 ; E_Base # So [9] BRIDE WITH VEIL..PRINCESS
-1F47C ; E_Base # So BABY ANGEL
-1F481..1F483 ; E_Base # So [3] INFORMATION DESK PERSON..DANCER
-1F485..1F487 ; E_Base # So [3] NAIL POLISH..HAIRCUT
-1F4AA ; E_Base # So FLEXED BICEPS
-1F574..1F575 ; E_Base # So [2] MAN IN BUSINESS SUIT LEVITATING..SLEUTH OR SPY
-1F57A ; E_Base # So MAN DANCING
-1F590 ; E_Base # So RAISED HAND WITH FINGERS SPLAYED
-1F595..1F596 ; E_Base # So [2] REVERSED HAND WITH MIDDLE FINGER EXTENDED..RAISED HAND WITH PART BETWEEN MIDDLE AND RING FINGERS
-1F645..1F647 ; E_Base # So [3] FACE WITH NO GOOD GESTURE..PERSON BOWING DEEPLY
-1F64B..1F64F ; E_Base # So [5] HAPPY PERSON RAISING ONE HAND..PERSON WITH FOLDED HANDS
-1F6A3 ; E_Base # So ROWBOAT
-1F6B4..1F6B6 ; E_Base # So [3] BICYCLIST..PEDESTRIAN
-1F6C0 ; E_Base # So BATH
-1F6CC ; E_Base # So SLEEPING ACCOMMODATION
-1F918..1F91C ; E_Base # So [5] SIGN OF THE HORNS..RIGHT-FACING FIST
-1F91E..1F91F ; E_Base # So [2] HAND WITH INDEX AND MIDDLE FINGERS CROSSED..I LOVE YOU HAND SIGN
-1F926 ; E_Base # So FACE PALM
-1F930..1F939 ; E_Base # So [10] PREGNANT WOMAN..JUGGLING
-1F93D..1F93E ; E_Base # So [2] WATER POLO..HANDBALL
-1F9D1..1F9DD ; E_Base # So [13] ADULT..ELF
-
-# Total code points: 98
-
-# ================================================
-
-1F3FB..1F3FF ; E_Modifier # Sk [5] EMOJI MODIFIER FITZPATRICK TYPE-1-2..EMOJI MODIFIER FITZPATRICK TYPE-6
-
-# Total code points: 5
-
-# ================================================
-
200D ; ZWJ # Cf ZERO WIDTH JOINER
# Total code points: 1
-# ================================================
-
-2640 ; Glue_After_Zwj # So FEMALE SIGN
-2642 ; Glue_After_Zwj # So MALE SIGN
-2695..2696 ; Glue_After_Zwj # So [2] STAFF OF AESCULAPIUS..SCALES
-2708 ; Glue_After_Zwj # So AIRPLANE
-2764 ; Glue_After_Zwj # So HEAVY BLACK HEART
-1F308 ; Glue_After_Zwj # So RAINBOW
-1F33E ; Glue_After_Zwj # So EAR OF RICE
-1F373 ; Glue_After_Zwj # So COOKING
-1F393 ; Glue_After_Zwj # So GRADUATION CAP
-1F3A4 ; Glue_After_Zwj # So MICROPHONE
-1F3A8 ; Glue_After_Zwj # So ARTIST PALETTE
-1F3EB ; Glue_After_Zwj # So SCHOOL
-1F3ED ; Glue_After_Zwj # So FACTORY
-1F48B ; Glue_After_Zwj # So KISS MARK
-1F4BB..1F4BC ; Glue_After_Zwj # So [2] PERSONAL COMPUTER..BRIEFCASE
-1F527 ; Glue_After_Zwj # So WRENCH
-1F52C ; Glue_After_Zwj # So MICROSCOPE
-1F5E8 ; Glue_After_Zwj # So LEFT SPEECH BUBBLE
-1F680 ; Glue_After_Zwj # So ROCKET
-1F692 ; Glue_After_Zwj # So FIRE ENGINE
-
-# Total code points: 22
-
-# ================================================
-
-1F466..1F469 ; E_Base_GAZ # So [4] BOY..WOMAN
-
-# Total code points: 4
-
# EOF
diff --git a/lib/stdlib/uc_spec/PropList.txt b/lib/stdlib/uc_spec/PropList.txt
index 9a2d0e4b1c..ef86795abe 100644
--- a/lib/stdlib/uc_spec/PropList.txt
+++ b/lib/stdlib/uc_spec/PropList.txt
@@ -1,6 +1,6 @@
-# PropList-10.0.0.txt
-# Date: 2017-03-10, 08:25:30 GMT
-# © 2017 Unicode®, Inc.
+# PropList-11.0.0.txt
+# Date: 2018-03-15, 04:28:35 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -125,7 +125,7 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
05C3 ; Terminal_Punctuation # Po HEBREW PUNCTUATION SOF PASUQ
060C ; Terminal_Punctuation # Po ARABIC COMMA
061B ; Terminal_Punctuation # Po ARABIC SEMICOLON
-061F ; Terminal_Punctuation # Po ARABIC QUESTION MARK
+061E..061F ; Terminal_Punctuation # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
06D4 ; Terminal_Punctuation # Po ARABIC FULL STOP
0700..070A ; Terminal_Punctuation # Po [11] SYRIAC END OF PARAGRAPH..SYRIAC CONTRACTION
070C ; Terminal_Punctuation # Po SYRIAC HARKLEAN METOBELUS
@@ -156,6 +156,8 @@ FF63 ; Quotation_Mark # Pe HALFWIDTH RIGHT CORNER BRACKET
2E2E ; Terminal_Punctuation # Po REVERSED QUESTION MARK
2E3C ; Terminal_Punctuation # Po STENOGRAPHIC FULL STOP
2E41 ; Terminal_Punctuation # Po REVERSED COMMA
+2E4C ; Terminal_Punctuation # Po MEDIEVAL COMMA
+2E4E ; Terminal_Punctuation # Po PUNCTUS ELEVATUS MARK
3001..3002 ; Terminal_Punctuation # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP
A4FE..A4FF ; Terminal_Punctuation # Po [2] LISU PUNCTUATION COMMA..LISU PUNCTUATION FULL STOP
A60D..A60F ; Terminal_Punctuation # Po [3] VAI COMMA..VAI QUESTION MARK
@@ -185,6 +187,7 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
10AF0..10AF5 ; Terminal_Punctuation # Po [6] MANICHAEAN PUNCTUATION STAR..MANICHAEAN PUNCTUATION TWO DOTS
10B3A..10B3F ; Terminal_Punctuation # Po [6] TINY TWO DOTS OVER ONE DOT PUNCTUATION..LARGE ONE RING OVER TWO RINGS PUNCTUATION
10B99..10B9C ; Terminal_Punctuation # Po [4] PSALTER PAHLAVI SECTION MARK..PSALTER PAHLAVI FOUR DOTS WITH DOT
+10F55..10F59 ; Terminal_Punctuation # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
11047..1104D ; Terminal_Punctuation # Po [7] BRAHMI DANDA..BRAHMI PUNCTUATION LOTUS
110BE..110C1 ; Terminal_Punctuation # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; Terminal_Punctuation # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
@@ -204,15 +207,17 @@ FF64 ; Terminal_Punctuation # Po HALFWIDTH IDEOGRAPHIC COMMA
11AA1..11AA2 ; Terminal_Punctuation # Po [2] SOYOMBO TERMINAL MARK-1..SOYOMBO TERMINAL MARK-2
11C41..11C43 ; Terminal_Punctuation # Po [3] BHAIKSUKI DANDA..BHAIKSUKI WORD SEPARATOR
11C71 ; Terminal_Punctuation # Po MARCHEN MARK SHAD
+11EF7..11EF8 ; Terminal_Punctuation # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
12470..12474 ; Terminal_Punctuation # Po [5] CUNEIFORM PUNCTUATION SIGN OLD ASSYRIAN WORD DIVIDER..CUNEIFORM PUNCTUATION SIGN DIAGONAL QUADCOLON
16A6E..16A6F ; Terminal_Punctuation # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; Terminal_Punctuation # Po BASSA VAH FULL STOP
16B37..16B39 ; Terminal_Punctuation # Po [3] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN CIM CHEEM
16B44 ; Terminal_Punctuation # Po PAHAWH HMONG SIGN XAUS
+16E97..16E98 ; Terminal_Punctuation # Po [2] MEDEFAIDRIN COMMA..MEDEFAIDRIN FULL STOP
1BC9F ; Terminal_Punctuation # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
1DA87..1DA8A ; Terminal_Punctuation # Po [4] SIGNWRITING COMMA..SIGNWRITING COLON
-# Total code points: 252
+# Total code points: 264
# ================================================
@@ -661,6 +666,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
10A01..10A03 ; Other_Alphabetic # Mn [3] KHAROSHTHI VOWEL SIGN I..KHAROSHTHI VOWEL SIGN VOCALIC R
10A05..10A06 ; Other_Alphabetic # Mn [2] KHAROSHTHI VOWEL SIGN E..KHAROSHTHI VOWEL SIGN O
10A0C..10A0F ; Other_Alphabetic # Mn [4] KHAROSHTHI VOWEL LENGTH MARK..KHAROSHTHI SIGN VISARGA
+10D24..10D27 ; Other_Alphabetic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
11000 ; Other_Alphabetic # Mc BRAHMI SIGN CANDRABINDU
11001 ; Other_Alphabetic # Mn BRAHMI SIGN ANUSVARA
11002 ; Other_Alphabetic # Mc BRAHMI SIGN VISARGA
@@ -673,6 +679,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11127..1112B ; Other_Alphabetic # Mn [5] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN UU
1112C ; Other_Alphabetic # Mc CHAKMA VOWEL SIGN E
1112D..11132 ; Other_Alphabetic # Mn [6] CHAKMA VOWEL SIGN AI..CHAKMA AU MARK
+11145..11146 ; Other_Alphabetic # Mc [2] CHAKMA VOWEL SIGN AA..CHAKMA VOWEL SIGN EI
11180..11181 ; Other_Alphabetic # Mn [2] SHARADA SIGN CANDRABINDU..SHARADA SIGN ANUSVARA
11182 ; Other_Alphabetic # Mc SHARADA SIGN VISARGA
111B3..111B5 ; Other_Alphabetic # Mc [3] SHARADA VOWEL SIGN AA..SHARADA VOWEL SIGN II
@@ -730,9 +737,10 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11722..11725 ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN I..AHOM VOWEL SIGN UU
11726 ; Other_Alphabetic # Mc AHOM VOWEL SIGN E
11727..1172A ; Other_Alphabetic # Mn [4] AHOM VOWEL SIGN AW..AHOM VOWEL SIGN AM
-11A01..11A06 ; Other_Alphabetic # Mn [6] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL SIGN O
-11A07..11A08 ; Other_Alphabetic # Mc [2] ZANABAZAR SQUARE VOWEL SIGN AI..ZANABAZAR SQUARE VOWEL SIGN AU
-11A09..11A0A ; Other_Alphabetic # Mn [2] ZANABAZAR SQUARE VOWEL SIGN REVERSED I..ZANABAZAR SQUARE VOWEL LENGTH MARK
+1182C..1182E ; Other_Alphabetic # Mc [3] DOGRA VOWEL SIGN AA..DOGRA VOWEL SIGN II
+1182F..11837 ; Other_Alphabetic # Mn [9] DOGRA VOWEL SIGN U..DOGRA SIGN ANUSVARA
+11838 ; Other_Alphabetic # Mc DOGRA SIGN VISARGA
+11A01..11A0A ; Other_Alphabetic # Mn [10] ZANABAZAR SQUARE VOWEL SIGN I..ZANABAZAR SQUARE VOWEL LENGTH MARK
11A35..11A38 ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE SIGN CANDRABINDU..ZANABAZAR SQUARE SIGN ANUSVARA
11A39 ; Other_Alphabetic # Mc ZANABAZAR SQUARE SIGN VISARGA
11A3B..11A3E ; Other_Alphabetic # Mn [4] ZANABAZAR SQUARE CLUSTER-FINAL LETTER YA..ZANABAZAR SQUARE CLUSTER-FINAL LETTER VA
@@ -758,6 +766,13 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
11D3F..11D41 ; Other_Alphabetic # Mn [3] MASARAM GONDI VOWEL SIGN AU..MASARAM GONDI SIGN VISARGA
11D43 ; Other_Alphabetic # Mn MASARAM GONDI SIGN CANDRA
11D47 ; Other_Alphabetic # Mn MASARAM GONDI RA-KARA
+11D8A..11D8E ; Other_Alphabetic # Mc [5] GUNJALA GONDI VOWEL SIGN AA..GUNJALA GONDI VOWEL SIGN UU
+11D90..11D91 ; Other_Alphabetic # Mn [2] GUNJALA GONDI VOWEL SIGN EE..GUNJALA GONDI VOWEL SIGN AI
+11D93..11D94 ; Other_Alphabetic # Mc [2] GUNJALA GONDI VOWEL SIGN OO..GUNJALA GONDI VOWEL SIGN AU
+11D95 ; Other_Alphabetic # Mn GUNJALA GONDI SIGN ANUSVARA
+11D96 ; Other_Alphabetic # Mc GUNJALA GONDI SIGN VISARGA
+11EF3..11EF4 ; Other_Alphabetic # Mn [2] MAKASAR VOWEL SIGN I..MAKASAR VOWEL SIGN U
+11EF5..11EF6 ; Other_Alphabetic # Mc [2] MAKASAR VOWEL SIGN E..MAKASAR VOWEL SIGN O
16B30..16B36 ; Other_Alphabetic # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
16F51..16F7E ; Other_Alphabetic # Mc [46] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN NG
1BC9E ; Other_Alphabetic # Mn DUPLOYAN DOUBLE MARK
@@ -771,7 +786,7 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
1F150..1F169 ; Other_Alphabetic # So [26] NEGATIVE CIRCLED LATIN CAPITAL LETTER A..NEGATIVE CIRCLED LATIN CAPITAL LETTER Z
1F170..1F189 ; Other_Alphabetic # So [26] NEGATIVE SQUARED LATIN CAPITAL LETTER A..NEGATIVE SQUARED LATIN CAPITAL LETTER Z
-# Total code points: 1300
+# Total code points: 1334
# ================================================
@@ -780,10 +795,10 @@ FB1E ; Other_Alphabetic # Mn HEBREW POINT JUDEO-SPANISH VARIKA
3021..3029 ; Ideographic # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE
3038..303A ; Ideographic # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY
3400..4DB5 ; Ideographic # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
-4E00..9FEA ; Ideographic # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA
+4E00..9FEF ; Ideographic # Lo [20976] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEF
F900..FA6D ; Ideographic # Lo [366] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA6D
FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COMPATIBILITY IDEOGRAPH-FAD9
-17000..187EC ; Ideographic # Lo [6125] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187EC
+17000..187F1 ; Ideographic # Lo [6130] TANGUT IDEOGRAPH-17000..TANGUT IDEOGRAPH-187F1
18800..18AF2 ; Ideographic # Lo [755] TANGUT COMPONENT-001..TANGUT COMPONENT-755
1B170..1B2FB ; Ideographic # Lo [396] NUSHU CHARACTER-1B170..NUSHU CHARACTER-1B2FB
20000..2A6D6 ; Ideographic # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6
@@ -793,7 +808,7 @@ FA70..FAD9 ; Ideographic # Lo [106] CJK COMPATIBILITY IDEOGRAPH-FA70..CJK COM
2CEB0..2EBE0 ; Ideographic # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
2F800..2FA1D ; Ideographic # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D
-# Total code points: 96174
+# Total code points: 96184
# ================================================
@@ -953,6 +968,9 @@ FF9E..FF9F ; Diacritic # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFW
FFE3 ; Diacritic # Sk FULLWIDTH MACRON
102E0 ; Diacritic # Mn COPTIC EPACT THOUSANDS MARK
10AE5..10AE6 ; Diacritic # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
+10D22..10D23 ; Diacritic # Lo [2] HANIFI ROHINGYA MARK SAKIN..HANIFI ROHINGYA MARK NA KHONNA
+10D24..10D27 ; Diacritic # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
+10F46..10F50 ; Diacritic # Mn [11] SOGDIAN COMBINING DOT BELOW..SOGDIAN COMBINING STROKE BELOW
110B9..110BA ; Diacritic # Mn [2] KAITHI SIGN VIRAMA..KAITHI SIGN NUKTA
11133..11134 ; Diacritic # Mn [2] CHAKMA VIRAMA..CHAKMA MAAYYAA
11173 ; Diacritic # Mn MAHAJANI SIGN NUKTA
@@ -973,12 +991,14 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
116B6 ; Diacritic # Mc TAKRI SIGN VIRAMA
116B7 ; Diacritic # Mn TAKRI SIGN NUKTA
1172B ; Diacritic # Mn AHOM SIGN KILLER
+11839..1183A ; Diacritic # Mn [2] DOGRA SIGN VIRAMA..DOGRA SIGN NUKTA
11A34 ; Diacritic # Mn ZANABAZAR SQUARE SIGN VIRAMA
11A47 ; Diacritic # Mn ZANABAZAR SQUARE SUBJOINER
11A99 ; Diacritic # Mn SOYOMBO SUBJOINER
11C3F ; Diacritic # Mn BHAIKSUKI SIGN VIRAMA
11D42 ; Diacritic # Mn MASARAM GONDI SIGN NUKTA
11D44..11D45 ; Diacritic # Mn [2] MASARAM GONDI SIGN HALANTA..MASARAM GONDI VIRAMA
+11D97 ; Diacritic # Mn GUNJALA GONDI VIRAMA
16AF0..16AF4 ; Diacritic # Mn [5] BASSA VAH COMBINING HIGH TONE..BASSA VAH COMBINING HIGH-LOW TONE
16F8F..16F92 ; Diacritic # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
16F93..16F9F ; Diacritic # Lm [13] MIAO LETTER TONE-2..MIAO LETTER REFORMED TONE-8
@@ -991,7 +1011,7 @@ FFE3 ; Diacritic # Sk FULLWIDTH MACRON
1E944..1E946 ; Diacritic # Mn [3] ADLAM ALIF LENGTHENER..ADLAM GEMINATION MARK
1E948..1E94A ; Diacritic # Mn [3] ADLAM CONSONANT MODIFIER..ADLAM NUKTA
-# Total code points: 798
+# Total code points: 818
# ================================================
@@ -1137,7 +1157,7 @@ E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
# ================================================
3400..4DB5 ; Unified_Ideograph # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5
-4E00..9FEA ; Unified_Ideograph # Lo [20971] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEA
+4E00..9FEF ; Unified_Ideograph # Lo [20976] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FEF
FA0E..FA0F ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA0E..CJK COMPATIBILITY IDEOGRAPH-FA0F
FA11 ; Unified_Ideograph # Lo CJK COMPATIBILITY IDEOGRAPH-FA11
FA13..FA14 ; Unified_Ideograph # Lo [2] CJK COMPATIBILITY IDEOGRAPH-FA13..CJK COMPATIBILITY IDEOGRAPH-FA14
@@ -1151,7 +1171,7 @@ FA27..FA29 ; Unified_Ideograph # Lo [3] CJK COMPATIBILITY IDEOGRAPH-FA27..C
2B820..2CEA1 ; Unified_Ideograph # Lo [5762] CJK UNIFIED IDEOGRAPH-2B820..CJK UNIFIED IDEOGRAPH-2CEA1
2CEB0..2EBE0 ; Unified_Ideograph # Lo [7473] CJK UNIFIED IDEOGRAPH-2CEB0..CJK UNIFIED IDEOGRAPH-2EBE0
-# Total code points: 87882
+# Total code points: 87887
# ================================================
@@ -1255,10 +1275,13 @@ AABB..AABC ; Logical_Order_Exception # Lo [2] TAI VIET VOWEL AUE..TAI VIET
002E ; Sentence_Terminal # Po FULL STOP
003F ; Sentence_Terminal # Po QUESTION MARK
0589 ; Sentence_Terminal # Po ARMENIAN FULL STOP
-061F ; Sentence_Terminal # Po ARABIC QUESTION MARK
+061E..061F ; Sentence_Terminal # Po [2] ARABIC TRIPLE DOT PUNCTUATION MARK..ARABIC QUESTION MARK
06D4 ; Sentence_Terminal # Po ARABIC FULL STOP
0700..0702 ; Sentence_Terminal # Po [3] SYRIAC END OF PARAGRAPH..SYRIAC SUBLINEAR FULL STOP
07F9 ; Sentence_Terminal # Po NKO EXCLAMATION MARK
+0837 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION MELODIC QITSA
+0839 ; Sentence_Terminal # Po SAMARITAN PUNCTUATION QITSA
+083D..083E ; Sentence_Terminal # Po [2] SAMARITAN PUNCTUATION SOF MASHFAAT..SAMARITAN PUNCTUATION ANNAAU
0964..0965 ; Sentence_Terminal # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA
104A..104B ; Sentence_Terminal # Po [2] MYANMAR SIGN LITTLE SECTION..MYANMAR SIGN SECTION
1362 ; Sentence_Terminal # Po ETHIOPIC FULL STOP
@@ -1296,6 +1319,7 @@ FF0E ; Sentence_Terminal # Po FULLWIDTH FULL STOP
FF1F ; Sentence_Terminal # Po FULLWIDTH QUESTION MARK
FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP
10A56..10A57 ; Sentence_Terminal # Po [2] KHAROSHTHI PUNCTUATION DANDA..KHAROSHTHI PUNCTUATION DOUBLE DANDA
+10F55..10F59 ; Sentence_Terminal # Po [5] SOGDIAN PUNCTUATION TWO VERTICAL BARS..SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT
11047..11048 ; Sentence_Terminal # Po [2] BRAHMI DANDA..BRAHMI DOUBLE DANDA
110BE..110C1 ; Sentence_Terminal # Po [4] KAITHI SECTION MARK..KAITHI DOUBLE DANDA
11141..11143 ; Sentence_Terminal # Po [3] CHAKMA DANDA..CHAKMA QUESTION MARK
@@ -1313,14 +1337,16 @@ FF61 ; Sentence_Terminal # Po HALFWIDTH IDEOGRAPHIC FULL STOP
11A42..11A43 ; Sentence_Terminal # Po [2] ZANABAZAR SQUARE MARK SHAD..ZANABAZAR SQUARE MARK DOUBLE SHAD
11A9B..11A9C ; Sentence_Terminal # Po [2] SOYOMBO MARK SHAD..SOYOMBO MARK DOUBLE SHAD
11C41..11C42 ; Sentence_Terminal # Po [2] BHAIKSUKI DANDA..BHAIKSUKI DOUBLE DANDA
+11EF7..11EF8 ; Sentence_Terminal # Po [2] MAKASAR PASSIMBANG..MAKASAR END OF SECTION
16A6E..16A6F ; Sentence_Terminal # Po [2] MRO DANDA..MRO DOUBLE DANDA
16AF5 ; Sentence_Terminal # Po BASSA VAH FULL STOP
16B37..16B38 ; Sentence_Terminal # Po [2] PAHAWH HMONG SIGN VOS THOM..PAHAWH HMONG SIGN VOS TSHAB CEEB
16B44 ; Sentence_Terminal # Po PAHAWH HMONG SIGN XAUS
+16E98 ; Sentence_Terminal # Po MEDEFAIDRIN FULL STOP
1BC9F ; Sentence_Terminal # Po DUPLOYAN PUNCTUATION CHINOOK FULL STOP
1DA88 ; Sentence_Terminal # Po SIGNWRITING FULL STOP
-# Total code points: 128
+# Total code points: 141
# ================================================
@@ -1521,14 +1547,10 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2B74..2B75 ; Pattern_Syntax # Cn [2] <reserved-2B74>..<reserved-2B75>
2B76..2B95 ; Pattern_Syntax # So [32] NORTH WEST TRIANGLE-HEADED ARROW TO BAR..RIGHTWARDS BLACK ARROW
2B96..2B97 ; Pattern_Syntax # Cn [2] <reserved-2B96>..<reserved-2B97>
-2B98..2BB9 ; Pattern_Syntax # So [34] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..UP ARROWHEAD IN A RECTANGLE BOX
-2BBA..2BBC ; Pattern_Syntax # Cn [3] <reserved-2BBA>..<reserved-2BBC>
-2BBD..2BC8 ; Pattern_Syntax # So [12] BALLOT BOX WITH LIGHT X..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
+2B98..2BC8 ; Pattern_Syntax # So [49] THREE-D TOP-LIGHTED LEFTWARDS EQUILATERAL ARROWHEAD..BLACK MEDIUM RIGHT-POINTING TRIANGLE CENTRED
2BC9 ; Pattern_Syntax # Cn <reserved-2BC9>
-2BCA..2BD2 ; Pattern_Syntax # So [9] TOP HALF BLACK CIRCLE..GROUP MARK
-2BD3..2BEB ; Pattern_Syntax # Cn [25] <reserved-2BD3>..<reserved-2BEB>
-2BEC..2BEF ; Pattern_Syntax # So [4] LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS..DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS
-2BF0..2BFF ; Pattern_Syntax # Cn [16] <reserved-2BF0>..<reserved-2BFF>
+2BCA..2BFE ; Pattern_Syntax # So [53] TOP HALF BLACK CIRCLE..REVERSED RIGHT ANGLE
+2BFF ; Pattern_Syntax # Cn <reserved-2BFF>
2E00..2E01 ; Pattern_Syntax # Po [2] RIGHT ANGLE SUBSTITUTION MARKER..RIGHT ANGLE DOTTED SUBSTITUTION MARKER
2E02 ; Pattern_Syntax # Pi LEFT SUBSTITUTION BRACKET
2E03 ; Pattern_Syntax # Pf RIGHT SUBSTITUTION BRACKET
@@ -1566,8 +1588,8 @@ E0100..E01EF ; Variation_Selector # Mn [240] VARIATION SELECTOR-17..VARIATION S
2E40 ; Pattern_Syntax # Pd DOUBLE HYPHEN
2E41 ; Pattern_Syntax # Po REVERSED COMMA
2E42 ; Pattern_Syntax # Ps DOUBLE LOW-REVERSED-9 QUOTATION MARK
-2E43..2E49 ; Pattern_Syntax # Po [7] DASH WITH LEFT UPTURN..DOUBLE STACKED COMMA
-2E4A..2E7F ; Pattern_Syntax # Cn [54] <reserved-2E4A>..<reserved-2E7F>
+2E43..2E4E ; Pattern_Syntax # Po [12] DASH WITH LEFT UPTURN..PUNCTUS ELEVATUS MARK
+2E4F..2E7F ; Pattern_Syntax # Cn [49] <reserved-2E4F>..<reserved-2E7F>
3001..3003 ; Pattern_Syntax # Po [3] IDEOGRAPHIC COMMA..DITTO MARK
3008 ; Pattern_Syntax # Ps LEFT ANGLE BRACKET
3009 ; Pattern_Syntax # Pe RIGHT ANGLE BRACKET
@@ -1606,8 +1628,9 @@ FE45..FE46 ; Pattern_Syntax # Po [2] SESAME DOT..WHITE SESAME DOT
070F ; Prepended_Concatenation_Mark # Cf SYRIAC ABBREVIATION MARK
08E2 ; Prepended_Concatenation_Mark # Cf ARABIC DISPUTED END OF AYAH
110BD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN
+110CD ; Prepended_Concatenation_Mark # Cf KAITHI NUMBER SIGN ABOVE
-# Total code points: 10
+# Total code points: 11
# ================================================
diff --git a/lib/stdlib/uc_spec/README-UPDATE.txt b/lib/stdlib/uc_spec/README-UPDATE.txt
index d59337e1a5..e1f5c8fcd0 100644
--- a/lib/stdlib/uc_spec/README-UPDATE.txt
+++ b/lib/stdlib/uc_spec/README-UPDATE.txt
@@ -1,7 +1,13 @@
When updating the unicode version copy the necessary files to this
directory.
-
And update the test files in stdlib/test/unicode_util_SUITE_data/*
+Unicode 11 was updated from:
+https://www.unicode.org/Public/11.0.0/ucd/
+https://www.unicode.org/Public/11.0.0/ucd/auxiliary/
+https://www.unicode.org/Public/emoji/11.0/
+
Update the spec_version(..) function in the generator,
gen_unicode_mod.escript
+
+
diff --git a/lib/stdlib/uc_spec/SpecialCasing.txt b/lib/stdlib/uc_spec/SpecialCasing.txt
index b9ba0d81c1..c90d09acb3 100644
--- a/lib/stdlib/uc_spec/SpecialCasing.txt
+++ b/lib/stdlib/uc_spec/SpecialCasing.txt
@@ -1,6 +1,6 @@
-# SpecialCasing-10.0.0.txt
-# Date: 2017-04-14, 05:40:43 GMT
-# © 2017 Unicode®, Inc.
+# SpecialCasing-11.0.0.txt
+# Date: 2018-02-22, 06:16:47 GMT
+# © 2018 Unicode®, Inc.
# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
# For terms of use, see http://www.unicode.org/terms_of_use.html
#
@@ -121,7 +121,7 @@ FB17; FB17; 0544 056D; 0544 053D; # ARMENIAN SMALL LIGATURE MEN XEH
# The following cases are already in the UnicodeData.txt file, so are only commented here.
-# 0345; 0345; 0345; 0399; # COMBINING GREEK YPOGEGRAMMENI
+# 0345; 0345; 0399; 0399; # COMBINING GREEK YPOGEGRAMMENI
# All letters with YPOGEGRAMMENI (iota-subscript) or PROSGEGRAMMENI (iota adscript)
# have special uppercases.
diff --git a/lib/stdlib/uc_spec/UnicodeData.txt b/lib/stdlib/uc_spec/UnicodeData.txt
index d89c64f526..ec32fafbce 100644
--- a/lib/stdlib/uc_spec/UnicodeData.txt
+++ b/lib/stdlib/uc_spec/UnicodeData.txt
@@ -1362,6 +1362,7 @@
055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0560;ARMENIAN SMALL LETTER TURNED AYB;Ll;0;L;;;;;N;;;;;
0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
@@ -1401,6 +1402,7 @@
0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0588;ARMENIAN SMALL LETTER YI WITH STROKE;Ll;0;L;;;;;N;;;;;
0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
058D;RIGHT-FACING ARMENIAN ETERNITY SIGN;So;0;ON;;;;;N;;;;;
@@ -1488,6 +1490,7 @@
05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05EF;HEBREW YOD TRIANGLE;Lo;0;R;;;;;N;;;;;
05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
@@ -1982,6 +1985,9 @@
07F8;NKO COMMA;Po;0;ON;;;;;N;;;;;
07F9;NKO EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
07FA;NKO LAJANYALAN;Lm;0;R;;;;;N;;;;;
+07FD;NKO DANTAYALAN;Mn;220;NSM;;;;;N;;;;;
+07FE;NKO DOROME SIGN;Sc;0;R;;;;;N;;;;;
+07FF;NKO TAMAN SIGN;Sc;0;R;;;;;N;;;;;
0800;SAMARITAN LETTER ALAF;Lo;0;R;;;;;N;;;;;
0801;SAMARITAN LETTER BIT;Lo;0;R;;;;;N;;;;;
0802;SAMARITAN LETTER GAMAN;Lo;0;R;;;;;N;;;;;
@@ -2112,6 +2118,7 @@
08BB;ARABIC LETTER AFRICAN FEH;Lo;0;AL;;;;;N;;;;;
08BC;ARABIC LETTER AFRICAN QAF;Lo;0;AL;;;;;N;;;;;
08BD;ARABIC LETTER AFRICAN NOON;Lo;0;AL;;;;;N;;;;;
+08D3;ARABIC SMALL LOW WAW;Mn;220;NSM;;;;;N;;;;;
08D4;ARABIC SMALL HIGH WORD AR-RUB;Mn;230;NSM;;;;;N;;;;;
08D5;ARABIC SMALL HIGH SAD;Mn;230;NSM;;;;;N;;;;;
08D6;ARABIC SMALL HIGH AIN;Mn;230;NSM;;;;;N;;;;;
@@ -2379,6 +2386,7 @@
09FB;BENGALI GANDA MARK;Sc;0;ET;;;;;N;;;;;
09FC;BENGALI LETTER VEDIC ANUSVARA;Lo;0;L;;;;;N;;;;;
09FD;BENGALI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+09FE;BENGALI SANDHI MARK;Mn;230;NSM;;;;;N;;;;;
0A01;GURMUKHI SIGN ADAK BINDI;Mn;0;NSM;;;;;N;;;;;
0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
0A03;GURMUKHI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2458,6 +2466,7 @@
0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
0A75;GURMUKHI SIGN YAKASH;Mn;0;NSM;;;;;N;;;;;
+0A76;GURMUKHI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -2715,6 +2724,7 @@
0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C04;TELUGU SIGN COMBINING ANUSVARA ABOVE;Mn;0;NSM;;;;;N;;;;;
0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
@@ -2811,6 +2821,7 @@
0C81;KANNADA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C84;KANNADA SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
@@ -3667,54 +3678,54 @@
10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;2D25;
10C7;GEORGIAN CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;2D27;
10CD;GEORGIAN CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;2D2D;
-10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
-10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
-10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
-10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
-10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
-10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
-10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
-10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
-10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
-10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
-10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
-10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
-10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
-10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
-10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
-10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
-10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
-10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
-10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
-10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
-10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
-10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
-10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
-10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
-10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
-10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
-10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
-10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
-10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
-10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
-10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
-10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
-10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
-10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
-10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
-10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
-10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
-10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
-10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
-10F7;GEORGIAN LETTER YN;Lo;0;L;;;;;N;;;;;
-10F8;GEORGIAN LETTER ELIFI;Lo;0;L;;;;;N;;;;;
-10F9;GEORGIAN LETTER TURNED GAN;Lo;0;L;;;;;N;;;;;
-10FA;GEORGIAN LETTER AIN;Lo;0;L;;;;;N;;;;;
+10D0;GEORGIAN LETTER AN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;1C90;;10D0
+10D1;GEORGIAN LETTER BAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;1C91;;10D1
+10D2;GEORGIAN LETTER GAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;1C92;;10D2
+10D3;GEORGIAN LETTER DON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;1C93;;10D3
+10D4;GEORGIAN LETTER EN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;1C94;;10D4
+10D5;GEORGIAN LETTER VIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;1C95;;10D5
+10D6;GEORGIAN LETTER ZEN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;1C96;;10D6
+10D7;GEORGIAN LETTER TAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;1C97;;10D7
+10D8;GEORGIAN LETTER IN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;1C98;;10D8
+10D9;GEORGIAN LETTER KAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;1C99;;10D9
+10DA;GEORGIAN LETTER LAS;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;1C9A;;10DA
+10DB;GEORGIAN LETTER MAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;1C9B;;10DB
+10DC;GEORGIAN LETTER NAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;1C9C;;10DC
+10DD;GEORGIAN LETTER ON;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;1C9D;;10DD
+10DE;GEORGIAN LETTER PAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;1C9E;;10DE
+10DF;GEORGIAN LETTER ZHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;1C9F;;10DF
+10E0;GEORGIAN LETTER RAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;1CA0;;10E0
+10E1;GEORGIAN LETTER SAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;1CA1;;10E1
+10E2;GEORGIAN LETTER TAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;1CA2;;10E2
+10E3;GEORGIAN LETTER UN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;1CA3;;10E3
+10E4;GEORGIAN LETTER PHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;1CA4;;10E4
+10E5;GEORGIAN LETTER KHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;1CA5;;10E5
+10E6;GEORGIAN LETTER GHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;1CA6;;10E6
+10E7;GEORGIAN LETTER QAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;1CA7;;10E7
+10E8;GEORGIAN LETTER SHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;1CA8;;10E8
+10E9;GEORGIAN LETTER CHIN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;1CA9;;10E9
+10EA;GEORGIAN LETTER CAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;1CAA;;10EA
+10EB;GEORGIAN LETTER JIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;1CAB;;10EB
+10EC;GEORGIAN LETTER CIL;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;1CAC;;10EC
+10ED;GEORGIAN LETTER CHAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;1CAD;;10ED
+10EE;GEORGIAN LETTER XAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;1CAE;;10EE
+10EF;GEORGIAN LETTER JHAN;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;1CAF;;10EF
+10F0;GEORGIAN LETTER HAE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;1CB0;;10F0
+10F1;GEORGIAN LETTER HE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;1CB1;;10F1
+10F2;GEORGIAN LETTER HIE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;1CB2;;10F2
+10F3;GEORGIAN LETTER WE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;1CB3;;10F3
+10F4;GEORGIAN LETTER HAR;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;1CB4;;10F4
+10F5;GEORGIAN LETTER HOE;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;1CB5;;10F5
+10F6;GEORGIAN LETTER FI;Ll;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;1CB6;;10F6
+10F7;GEORGIAN LETTER YN;Ll;0;L;;;;;N;;;1CB7;;10F7
+10F8;GEORGIAN LETTER ELIFI;Ll;0;L;;;;;N;;;1CB8;;10F8
+10F9;GEORGIAN LETTER TURNED GAN;Ll;0;L;;;;;N;;;1CB9;;10F9
+10FA;GEORGIAN LETTER AIN;Ll;0;L;;;;;N;;;1CBA;;10FA
10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
10FC;MODIFIER LETTER GEORGIAN NAR;Lm;0;L;<super> 10DC;;;;N;;;;;
-10FD;GEORGIAN LETTER AEN;Lo;0;L;;;;;N;;;;;
-10FE;GEORGIAN LETTER HARD SIGN;Lo;0;L;;;;;N;;;;;
-10FF;GEORGIAN LETTER LABIAL SIGN;Lo;0;L;;;;;N;;;;;
+10FD;GEORGIAN LETTER AEN;Ll;0;L;;;;;N;;;1CBD;;10FD
+10FE;GEORGIAN LETTER HARD SIGN;Ll;0;L;;;;;N;;;1CBE;;10FE
+10FF;GEORGIAN LETTER LABIAL SIGN;Ll;0;L;;;;;N;;;1CBF;;10FF
1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;;;;
1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;;;;
@@ -5513,6 +5524,7 @@
1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1878;MONGOLIAN LETTER CHA WITH TWO DOTS;Lo;0;L;;;;;N;;;;;
1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
@@ -6388,6 +6400,52 @@
1C86;CYRILLIC SMALL LETTER TALL HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
1C87;CYRILLIC SMALL LETTER TALL YAT;Ll;0;L;;;;;N;;;0462;;0462
1C88;CYRILLIC SMALL LETTER UNBLENDED UK;Ll;0;L;;;;;N;;;A64A;;A64A
+1C90;GEORGIAN MTAVRULI CAPITAL LETTER AN;Lu;0;L;;;;;N;;;;10D0;
+1C91;GEORGIAN MTAVRULI CAPITAL LETTER BAN;Lu;0;L;;;;;N;;;;10D1;
+1C92;GEORGIAN MTAVRULI CAPITAL LETTER GAN;Lu;0;L;;;;;N;;;;10D2;
+1C93;GEORGIAN MTAVRULI CAPITAL LETTER DON;Lu;0;L;;;;;N;;;;10D3;
+1C94;GEORGIAN MTAVRULI CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;10D4;
+1C95;GEORGIAN MTAVRULI CAPITAL LETTER VIN;Lu;0;L;;;;;N;;;;10D5;
+1C96;GEORGIAN MTAVRULI CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;;;10D6;
+1C97;GEORGIAN MTAVRULI CAPITAL LETTER TAN;Lu;0;L;;;;;N;;;;10D7;
+1C98;GEORGIAN MTAVRULI CAPITAL LETTER IN;Lu;0;L;;;;;N;;;;10D8;
+1C99;GEORGIAN MTAVRULI CAPITAL LETTER KAN;Lu;0;L;;;;;N;;;;10D9;
+1C9A;GEORGIAN MTAVRULI CAPITAL LETTER LAS;Lu;0;L;;;;;N;;;;10DA;
+1C9B;GEORGIAN MTAVRULI CAPITAL LETTER MAN;Lu;0;L;;;;;N;;;;10DB;
+1C9C;GEORGIAN MTAVRULI CAPITAL LETTER NAR;Lu;0;L;;;;;N;;;;10DC;
+1C9D;GEORGIAN MTAVRULI CAPITAL LETTER ON;Lu;0;L;;;;;N;;;;10DD;
+1C9E;GEORGIAN MTAVRULI CAPITAL LETTER PAR;Lu;0;L;;;;;N;;;;10DE;
+1C9F;GEORGIAN MTAVRULI CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;;;10DF;
+1CA0;GEORGIAN MTAVRULI CAPITAL LETTER RAE;Lu;0;L;;;;;N;;;;10E0;
+1CA1;GEORGIAN MTAVRULI CAPITAL LETTER SAN;Lu;0;L;;;;;N;;;;10E1;
+1CA2;GEORGIAN MTAVRULI CAPITAL LETTER TAR;Lu;0;L;;;;;N;;;;10E2;
+1CA3;GEORGIAN MTAVRULI CAPITAL LETTER UN;Lu;0;L;;;;;N;;;;10E3;
+1CA4;GEORGIAN MTAVRULI CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;;;10E4;
+1CA5;GEORGIAN MTAVRULI CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;;;10E5;
+1CA6;GEORGIAN MTAVRULI CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;;;10E6;
+1CA7;GEORGIAN MTAVRULI CAPITAL LETTER QAR;Lu;0;L;;;;;N;;;;10E7;
+1CA8;GEORGIAN MTAVRULI CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;;;10E8;
+1CA9;GEORGIAN MTAVRULI CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;;;10E9;
+1CAA;GEORGIAN MTAVRULI CAPITAL LETTER CAN;Lu;0;L;;;;;N;;;;10EA;
+1CAB;GEORGIAN MTAVRULI CAPITAL LETTER JIL;Lu;0;L;;;;;N;;;;10EB;
+1CAC;GEORGIAN MTAVRULI CAPITAL LETTER CIL;Lu;0;L;;;;;N;;;;10EC;
+1CAD;GEORGIAN MTAVRULI CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;;;10ED;
+1CAE;GEORGIAN MTAVRULI CAPITAL LETTER XAN;Lu;0;L;;;;;N;;;;10EE;
+1CAF;GEORGIAN MTAVRULI CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;;;10EF;
+1CB0;GEORGIAN MTAVRULI CAPITAL LETTER HAE;Lu;0;L;;;;;N;;;;10F0;
+1CB1;GEORGIAN MTAVRULI CAPITAL LETTER HE;Lu;0;L;;;;;N;;;;10F1;
+1CB2;GEORGIAN MTAVRULI CAPITAL LETTER HIE;Lu;0;L;;;;;N;;;;10F2;
+1CB3;GEORGIAN MTAVRULI CAPITAL LETTER WE;Lu;0;L;;;;;N;;;;10F3;
+1CB4;GEORGIAN MTAVRULI CAPITAL LETTER HAR;Lu;0;L;;;;;N;;;;10F4;
+1CB5;GEORGIAN MTAVRULI CAPITAL LETTER HOE;Lu;0;L;;;;;N;;;;10F5;
+1CB6;GEORGIAN MTAVRULI CAPITAL LETTER FI;Lu;0;L;;;;;N;;;;10F6;
+1CB7;GEORGIAN MTAVRULI CAPITAL LETTER YN;Lu;0;L;;;;;N;;;;10F7;
+1CB8;GEORGIAN MTAVRULI CAPITAL LETTER ELIFI;Lu;0;L;;;;;N;;;;10F8;
+1CB9;GEORGIAN MTAVRULI CAPITAL LETTER TURNED GAN;Lu;0;L;;;;;N;;;;10F9;
+1CBA;GEORGIAN MTAVRULI CAPITAL LETTER AIN;Lu;0;L;;;;;N;;;;10FA;
+1CBD;GEORGIAN MTAVRULI CAPITAL LETTER AEN;Lu;0;L;;;;;N;;;;10FD;
+1CBE;GEORGIAN MTAVRULI CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;10FE;
+1CBF;GEORGIAN MTAVRULI CAPITAL LETTER LABIAL SIGN;Lu;0;L;;;;;N;;;;10FF;
1CC0;SUNDANESE PUNCTUATION BINDU SURYA;Po;0;L;;;;;N;;;;;
1CC1;SUNDANESE PUNCTUATION BINDU PANGLONG;Po;0;L;;;;;N;;;;;
1CC2;SUNDANESE PUNCTUATION BINDU PURNAMA;Po;0;L;;;;;N;;;;;
@@ -9559,7 +9617,7 @@
299E;ANGLE WITH S INSIDE;Sm;0;ON;;;;;Y;;;;;
299F;ACUTE ANGLE;Sm;0;ON;;;;;Y;;;;;
29A0;SPHERICAL ANGLE OPENING LEFT;Sm;0;ON;;;;;Y;;;;;
-29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;Y;;;;;
+29A1;SPHERICAL ANGLE OPENING UP;Sm;0;ON;;;;;N;;;;;
29A2;TURNED ANGLE;Sm;0;ON;;;;;Y;;;;;
29A3;REVERSED ANGLE;Sm;0;ON;;;;;Y;;;;;
29A4;ANGLE WITH UNDERBAR;Sm;0;ON;;;;;Y;;;;;
@@ -10092,6 +10150,9 @@
2BB7;RIBBON ARROW RIGHT DOWN;So;0;ON;;;;;N;;;;;
2BB8;UPWARDS WHITE ARROW FROM BAR WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
2BB9;UP ARROWHEAD IN A RECTANGLE BOX;So;0;ON;;;;;N;;;;;
+2BBA;OVERLAPPING WHITE SQUARES;So;0;ON;;;;;N;;;;;
+2BBB;OVERLAPPING WHITE AND BLACK SQUARES;So;0;ON;;;;;N;;;;;
+2BBC;OVERLAPPING BLACK SQUARES;So;0;ON;;;;;N;;;;;
2BBD;BALLOT BOX WITH LIGHT X;So;0;ON;;;;;N;;;;;
2BBE;CIRCLED X;So;0;ON;;;;;N;;;;;
2BBF;CIRCLED BOLD X;So;0;ON;;;;;N;;;;;
@@ -10113,10 +10174,50 @@
2BD0;SQUARE POSITION INDICATOR;So;0;ON;;;;;N;;;;;
2BD1;UNCERTAINTY SIGN;So;0;ON;;;;;N;;;;;
2BD2;GROUP MARK;So;0;ON;;;;;N;;;;;
+2BD3;PLUTO FORM TWO;So;0;ON;;;;;N;;;;;
+2BD4;PLUTO FORM THREE;So;0;ON;;;;;N;;;;;
+2BD5;PLUTO FORM FOUR;So;0;ON;;;;;N;;;;;
+2BD6;PLUTO FORM FIVE;So;0;ON;;;;;N;;;;;
+2BD7;TRANSPLUTO;So;0;ON;;;;;N;;;;;
+2BD8;PROSERPINA;So;0;ON;;;;;N;;;;;
+2BD9;ASTRAEA;So;0;ON;;;;;N;;;;;
+2BDA;HYGIEA;So;0;ON;;;;;N;;;;;
+2BDB;PHOLUS;So;0;ON;;;;;N;;;;;
+2BDC;NESSUS;So;0;ON;;;;;N;;;;;
+2BDD;WHITE MOON SELENA;So;0;ON;;;;;N;;;;;
+2BDE;BLACK DIAMOND ON CROSS;So;0;ON;;;;;N;;;;;
+2BDF;TRUE LIGHT MOON ARTA;So;0;ON;;;;;N;;;;;
+2BE0;CUPIDO;So;0;ON;;;;;N;;;;;
+2BE1;HADES;So;0;ON;;;;;N;;;;;
+2BE2;ZEUS;So;0;ON;;;;;N;;;;;
+2BE3;KRONOS;So;0;ON;;;;;N;;;;;
+2BE4;APOLLON;So;0;ON;;;;;N;;;;;
+2BE5;ADMETOS;So;0;ON;;;;;N;;;;;
+2BE6;VULCANUS;So;0;ON;;;;;N;;;;;
+2BE7;POSEIDON;So;0;ON;;;;;N;;;;;
+2BE8;LEFT HALF BLACK STAR;So;0;ON;;;;;N;;;;;
+2BE9;RIGHT HALF BLACK STAR;So;0;ON;;;;;N;;;;;
+2BEA;STAR WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+2BEB;STAR WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
2BEC;LEFTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BED;UPWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BEE;RIGHTWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
2BEF;DOWNWARDS TWO-HEADED ARROW WITH TRIANGLE ARROWHEADS;So;0;ON;;;;;N;;;;;
+2BF0;ERIS FORM ONE;So;0;ON;;;;;N;;;;;
+2BF1;ERIS FORM TWO;So;0;ON;;;;;N;;;;;
+2BF2;SEDNA;So;0;ON;;;;;N;;;;;
+2BF3;RUSSIAN ASTROLOGICAL SYMBOL VIGINTILE;So;0;ON;;;;;N;;;;;
+2BF4;RUSSIAN ASTROLOGICAL SYMBOL NOVILE;So;0;ON;;;;;N;;;;;
+2BF5;RUSSIAN ASTROLOGICAL SYMBOL QUINTILE;So;0;ON;;;;;N;;;;;
+2BF6;RUSSIAN ASTROLOGICAL SYMBOL BINOVILE;So;0;ON;;;;;N;;;;;
+2BF7;RUSSIAN ASTROLOGICAL SYMBOL SENTAGON;So;0;ON;;;;;N;;;;;
+2BF8;RUSSIAN ASTROLOGICAL SYMBOL TREDECILE;So;0;ON;;;;;N;;;;;
+2BF9;EQUALS SIGN WITH INFINITY BELOW;So;0;ON;;;;;N;;;;;
+2BFA;UNITED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFB;SEPARATED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFC;DOUBLED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFD;PASSED SYMBOL;So;0;ON;;;;;N;;;;;
+2BFE;REVERSED RIGHT ANGLE;So;0;ON;;;;;Y;;;;;
2C00;GLAGOLITIC CAPITAL LETTER AZU;Lu;0;L;;;;;N;;;;2C30;
2C01;GLAGOLITIC CAPITAL LETTER BUKY;Lu;0;L;;;;;N;;;;2C31;
2C02;GLAGOLITIC CAPITAL LETTER VEDE;Lu;0;L;;;;;N;;;;2C32;
@@ -10650,6 +10751,11 @@
2E47;LOW KAVYKA;Po;0;ON;;;;;N;;;;;
2E48;LOW KAVYKA WITH DOT;Po;0;ON;;;;;N;;;;;
2E49;DOUBLE STACKED COMMA;Po;0;ON;;;;;N;;;;;
+2E4A;DOTTED SOLIDUS;Po;0;ON;;;;;N;;;;;
+2E4B;TRIPLE DAGGER;Po;0;ON;;;;;N;;;;;
+2E4C;MEDIEVAL COMMA;Po;0;ON;;;;;N;;;;;
+2E4D;PARAGRAPHUS MARK;Po;0;ON;;;;;N;;;;;
+2E4E;PUNCTUS ELEVATUS MARK;Po;0;ON;;;;;N;;;;;
2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
@@ -11286,6 +11392,7 @@
312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
312D;BOPOMOFO LETTER IH;Lo;0;L;;;;;N;;;;;
312E;BOPOMOFO LETTER O WITH DOT ABOVE;Lo;0;L;;;;;N;;;;;
+312F;BOPOMOFO LETTER NN;Lo;0;L;;;;;N;;;;;
3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
@@ -12052,7 +12159,7 @@
4DFE;HEXAGRAM FOR AFTER COMPLETION;So;0;ON;;;;;N;;;;;
4DFF;HEXAGRAM FOR BEFORE COMPLETION;So;0;ON;;;;;N;;;;;
4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
-9FEA;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+9FEF;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
@@ -13980,6 +14087,7 @@ A7AB;LATIN CAPITAL LETTER REVERSED OPEN E;Lu;0;L;;;;;N;;;;025C;
A7AC;LATIN CAPITAL LETTER SCRIPT G;Lu;0;L;;;;;N;;;;0261;
A7AD;LATIN CAPITAL LETTER L WITH BELT;Lu;0;L;;;;;N;;;;026C;
A7AE;LATIN CAPITAL LETTER SMALL CAPITAL I;Lu;0;L;;;;;N;;;;026A;
+A7AF;LATIN LETTER SMALL CAPITAL Q;Ll;0;L;;;;;N;;;;;
A7B0;LATIN CAPITAL LETTER TURNED K;Lu;0;L;;;;;N;;;;029E;
A7B1;LATIN CAPITAL LETTER TURNED T;Lu;0;L;;;;;N;;;;0287;
A7B2;LATIN CAPITAL LETTER J WITH CROSSED-TAIL;Lu;0;L;;;;;N;;;;029D;
@@ -13988,6 +14096,8 @@ A7B4;LATIN CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;A7B5;
A7B5;LATIN SMALL LETTER BETA;Ll;0;L;;;;;N;;;A7B4;;A7B4
A7B6;LATIN CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;A7B7;
A7B7;LATIN SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;A7B6;;A7B6
+A7B8;LATIN CAPITAL LETTER U WITH STROKE;Lu;0;L;;;;;N;;;;A7B9;
+A7B9;LATIN SMALL LETTER U WITH STROKE;Ll;0;L;;;;;N;;;A7B8;;A7B8
A7F7;LATIN EPIGRAPHIC LETTER SIDEWAYS I;Lo;0;L;;;;;N;;;;;
A7F8;MODIFIER LETTER CAPITAL H WITH STROKE;Lm;0;L;<super> 0126;;;;N;;;;;
A7F9;MODIFIER LETTER SMALL LIGATURE OE;Lm;0;L;<super> 0153;;;;N;;;;;
@@ -14219,6 +14329,8 @@ A8FA;DEVANAGARI CARET;Po;0;L;;;;;N;;;;;
A8FB;DEVANAGARI HEADSTROKE;Lo;0;L;;;;;N;;;;;
A8FC;DEVANAGARI SIGN SIDDHAM;Po;0;L;;;;;N;;;;;
A8FD;DEVANAGARI JAIN OM;Lo;0;L;;;;;N;;;;;
+A8FE;DEVANAGARI LETTER AY;Lo;0;L;;;;;N;;;;;
+A8FF;DEVANAGARI VOWEL SIGN AY;Mn;0;NSM;;;;;N;;;;;
A900;KAYAH LI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
A901;KAYAH LI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
A902;KAYAH LI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
@@ -18363,6 +18475,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10A31;KHAROSHTHI LETTER HA;Lo;0;R;;;;;N;;;;;
10A32;KHAROSHTHI LETTER KKA;Lo;0;R;;;;;N;;;;;
10A33;KHAROSHTHI LETTER TTTHA;Lo;0;R;;;;;N;;;;;
+10A34;KHAROSHTHI LETTER TTTA;Lo;0;R;;;;;N;;;;;
+10A35;KHAROSHTHI LETTER VHA;Lo;0;R;;;;;N;;;;;
10A38;KHAROSHTHI SIGN BAR ABOVE;Mn;230;NSM;;;;;N;;;;;
10A39;KHAROSHTHI SIGN CAUDA;Mn;1;NSM;;;;;N;;;;;
10A3A;KHAROSHTHI SIGN DOT BELOW;Mn;220;NSM;;;;;N;;;;;
@@ -18375,6 +18489,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10A45;KHAROSHTHI NUMBER TWENTY;No;0;R;;;;20;N;;;;;
10A46;KHAROSHTHI NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
10A47;KHAROSHTHI NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10A48;KHAROSHTHI FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;
10A50;KHAROSHTHI PUNCTUATION DOT;Po;0;R;;;;;N;;;;;
10A51;KHAROSHTHI PUNCTUATION SMALL CIRCLE;Po;0;R;;;;;N;;;;;
10A52;KHAROSHTHI PUNCTUATION CIRCLE;Po;0;R;;;;;N;;;;;
@@ -18827,6 +18942,56 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10CFD;OLD HUNGARIAN NUMBER FIFTY;No;0;R;;;;50;N;;;;;
10CFE;OLD HUNGARIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
10CFF;OLD HUNGARIAN NUMBER ONE THOUSAND;No;0;R;;;;1000;N;;;;;
+10D00;HANIFI ROHINGYA LETTER A;Lo;0;AL;;;;;N;;;;;
+10D01;HANIFI ROHINGYA LETTER BA;Lo;0;AL;;;;;N;;;;;
+10D02;HANIFI ROHINGYA LETTER PA;Lo;0;AL;;;;;N;;;;;
+10D03;HANIFI ROHINGYA LETTER TA;Lo;0;AL;;;;;N;;;;;
+10D04;HANIFI ROHINGYA LETTER TTA;Lo;0;AL;;;;;N;;;;;
+10D05;HANIFI ROHINGYA LETTER JA;Lo;0;AL;;;;;N;;;;;
+10D06;HANIFI ROHINGYA LETTER CA;Lo;0;AL;;;;;N;;;;;
+10D07;HANIFI ROHINGYA LETTER HA;Lo;0;AL;;;;;N;;;;;
+10D08;HANIFI ROHINGYA LETTER KHA;Lo;0;AL;;;;;N;;;;;
+10D09;HANIFI ROHINGYA LETTER FA;Lo;0;AL;;;;;N;;;;;
+10D0A;HANIFI ROHINGYA LETTER DA;Lo;0;AL;;;;;N;;;;;
+10D0B;HANIFI ROHINGYA LETTER DDA;Lo;0;AL;;;;;N;;;;;
+10D0C;HANIFI ROHINGYA LETTER RA;Lo;0;AL;;;;;N;;;;;
+10D0D;HANIFI ROHINGYA LETTER RRA;Lo;0;AL;;;;;N;;;;;
+10D0E;HANIFI ROHINGYA LETTER ZA;Lo;0;AL;;;;;N;;;;;
+10D0F;HANIFI ROHINGYA LETTER SA;Lo;0;AL;;;;;N;;;;;
+10D10;HANIFI ROHINGYA LETTER SHA;Lo;0;AL;;;;;N;;;;;
+10D11;HANIFI ROHINGYA LETTER KA;Lo;0;AL;;;;;N;;;;;
+10D12;HANIFI ROHINGYA LETTER GA;Lo;0;AL;;;;;N;;;;;
+10D13;HANIFI ROHINGYA LETTER LA;Lo;0;AL;;;;;N;;;;;
+10D14;HANIFI ROHINGYA LETTER MA;Lo;0;AL;;;;;N;;;;;
+10D15;HANIFI ROHINGYA LETTER NA;Lo;0;AL;;;;;N;;;;;
+10D16;HANIFI ROHINGYA LETTER WA;Lo;0;AL;;;;;N;;;;;
+10D17;HANIFI ROHINGYA LETTER KINNA WA;Lo;0;AL;;;;;N;;;;;
+10D18;HANIFI ROHINGYA LETTER YA;Lo;0;AL;;;;;N;;;;;
+10D19;HANIFI ROHINGYA LETTER KINNA YA;Lo;0;AL;;;;;N;;;;;
+10D1A;HANIFI ROHINGYA LETTER NGA;Lo;0;AL;;;;;N;;;;;
+10D1B;HANIFI ROHINGYA LETTER NYA;Lo;0;AL;;;;;N;;;;;
+10D1C;HANIFI ROHINGYA LETTER VA;Lo;0;AL;;;;;N;;;;;
+10D1D;HANIFI ROHINGYA VOWEL A;Lo;0;AL;;;;;N;;;;;
+10D1E;HANIFI ROHINGYA VOWEL I;Lo;0;AL;;;;;N;;;;;
+10D1F;HANIFI ROHINGYA VOWEL U;Lo;0;AL;;;;;N;;;;;
+10D20;HANIFI ROHINGYA VOWEL E;Lo;0;AL;;;;;N;;;;;
+10D21;HANIFI ROHINGYA VOWEL O;Lo;0;AL;;;;;N;;;;;
+10D22;HANIFI ROHINGYA MARK SAKIN;Lo;0;AL;;;;;N;;;;;
+10D23;HANIFI ROHINGYA MARK NA KHONNA;Lo;0;AL;;;;;N;;;;;
+10D24;HANIFI ROHINGYA SIGN HARBAHAY;Mn;230;NSM;;;;;N;;;;;
+10D25;HANIFI ROHINGYA SIGN TAHALA;Mn;230;NSM;;;;;N;;;;;
+10D26;HANIFI ROHINGYA SIGN TANA;Mn;230;NSM;;;;;N;;;;;
+10D27;HANIFI ROHINGYA SIGN TASSI;Mn;230;NSM;;;;;N;;;;;
+10D30;HANIFI ROHINGYA DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+10D31;HANIFI ROHINGYA DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+10D32;HANIFI ROHINGYA DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+10D33;HANIFI ROHINGYA DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+10D34;HANIFI ROHINGYA DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+10D35;HANIFI ROHINGYA DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+10D36;HANIFI ROHINGYA DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+10D37;HANIFI ROHINGYA DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+10D38;HANIFI ROHINGYA DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+10D39;HANIFI ROHINGYA DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
10E60;RUMI DIGIT ONE;No;0;AN;;;1;1;N;;;;;
10E61;RUMI DIGIT TWO;No;0;AN;;;2;2;N;;;;;
10E62;RUMI DIGIT THREE;No;0;AN;;;3;3;N;;;;;
@@ -18858,6 +19023,88 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
10E7C;RUMI FRACTION ONE QUARTER;No;0;AN;;;;1/4;N;;;;;
10E7D;RUMI FRACTION ONE THIRD;No;0;AN;;;;1/3;N;;;;;
10E7E;RUMI FRACTION TWO THIRDS;No;0;AN;;;;2/3;N;;;;;
+10F00;OLD SOGDIAN LETTER ALEPH;Lo;0;R;;;;;N;;;;;
+10F01;OLD SOGDIAN LETTER FINAL ALEPH;Lo;0;R;;;;;N;;;;;
+10F02;OLD SOGDIAN LETTER BETH;Lo;0;R;;;;;N;;;;;
+10F03;OLD SOGDIAN LETTER FINAL BETH;Lo;0;R;;;;;N;;;;;
+10F04;OLD SOGDIAN LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+10F05;OLD SOGDIAN LETTER HE;Lo;0;R;;;;;N;;;;;
+10F06;OLD SOGDIAN LETTER FINAL HE;Lo;0;R;;;;;N;;;;;
+10F07;OLD SOGDIAN LETTER WAW;Lo;0;R;;;;;N;;;;;
+10F08;OLD SOGDIAN LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+10F09;OLD SOGDIAN LETTER HETH;Lo;0;R;;;;;N;;;;;
+10F0A;OLD SOGDIAN LETTER YODH;Lo;0;R;;;;;N;;;;;
+10F0B;OLD SOGDIAN LETTER KAPH;Lo;0;R;;;;;N;;;;;
+10F0C;OLD SOGDIAN LETTER LAMEDH;Lo;0;R;;;;;N;;;;;
+10F0D;OLD SOGDIAN LETTER MEM;Lo;0;R;;;;;N;;;;;
+10F0E;OLD SOGDIAN LETTER NUN;Lo;0;R;;;;;N;;;;;
+10F0F;OLD SOGDIAN LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+10F10;OLD SOGDIAN LETTER FINAL NUN WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F11;OLD SOGDIAN LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+10F12;OLD SOGDIAN LETTER AYIN;Lo;0;R;;;;;N;;;;;
+10F13;OLD SOGDIAN LETTER ALTERNATE AYIN;Lo;0;R;;;;;N;;;;;
+10F14;OLD SOGDIAN LETTER PE;Lo;0;R;;;;;N;;;;;
+10F15;OLD SOGDIAN LETTER SADHE;Lo;0;R;;;;;N;;;;;
+10F16;OLD SOGDIAN LETTER FINAL SADHE;Lo;0;R;;;;;N;;;;;
+10F17;OLD SOGDIAN LETTER FINAL SADHE WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F18;OLD SOGDIAN LETTER RESH-AYIN-DALETH;Lo;0;R;;;;;N;;;;;
+10F19;OLD SOGDIAN LETTER SHIN;Lo;0;R;;;;;N;;;;;
+10F1A;OLD SOGDIAN LETTER TAW;Lo;0;R;;;;;N;;;;;
+10F1B;OLD SOGDIAN LETTER FINAL TAW;Lo;0;R;;;;;N;;;;;
+10F1C;OLD SOGDIAN LETTER FINAL TAW WITH VERTICAL TAIL;Lo;0;R;;;;;N;;;;;
+10F1D;OLD SOGDIAN NUMBER ONE;No;0;R;;;;1;N;;;;;
+10F1E;OLD SOGDIAN NUMBER TWO;No;0;R;;;;2;N;;;;;
+10F1F;OLD SOGDIAN NUMBER THREE;No;0;R;;;;3;N;;;;;
+10F20;OLD SOGDIAN NUMBER FOUR;No;0;R;;;;4;N;;;;;
+10F21;OLD SOGDIAN NUMBER FIVE;No;0;R;;;;5;N;;;;;
+10F22;OLD SOGDIAN NUMBER TEN;No;0;R;;;;10;N;;;;;
+10F23;OLD SOGDIAN NUMBER TWENTY;No;0;R;;;;20;N;;;;;
+10F24;OLD SOGDIAN NUMBER THIRTY;No;0;R;;;;30;N;;;;;
+10F25;OLD SOGDIAN NUMBER ONE HUNDRED;No;0;R;;;;100;N;;;;;
+10F26;OLD SOGDIAN FRACTION ONE HALF;No;0;R;;;;1/2;N;;;;;
+10F27;OLD SOGDIAN LIGATURE AYIN-DALETH;Lo;0;R;;;;;N;;;;;
+10F30;SOGDIAN LETTER ALEPH;Lo;0;AL;;;;;N;;;;;
+10F31;SOGDIAN LETTER BETH;Lo;0;AL;;;;;N;;;;;
+10F32;SOGDIAN LETTER GIMEL;Lo;0;AL;;;;;N;;;;;
+10F33;SOGDIAN LETTER HE;Lo;0;AL;;;;;N;;;;;
+10F34;SOGDIAN LETTER WAW;Lo;0;AL;;;;;N;;;;;
+10F35;SOGDIAN LETTER ZAYIN;Lo;0;AL;;;;;N;;;;;
+10F36;SOGDIAN LETTER HETH;Lo;0;AL;;;;;N;;;;;
+10F37;SOGDIAN LETTER YODH;Lo;0;AL;;;;;N;;;;;
+10F38;SOGDIAN LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+10F39;SOGDIAN LETTER LAMEDH;Lo;0;AL;;;;;N;;;;;
+10F3A;SOGDIAN LETTER MEM;Lo;0;AL;;;;;N;;;;;
+10F3B;SOGDIAN LETTER NUN;Lo;0;AL;;;;;N;;;;;
+10F3C;SOGDIAN LETTER SAMEKH;Lo;0;AL;;;;;N;;;;;
+10F3D;SOGDIAN LETTER AYIN;Lo;0;AL;;;;;N;;;;;
+10F3E;SOGDIAN LETTER PE;Lo;0;AL;;;;;N;;;;;
+10F3F;SOGDIAN LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+10F40;SOGDIAN LETTER RESH-AYIN;Lo;0;AL;;;;;N;;;;;
+10F41;SOGDIAN LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+10F42;SOGDIAN LETTER TAW;Lo;0;AL;;;;;N;;;;;
+10F43;SOGDIAN LETTER FETH;Lo;0;AL;;;;;N;;;;;
+10F44;SOGDIAN LETTER LESH;Lo;0;AL;;;;;N;;;;;
+10F45;SOGDIAN INDEPENDENT SHIN;Lo;0;AL;;;;;N;;;;;
+10F46;SOGDIAN COMBINING DOT BELOW;Mn;220;NSM;;;;;N;;;;;
+10F47;SOGDIAN COMBINING TWO DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+10F48;SOGDIAN COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F49;SOGDIAN COMBINING TWO DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4A;SOGDIAN COMBINING CURVE ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4B;SOGDIAN COMBINING CURVE BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4C;SOGDIAN COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;;;;;
+10F4D;SOGDIAN COMBINING HOOK BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4E;SOGDIAN COMBINING LONG HOOK BELOW;Mn;220;NSM;;;;;N;;;;;
+10F4F;SOGDIAN COMBINING RESH BELOW;Mn;220;NSM;;;;;N;;;;;
+10F50;SOGDIAN COMBINING STROKE BELOW;Mn;220;NSM;;;;;N;;;;;
+10F51;SOGDIAN NUMBER ONE;No;0;AL;;;;1;N;;;;;
+10F52;SOGDIAN NUMBER TEN;No;0;AL;;;;10;N;;;;;
+10F53;SOGDIAN NUMBER TWENTY;No;0;AL;;;;20;N;;;;;
+10F54;SOGDIAN NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;
+10F55;SOGDIAN PUNCTUATION TWO VERTICAL BARS;Po;0;AL;;;;;N;;;;;
+10F56;SOGDIAN PUNCTUATION TWO VERTICAL BARS WITH DOTS;Po;0;AL;;;;;N;;;;;
+10F57;SOGDIAN PUNCTUATION CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
+10F58;SOGDIAN PUNCTUATION TWO CIRCLES WITH DOTS;Po;0;AL;;;;;N;;;;;
+10F59;SOGDIAN PUNCTUATION HALF CIRCLE WITH DOT;Po;0;AL;;;;;N;;;;;
11000;BRAHMI SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
11001;BRAHMI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
11002;BRAHMI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
@@ -19033,6 +19280,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
110BF;KAITHI DOUBLE SECTION MARK;Po;0;L;;;;;N;;;;;
110C0;KAITHI DANDA;Po;0;L;;;;;N;;;;;
110C1;KAITHI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+110CD;KAITHI NUMBER SIGN ABOVE;Cf;0;L;;;;;N;;;;;
110D0;SORA SOMPENG LETTER SAH;Lo;0;L;;;;;N;;;;;
110D1;SORA SOMPENG LETTER TAH;Lo;0;L;;;;;N;;;;;
110D2;SORA SOMPENG LETTER BAH;Lo;0;L;;;;;N;;;;;
@@ -19135,6 +19383,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11141;CHAKMA DANDA;Po;0;L;;;;;N;;;;;
11142;CHAKMA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
11143;CHAKMA QUESTION MARK;Po;0;L;;;;;N;;;;;
+11144;CHAKMA LETTER LHAA;Lo;0;L;;;;;N;;;;;
+11145;CHAKMA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11146;CHAKMA VOWEL SIGN EI;Mc;0;L;;;;;N;;;;;
11150;MAHAJANI LETTER A;Lo;0;L;;;;;N;;;;;
11151;MAHAJANI LETTER I;Lo;0;L;;;;;N;;;;;
11152;MAHAJANI LETTER U;Lo;0;L;;;;;N;;;;;
@@ -19247,7 +19498,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
111C6;SHARADA DOUBLE DANDA;Po;0;L;;;;;N;;;;;
111C7;SHARADA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
111C8;SHARADA SEPARATOR;Po;0;L;;;;;N;;;;;
-111C9;SHARADA SANDHI MARK;Po;0;L;;;;;N;;;;;
+111C9;SHARADA SANDHI MARK;Mn;0;NSM;;;;;N;;;;;
111CA;SHARADA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
111CB;SHARADA VOWEL MODIFIER MARK;Mn;0;NSM;;;;;N;;;;;
111CC;SHARADA EXTRA SHORT VOWEL MARK;Mn;0;NSM;;;;;N;;;;;
@@ -19507,6 +19758,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11337;GRANTHA LETTER SSA;Lo;0;L;;;;;N;;;;;
11338;GRANTHA LETTER SA;Lo;0;L;;;;;N;;;;;
11339;GRANTHA LETTER HA;Lo;0;L;;;;;N;;;;;
+1133B;COMBINING BINDU BELOW;Mn;7;NSM;;;;;N;;;;;
1133C;GRANTHA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
1133D;GRANTHA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
1133E;GRANTHA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
@@ -19634,6 +19886,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11459;NEWA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
1145B;NEWA PLACEHOLDER MARK;Po;0;L;;;;;N;;;;;
1145D;NEWA INSERTION SIGN;Po;0;L;;;;;N;;;;;
+1145E;NEWA SANDHI MARK;Mn;230;NSM;;;;;N;;;;;
11480;TIRHUTA ANJI;Lo;0;L;;;;;N;;;;;
11481;TIRHUTA LETTER A;Lo;0;L;;;;;N;;;;;
11482;TIRHUTA LETTER AA;Lo;0;L;;;;;N;;;;;
@@ -19992,6 +20245,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11717;AHOM LETTER GHA;Lo;0;L;;;;;N;;;;;
11718;AHOM LETTER BHA;Lo;0;L;;;;;N;;;;;
11719;AHOM LETTER JHA;Lo;0;L;;;;;N;;;;;
+1171A;AHOM LETTER ALTERNATE BA;Lo;0;L;;;;;N;;;;;
1171D;AHOM CONSONANT SIGN MEDIAL LA;Mn;0;NSM;;;;;N;;;;;
1171E;AHOM CONSONANT SIGN MEDIAL RA;Mn;0;NSM;;;;;N;;;;;
1171F;AHOM CONSONANT SIGN MEDIAL LIGATING RA;Mn;0;NSM;;;;;N;;;;;
@@ -20023,6 +20277,66 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1173D;AHOM SIGN SECTION;Po;0;L;;;;;N;;;;;
1173E;AHOM SIGN RULAI;Po;0;L;;;;;N;;;;;
1173F;AHOM SYMBOL VI;So;0;L;;;;;N;;;;;
+11800;DOGRA LETTER A;Lo;0;L;;;;;N;;;;;
+11801;DOGRA LETTER AA;Lo;0;L;;;;;N;;;;;
+11802;DOGRA LETTER I;Lo;0;L;;;;;N;;;;;
+11803;DOGRA LETTER II;Lo;0;L;;;;;N;;;;;
+11804;DOGRA LETTER U;Lo;0;L;;;;;N;;;;;
+11805;DOGRA LETTER UU;Lo;0;L;;;;;N;;;;;
+11806;DOGRA LETTER E;Lo;0;L;;;;;N;;;;;
+11807;DOGRA LETTER AI;Lo;0;L;;;;;N;;;;;
+11808;DOGRA LETTER O;Lo;0;L;;;;;N;;;;;
+11809;DOGRA LETTER AU;Lo;0;L;;;;;N;;;;;
+1180A;DOGRA LETTER KA;Lo;0;L;;;;;N;;;;;
+1180B;DOGRA LETTER KHA;Lo;0;L;;;;;N;;;;;
+1180C;DOGRA LETTER GA;Lo;0;L;;;;;N;;;;;
+1180D;DOGRA LETTER GHA;Lo;0;L;;;;;N;;;;;
+1180E;DOGRA LETTER NGA;Lo;0;L;;;;;N;;;;;
+1180F;DOGRA LETTER CA;Lo;0;L;;;;;N;;;;;
+11810;DOGRA LETTER CHA;Lo;0;L;;;;;N;;;;;
+11811;DOGRA LETTER JA;Lo;0;L;;;;;N;;;;;
+11812;DOGRA LETTER JHA;Lo;0;L;;;;;N;;;;;
+11813;DOGRA LETTER NYA;Lo;0;L;;;;;N;;;;;
+11814;DOGRA LETTER TTA;Lo;0;L;;;;;N;;;;;
+11815;DOGRA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11816;DOGRA LETTER DDA;Lo;0;L;;;;;N;;;;;
+11817;DOGRA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11818;DOGRA LETTER NNA;Lo;0;L;;;;;N;;;;;
+11819;DOGRA LETTER TA;Lo;0;L;;;;;N;;;;;
+1181A;DOGRA LETTER THA;Lo;0;L;;;;;N;;;;;
+1181B;DOGRA LETTER DA;Lo;0;L;;;;;N;;;;;
+1181C;DOGRA LETTER DHA;Lo;0;L;;;;;N;;;;;
+1181D;DOGRA LETTER NA;Lo;0;L;;;;;N;;;;;
+1181E;DOGRA LETTER PA;Lo;0;L;;;;;N;;;;;
+1181F;DOGRA LETTER PHA;Lo;0;L;;;;;N;;;;;
+11820;DOGRA LETTER BA;Lo;0;L;;;;;N;;;;;
+11821;DOGRA LETTER BHA;Lo;0;L;;;;;N;;;;;
+11822;DOGRA LETTER MA;Lo;0;L;;;;;N;;;;;
+11823;DOGRA LETTER YA;Lo;0;L;;;;;N;;;;;
+11824;DOGRA LETTER RA;Lo;0;L;;;;;N;;;;;
+11825;DOGRA LETTER LA;Lo;0;L;;;;;N;;;;;
+11826;DOGRA LETTER VA;Lo;0;L;;;;;N;;;;;
+11827;DOGRA LETTER SHA;Lo;0;L;;;;;N;;;;;
+11828;DOGRA LETTER SSA;Lo;0;L;;;;;N;;;;;
+11829;DOGRA LETTER SA;Lo;0;L;;;;;N;;;;;
+1182A;DOGRA LETTER HA;Lo;0;L;;;;;N;;;;;
+1182B;DOGRA LETTER RRA;Lo;0;L;;;;;N;;;;;
+1182C;DOGRA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+1182D;DOGRA VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+1182E;DOGRA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+1182F;DOGRA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11830;DOGRA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+11831;DOGRA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+11832;DOGRA VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+11833;DOGRA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+11834;DOGRA VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11835;DOGRA VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+11836;DOGRA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+11837;DOGRA SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11838;DOGRA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11839;DOGRA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1183A;DOGRA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+1183B;DOGRA ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
118A0;WARANG CITI CAPITAL LETTER NGAA;Lu;0;L;;;;;N;;;;118C0;
118A1;WARANG CITI CAPITAL LETTER A;Lu;0;L;;;;;N;;;;118C1;
118A2;WARANG CITI CAPITAL LETTER WI;Lu;0;L;;;;;N;;;;118C2;
@@ -20114,8 +20428,8 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11A04;ZANABAZAR SQUARE VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
11A05;ZANABAZAR SQUARE VOWEL SIGN OE;Mn;0;NSM;;;;;N;;;;;
11A06;ZANABAZAR SQUARE VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
-11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
-11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11A07;ZANABAZAR SQUARE VOWEL SIGN AI;Mn;0;L;;;;;N;;;;;
+11A08;ZANABAZAR SQUARE VOWEL SIGN AU;Mn;0;L;;;;;N;;;;;
11A09;ZANABAZAR SQUARE VOWEL SIGN REVERSED I;Mn;0;NSM;;;;;N;;;;;
11A0A;ZANABAZAR SQUARE VOWEL LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
11A0B;ZANABAZAR SQUARE LETTER KA;Lo;0;L;;;;;N;;;;;
@@ -20254,6 +20568,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11A9A;SOYOMBO MARK TSHEG;Po;0;L;;;;;N;;;;;
11A9B;SOYOMBO MARK SHAD;Po;0;L;;;;;N;;;;;
11A9C;SOYOMBO MARK DOUBLE SHAD;Po;0;L;;;;;N;;;;;
+11A9D;SOYOMBO MARK PLUTA;Lo;0;L;;;;;N;;;;;
11A9E;SOYOMBO HEAD MARK WITH MOON AND SUN AND TRIPLE FLAME;Po;0;L;;;;;N;;;;;
11A9F;SOYOMBO HEAD MARK WITH MOON AND SUN AND FLAME;Po;0;L;;;;;N;;;;;
11AA0;SOYOMBO HEAD MARK WITH MOON AND SUN;Po;0;L;;;;;N;;;;;
@@ -20556,6 +20871,94 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
11D57;MASARAM GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
11D58;MASARAM GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
11D59;MASARAM GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11D60;GUNJALA GONDI LETTER A;Lo;0;L;;;;;N;;;;;
+11D61;GUNJALA GONDI LETTER AA;Lo;0;L;;;;;N;;;;;
+11D62;GUNJALA GONDI LETTER I;Lo;0;L;;;;;N;;;;;
+11D63;GUNJALA GONDI LETTER II;Lo;0;L;;;;;N;;;;;
+11D64;GUNJALA GONDI LETTER U;Lo;0;L;;;;;N;;;;;
+11D65;GUNJALA GONDI LETTER UU;Lo;0;L;;;;;N;;;;;
+11D67;GUNJALA GONDI LETTER EE;Lo;0;L;;;;;N;;;;;
+11D68;GUNJALA GONDI LETTER AI;Lo;0;L;;;;;N;;;;;
+11D6A;GUNJALA GONDI LETTER OO;Lo;0;L;;;;;N;;;;;
+11D6B;GUNJALA GONDI LETTER AU;Lo;0;L;;;;;N;;;;;
+11D6C;GUNJALA GONDI LETTER YA;Lo;0;L;;;;;N;;;;;
+11D6D;GUNJALA GONDI LETTER VA;Lo;0;L;;;;;N;;;;;
+11D6E;GUNJALA GONDI LETTER BA;Lo;0;L;;;;;N;;;;;
+11D6F;GUNJALA GONDI LETTER BHA;Lo;0;L;;;;;N;;;;;
+11D70;GUNJALA GONDI LETTER MA;Lo;0;L;;;;;N;;;;;
+11D71;GUNJALA GONDI LETTER KA;Lo;0;L;;;;;N;;;;;
+11D72;GUNJALA GONDI LETTER KHA;Lo;0;L;;;;;N;;;;;
+11D73;GUNJALA GONDI LETTER TA;Lo;0;L;;;;;N;;;;;
+11D74;GUNJALA GONDI LETTER THA;Lo;0;L;;;;;N;;;;;
+11D75;GUNJALA GONDI LETTER LA;Lo;0;L;;;;;N;;;;;
+11D76;GUNJALA GONDI LETTER GA;Lo;0;L;;;;;N;;;;;
+11D77;GUNJALA GONDI LETTER GHA;Lo;0;L;;;;;N;;;;;
+11D78;GUNJALA GONDI LETTER DA;Lo;0;L;;;;;N;;;;;
+11D79;GUNJALA GONDI LETTER DHA;Lo;0;L;;;;;N;;;;;
+11D7A;GUNJALA GONDI LETTER NA;Lo;0;L;;;;;N;;;;;
+11D7B;GUNJALA GONDI LETTER CA;Lo;0;L;;;;;N;;;;;
+11D7C;GUNJALA GONDI LETTER CHA;Lo;0;L;;;;;N;;;;;
+11D7D;GUNJALA GONDI LETTER TTA;Lo;0;L;;;;;N;;;;;
+11D7E;GUNJALA GONDI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+11D7F;GUNJALA GONDI LETTER LLA;Lo;0;L;;;;;N;;;;;
+11D80;GUNJALA GONDI LETTER JA;Lo;0;L;;;;;N;;;;;
+11D81;GUNJALA GONDI LETTER JHA;Lo;0;L;;;;;N;;;;;
+11D82;GUNJALA GONDI LETTER DDA;Lo;0;L;;;;;N;;;;;
+11D83;GUNJALA GONDI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+11D84;GUNJALA GONDI LETTER NGA;Lo;0;L;;;;;N;;;;;
+11D85;GUNJALA GONDI LETTER PA;Lo;0;L;;;;;N;;;;;
+11D86;GUNJALA GONDI LETTER PHA;Lo;0;L;;;;;N;;;;;
+11D87;GUNJALA GONDI LETTER HA;Lo;0;L;;;;;N;;;;;
+11D88;GUNJALA GONDI LETTER RA;Lo;0;L;;;;;N;;;;;
+11D89;GUNJALA GONDI LETTER SA;Lo;0;L;;;;;N;;;;;
+11D8A;GUNJALA GONDI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+11D8B;GUNJALA GONDI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+11D8C;GUNJALA GONDI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+11D8D;GUNJALA GONDI VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+11D8E;GUNJALA GONDI VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+11D90;GUNJALA GONDI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+11D91;GUNJALA GONDI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+11D93;GUNJALA GONDI VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+11D94;GUNJALA GONDI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+11D95;GUNJALA GONDI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+11D96;GUNJALA GONDI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+11D97;GUNJALA GONDI VIRAMA;Mn;9;NSM;;;;;N;;;;;
+11D98;GUNJALA GONDI OM;Lo;0;L;;;;;N;;;;;
+11DA0;GUNJALA GONDI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+11DA1;GUNJALA GONDI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+11DA2;GUNJALA GONDI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+11DA3;GUNJALA GONDI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+11DA4;GUNJALA GONDI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+11DA5;GUNJALA GONDI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+11DA6;GUNJALA GONDI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+11DA7;GUNJALA GONDI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+11DA8;GUNJALA GONDI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+11DA9;GUNJALA GONDI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+11EE0;MAKASAR LETTER KA;Lo;0;L;;;;;N;;;;;
+11EE1;MAKASAR LETTER GA;Lo;0;L;;;;;N;;;;;
+11EE2;MAKASAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+11EE3;MAKASAR LETTER PA;Lo;0;L;;;;;N;;;;;
+11EE4;MAKASAR LETTER BA;Lo;0;L;;;;;N;;;;;
+11EE5;MAKASAR LETTER MA;Lo;0;L;;;;;N;;;;;
+11EE6;MAKASAR LETTER TA;Lo;0;L;;;;;N;;;;;
+11EE7;MAKASAR LETTER DA;Lo;0;L;;;;;N;;;;;
+11EE8;MAKASAR LETTER NA;Lo;0;L;;;;;N;;;;;
+11EE9;MAKASAR LETTER CA;Lo;0;L;;;;;N;;;;;
+11EEA;MAKASAR LETTER JA;Lo;0;L;;;;;N;;;;;
+11EEB;MAKASAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+11EEC;MAKASAR LETTER YA;Lo;0;L;;;;;N;;;;;
+11EED;MAKASAR LETTER RA;Lo;0;L;;;;;N;;;;;
+11EEE;MAKASAR LETTER LA;Lo;0;L;;;;;N;;;;;
+11EEF;MAKASAR LETTER VA;Lo;0;L;;;;;N;;;;;
+11EF0;MAKASAR LETTER SA;Lo;0;L;;;;;N;;;;;
+11EF1;MAKASAR LETTER A;Lo;0;L;;;;;N;;;;;
+11EF2;MAKASAR ANGKA;Lo;0;L;;;;;N;;;;;
+11EF3;MAKASAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+11EF4;MAKASAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+11EF5;MAKASAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+11EF6;MAKASAR VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+11EF7;MAKASAR PASSIMBANG;Po;0;L;;;;;N;;;;;
+11EF8;MAKASAR END OF SECTION;Po;0;L;;;;;N;;;;;
12000;CUNEIFORM SIGN A;Lo;0;L;;;;;N;;;;;
12001;CUNEIFORM SIGN A TIMES A;Lo;0;L;;;;;N;;;;;
12002;CUNEIFORM SIGN A TIMES BAD;Lo;0;L;;;;;N;;;;;
@@ -24219,6 +24622,97 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16B8D;PAHAWH HMONG CLAN SIGN TSWB;Lo;0;L;;;;;N;;;;;
16B8E;PAHAWH HMONG CLAN SIGN KWM;Lo;0;L;;;;;N;;;;;
16B8F;PAHAWH HMONG CLAN SIGN VWJ;Lo;0;L;;;;;N;;;;;
+16E40;MEDEFAIDRIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;16E60;
+16E41;MEDEFAIDRIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;16E61;
+16E42;MEDEFAIDRIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;16E62;
+16E43;MEDEFAIDRIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;16E63;
+16E44;MEDEFAIDRIN CAPITAL LETTER ATIU;Lu;0;L;;;;;N;;;;16E64;
+16E45;MEDEFAIDRIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;16E65;
+16E46;MEDEFAIDRIN CAPITAL LETTER KP;Lu;0;L;;;;;N;;;;16E66;
+16E47;MEDEFAIDRIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;16E67;
+16E48;MEDEFAIDRIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;16E68;
+16E49;MEDEFAIDRIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;16E69;
+16E4A;MEDEFAIDRIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;16E6A;
+16E4B;MEDEFAIDRIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;16E6B;
+16E4C;MEDEFAIDRIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;16E6C;
+16E4D;MEDEFAIDRIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;16E6D;
+16E4E;MEDEFAIDRIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;16E6E;
+16E4F;MEDEFAIDRIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;16E6F;
+16E50;MEDEFAIDRIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;16E70;
+16E51;MEDEFAIDRIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;16E71;
+16E52;MEDEFAIDRIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;16E72;
+16E53;MEDEFAIDRIN CAPITAL LETTER YU;Lu;0;L;;;;;N;;;;16E73;
+16E54;MEDEFAIDRIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;16E74;
+16E55;MEDEFAIDRIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;16E75;
+16E56;MEDEFAIDRIN CAPITAL LETTER HP;Lu;0;L;;;;;N;;;;16E76;
+16E57;MEDEFAIDRIN CAPITAL LETTER NY;Lu;0;L;;;;;N;;;;16E77;
+16E58;MEDEFAIDRIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;16E78;
+16E59;MEDEFAIDRIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;16E79;
+16E5A;MEDEFAIDRIN CAPITAL LETTER OE;Lu;0;L;;;;;N;;;;16E7A;
+16E5B;MEDEFAIDRIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;16E7B;
+16E5C;MEDEFAIDRIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;16E7C;
+16E5D;MEDEFAIDRIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;16E7D;
+16E5E;MEDEFAIDRIN CAPITAL LETTER AI;Lu;0;L;;;;;N;;;;16E7E;
+16E5F;MEDEFAIDRIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;16E7F;
+16E60;MEDEFAIDRIN SMALL LETTER M;Ll;0;L;;;;;N;;;16E40;;16E40
+16E61;MEDEFAIDRIN SMALL LETTER S;Ll;0;L;;;;;N;;;16E41;;16E41
+16E62;MEDEFAIDRIN SMALL LETTER V;Ll;0;L;;;;;N;;;16E42;;16E42
+16E63;MEDEFAIDRIN SMALL LETTER W;Ll;0;L;;;;;N;;;16E43;;16E43
+16E64;MEDEFAIDRIN SMALL LETTER ATIU;Ll;0;L;;;;;N;;;16E44;;16E44
+16E65;MEDEFAIDRIN SMALL LETTER Z;Ll;0;L;;;;;N;;;16E45;;16E45
+16E66;MEDEFAIDRIN SMALL LETTER KP;Ll;0;L;;;;;N;;;16E46;;16E46
+16E67;MEDEFAIDRIN SMALL LETTER P;Ll;0;L;;;;;N;;;16E47;;16E47
+16E68;MEDEFAIDRIN SMALL LETTER T;Ll;0;L;;;;;N;;;16E48;;16E48
+16E69;MEDEFAIDRIN SMALL LETTER G;Ll;0;L;;;;;N;;;16E49;;16E49
+16E6A;MEDEFAIDRIN SMALL LETTER F;Ll;0;L;;;;;N;;;16E4A;;16E4A
+16E6B;MEDEFAIDRIN SMALL LETTER I;Ll;0;L;;;;;N;;;16E4B;;16E4B
+16E6C;MEDEFAIDRIN SMALL LETTER K;Ll;0;L;;;;;N;;;16E4C;;16E4C
+16E6D;MEDEFAIDRIN SMALL LETTER A;Ll;0;L;;;;;N;;;16E4D;;16E4D
+16E6E;MEDEFAIDRIN SMALL LETTER J;Ll;0;L;;;;;N;;;16E4E;;16E4E
+16E6F;MEDEFAIDRIN SMALL LETTER E;Ll;0;L;;;;;N;;;16E4F;;16E4F
+16E70;MEDEFAIDRIN SMALL LETTER B;Ll;0;L;;;;;N;;;16E50;;16E50
+16E71;MEDEFAIDRIN SMALL LETTER C;Ll;0;L;;;;;N;;;16E51;;16E51
+16E72;MEDEFAIDRIN SMALL LETTER U;Ll;0;L;;;;;N;;;16E52;;16E52
+16E73;MEDEFAIDRIN SMALL LETTER YU;Ll;0;L;;;;;N;;;16E53;;16E53
+16E74;MEDEFAIDRIN SMALL LETTER L;Ll;0;L;;;;;N;;;16E54;;16E54
+16E75;MEDEFAIDRIN SMALL LETTER Q;Ll;0;L;;;;;N;;;16E55;;16E55
+16E76;MEDEFAIDRIN SMALL LETTER HP;Ll;0;L;;;;;N;;;16E56;;16E56
+16E77;MEDEFAIDRIN SMALL LETTER NY;Ll;0;L;;;;;N;;;16E57;;16E57
+16E78;MEDEFAIDRIN SMALL LETTER X;Ll;0;L;;;;;N;;;16E58;;16E58
+16E79;MEDEFAIDRIN SMALL LETTER D;Ll;0;L;;;;;N;;;16E59;;16E59
+16E7A;MEDEFAIDRIN SMALL LETTER OE;Ll;0;L;;;;;N;;;16E5A;;16E5A
+16E7B;MEDEFAIDRIN SMALL LETTER N;Ll;0;L;;;;;N;;;16E5B;;16E5B
+16E7C;MEDEFAIDRIN SMALL LETTER R;Ll;0;L;;;;;N;;;16E5C;;16E5C
+16E7D;MEDEFAIDRIN SMALL LETTER O;Ll;0;L;;;;;N;;;16E5D;;16E5D
+16E7E;MEDEFAIDRIN SMALL LETTER AI;Ll;0;L;;;;;N;;;16E5E;;16E5E
+16E7F;MEDEFAIDRIN SMALL LETTER Y;Ll;0;L;;;;;N;;;16E5F;;16E5F
+16E80;MEDEFAIDRIN DIGIT ZERO;No;0;L;;;;0;N;;;;;
+16E81;MEDEFAIDRIN DIGIT ONE;No;0;L;;;;1;N;;;;;
+16E82;MEDEFAIDRIN DIGIT TWO;No;0;L;;;;2;N;;;;;
+16E83;MEDEFAIDRIN DIGIT THREE;No;0;L;;;;3;N;;;;;
+16E84;MEDEFAIDRIN DIGIT FOUR;No;0;L;;;;4;N;;;;;
+16E85;MEDEFAIDRIN DIGIT FIVE;No;0;L;;;;5;N;;;;;
+16E86;MEDEFAIDRIN DIGIT SIX;No;0;L;;;;6;N;;;;;
+16E87;MEDEFAIDRIN DIGIT SEVEN;No;0;L;;;;7;N;;;;;
+16E88;MEDEFAIDRIN DIGIT EIGHT;No;0;L;;;;8;N;;;;;
+16E89;MEDEFAIDRIN DIGIT NINE;No;0;L;;;;9;N;;;;;
+16E8A;MEDEFAIDRIN NUMBER TEN;No;0;L;;;;10;N;;;;;
+16E8B;MEDEFAIDRIN NUMBER ELEVEN;No;0;L;;;;11;N;;;;;
+16E8C;MEDEFAIDRIN NUMBER TWELVE;No;0;L;;;;12;N;;;;;
+16E8D;MEDEFAIDRIN NUMBER THIRTEEN;No;0;L;;;;13;N;;;;;
+16E8E;MEDEFAIDRIN NUMBER FOURTEEN;No;0;L;;;;14;N;;;;;
+16E8F;MEDEFAIDRIN NUMBER FIFTEEN;No;0;L;;;;15;N;;;;;
+16E90;MEDEFAIDRIN NUMBER SIXTEEN;No;0;L;;;;16;N;;;;;
+16E91;MEDEFAIDRIN NUMBER SEVENTEEN;No;0;L;;;;17;N;;;;;
+16E92;MEDEFAIDRIN NUMBER EIGHTEEN;No;0;L;;;;18;N;;;;;
+16E93;MEDEFAIDRIN NUMBER NINETEEN;No;0;L;;;;19;N;;;;;
+16E94;MEDEFAIDRIN DIGIT ONE ALTERNATE FORM;No;0;L;;;;1;N;;;;;
+16E95;MEDEFAIDRIN DIGIT TWO ALTERNATE FORM;No;0;L;;;;2;N;;;;;
+16E96;MEDEFAIDRIN DIGIT THREE ALTERNATE FORM;No;0;L;;;;3;N;;;;;
+16E97;MEDEFAIDRIN COMMA;Po;0;L;;;;;N;;;;;
+16E98;MEDEFAIDRIN FULL STOP;Po;0;L;;;;;N;;;;;
+16E99;MEDEFAIDRIN SYMBOL AIVA;Po;0;L;;;;;N;;;;;
+16E9A;MEDEFAIDRIN EXCLAMATION OH;Po;0;L;;;;;N;;;;;
16F00;MIAO LETTER PA;Lo;0;L;;;;;N;;;;;
16F01;MIAO LETTER BA;Lo;0;L;;;;;N;;;;;
16F02;MIAO LETTER YI PA;Lo;0;L;;;;;N;;;;;
@@ -24355,7 +24849,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
16FE0;TANGUT ITERATION MARK;Lm;0;L;;;;;N;;;;;
16FE1;NUSHU ITERATION MARK;Lm;0;L;;;;;N;;;;;
17000;<Tangut Ideograph, First>;Lo;0;L;;;;;N;;;;;
-187EC;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+187F1;<Tangut Ideograph, Last>;Lo;0;L;;;;;N;;;;;
18800;TANGUT COMPONENT-001;Lo;0;L;;;;;N;;;;;
18801;TANGUT COMPONENT-002;Lo;0;L;;;;;N;;;;;
18802;TANGUT COMPONENT-003;Lo;0;L;;;;;N;;;;;
@@ -26488,6 +26982,26 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1D243;COMBINING GREEK MUSICAL TETRASEME;Mn;230;NSM;;;;;N;;;;;
1D244;COMBINING GREEK MUSICAL PENTASEME;Mn;230;NSM;;;;;N;;;;;
1D245;GREEK MUSICAL LEIMMA;So;0;ON;;;;;N;;;;;
+1D2E0;MAYAN NUMERAL ZERO;No;0;L;;;;0;N;;;;;
+1D2E1;MAYAN NUMERAL ONE;No;0;L;;;;1;N;;;;;
+1D2E2;MAYAN NUMERAL TWO;No;0;L;;;;2;N;;;;;
+1D2E3;MAYAN NUMERAL THREE;No;0;L;;;;3;N;;;;;
+1D2E4;MAYAN NUMERAL FOUR;No;0;L;;;;4;N;;;;;
+1D2E5;MAYAN NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+1D2E6;MAYAN NUMERAL SIX;No;0;L;;;;6;N;;;;;
+1D2E7;MAYAN NUMERAL SEVEN;No;0;L;;;;7;N;;;;;
+1D2E8;MAYAN NUMERAL EIGHT;No;0;L;;;;8;N;;;;;
+1D2E9;MAYAN NUMERAL NINE;No;0;L;;;;9;N;;;;;
+1D2EA;MAYAN NUMERAL TEN;No;0;L;;;;10;N;;;;;
+1D2EB;MAYAN NUMERAL ELEVEN;No;0;L;;;;11;N;;;;;
+1D2EC;MAYAN NUMERAL TWELVE;No;0;L;;;;12;N;;;;;
+1D2ED;MAYAN NUMERAL THIRTEEN;No;0;L;;;;13;N;;;;;
+1D2EE;MAYAN NUMERAL FOURTEEN;No;0;L;;;;14;N;;;;;
+1D2EF;MAYAN NUMERAL FIFTEEN;No;0;L;;;;15;N;;;;;
+1D2F0;MAYAN NUMERAL SIXTEEN;No;0;L;;;;16;N;;;;;
+1D2F1;MAYAN NUMERAL SEVENTEEN;No;0;L;;;;17;N;;;;;
+1D2F2;MAYAN NUMERAL EIGHTEEN;No;0;L;;;;18;N;;;;;
+1D2F3;MAYAN NUMERAL NINETEEN;No;0;L;;;;19;N;;;;;
1D300;MONOGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
1D301;DIGRAM FOR HEAVENLY EARTH;So;0;ON;;;;;N;;;;;
1D302;DIGRAM FOR HUMAN EARTH;So;0;ON;;;;;N;;;;;
@@ -26593,6 +27107,13 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1D36F;COUNTING ROD TENS DIGIT SEVEN;No;0;L;;;;70;N;;;;;
1D370;COUNTING ROD TENS DIGIT EIGHT;No;0;L;;;;80;N;;;;;
1D371;COUNTING ROD TENS DIGIT NINE;No;0;L;;;;90;N;;;;;
+1D372;IDEOGRAPHIC TALLY MARK ONE;No;0;L;;;;1;N;;;;;
+1D373;IDEOGRAPHIC TALLY MARK TWO;No;0;L;;;;2;N;;;;;
+1D374;IDEOGRAPHIC TALLY MARK THREE;No;0;L;;;;3;N;;;;;
+1D375;IDEOGRAPHIC TALLY MARK FOUR;No;0;L;;;;4;N;;;;;
+1D376;IDEOGRAPHIC TALLY MARK FIVE;No;0;L;;;;5;N;;;;;
+1D377;TALLY MARK ONE;No;0;L;;;;1;N;;;;;
+1D378;TALLY MARK FIVE;No;0;L;;;;5;N;;;;;
1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
@@ -28599,6 +29120,74 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1E959;ADLAM DIGIT NINE;Nd;0;R;;9;9;9;N;;;;;
1E95E;ADLAM INITIAL EXCLAMATION MARK;Po;0;R;;;;;N;;;;;
1E95F;ADLAM INITIAL QUESTION MARK;Po;0;R;;;;;N;;;;;
+1EC71;INDIC SIYAQ NUMBER ONE;No;0;AL;;;;1;N;;;;;
+1EC72;INDIC SIYAQ NUMBER TWO;No;0;AL;;;;2;N;;;;;
+1EC73;INDIC SIYAQ NUMBER THREE;No;0;AL;;;;3;N;;;;;
+1EC74;INDIC SIYAQ NUMBER FOUR;No;0;AL;;;;4;N;;;;;
+1EC75;INDIC SIYAQ NUMBER FIVE;No;0;AL;;;;5;N;;;;;
+1EC76;INDIC SIYAQ NUMBER SIX;No;0;AL;;;;6;N;;;;;
+1EC77;INDIC SIYAQ NUMBER SEVEN;No;0;AL;;;;7;N;;;;;
+1EC78;INDIC SIYAQ NUMBER EIGHT;No;0;AL;;;;8;N;;;;;
+1EC79;INDIC SIYAQ NUMBER NINE;No;0;AL;;;;9;N;;;;;
+1EC7A;INDIC SIYAQ NUMBER TEN;No;0;AL;;;;10;N;;;;;
+1EC7B;INDIC SIYAQ NUMBER TWENTY;No;0;AL;;;;20;N;;;;;
+1EC7C;INDIC SIYAQ NUMBER THIRTY;No;0;AL;;;;30;N;;;;;
+1EC7D;INDIC SIYAQ NUMBER FORTY;No;0;AL;;;;40;N;;;;;
+1EC7E;INDIC SIYAQ NUMBER FIFTY;No;0;AL;;;;50;N;;;;;
+1EC7F;INDIC SIYAQ NUMBER SIXTY;No;0;AL;;;;60;N;;;;;
+1EC80;INDIC SIYAQ NUMBER SEVENTY;No;0;AL;;;;70;N;;;;;
+1EC81;INDIC SIYAQ NUMBER EIGHTY;No;0;AL;;;;80;N;;;;;
+1EC82;INDIC SIYAQ NUMBER NINETY;No;0;AL;;;;90;N;;;;;
+1EC83;INDIC SIYAQ NUMBER ONE HUNDRED;No;0;AL;;;;100;N;;;;;
+1EC84;INDIC SIYAQ NUMBER TWO HUNDRED;No;0;AL;;;;200;N;;;;;
+1EC85;INDIC SIYAQ NUMBER THREE HUNDRED;No;0;AL;;;;300;N;;;;;
+1EC86;INDIC SIYAQ NUMBER FOUR HUNDRED;No;0;AL;;;;400;N;;;;;
+1EC87;INDIC SIYAQ NUMBER FIVE HUNDRED;No;0;AL;;;;500;N;;;;;
+1EC88;INDIC SIYAQ NUMBER SIX HUNDRED;No;0;AL;;;;600;N;;;;;
+1EC89;INDIC SIYAQ NUMBER SEVEN HUNDRED;No;0;AL;;;;700;N;;;;;
+1EC8A;INDIC SIYAQ NUMBER EIGHT HUNDRED;No;0;AL;;;;800;N;;;;;
+1EC8B;INDIC SIYAQ NUMBER NINE HUNDRED;No;0;AL;;;;900;N;;;;;
+1EC8C;INDIC SIYAQ NUMBER ONE THOUSAND;No;0;AL;;;;1000;N;;;;;
+1EC8D;INDIC SIYAQ NUMBER TWO THOUSAND;No;0;AL;;;;2000;N;;;;;
+1EC8E;INDIC SIYAQ NUMBER THREE THOUSAND;No;0;AL;;;;3000;N;;;;;
+1EC8F;INDIC SIYAQ NUMBER FOUR THOUSAND;No;0;AL;;;;4000;N;;;;;
+1EC90;INDIC SIYAQ NUMBER FIVE THOUSAND;No;0;AL;;;;5000;N;;;;;
+1EC91;INDIC SIYAQ NUMBER SIX THOUSAND;No;0;AL;;;;6000;N;;;;;
+1EC92;INDIC SIYAQ NUMBER SEVEN THOUSAND;No;0;AL;;;;7000;N;;;;;
+1EC93;INDIC SIYAQ NUMBER EIGHT THOUSAND;No;0;AL;;;;8000;N;;;;;
+1EC94;INDIC SIYAQ NUMBER NINE THOUSAND;No;0;AL;;;;9000;N;;;;;
+1EC95;INDIC SIYAQ NUMBER TEN THOUSAND;No;0;AL;;;;10000;N;;;;;
+1EC96;INDIC SIYAQ NUMBER TWENTY THOUSAND;No;0;AL;;;;20000;N;;;;;
+1EC97;INDIC SIYAQ NUMBER THIRTY THOUSAND;No;0;AL;;;;30000;N;;;;;
+1EC98;INDIC SIYAQ NUMBER FORTY THOUSAND;No;0;AL;;;;40000;N;;;;;
+1EC99;INDIC SIYAQ NUMBER FIFTY THOUSAND;No;0;AL;;;;50000;N;;;;;
+1EC9A;INDIC SIYAQ NUMBER SIXTY THOUSAND;No;0;AL;;;;60000;N;;;;;
+1EC9B;INDIC SIYAQ NUMBER SEVENTY THOUSAND;No;0;AL;;;;70000;N;;;;;
+1EC9C;INDIC SIYAQ NUMBER EIGHTY THOUSAND;No;0;AL;;;;80000;N;;;;;
+1EC9D;INDIC SIYAQ NUMBER NINETY THOUSAND;No;0;AL;;;;90000;N;;;;;
+1EC9E;INDIC SIYAQ NUMBER LAKH;No;0;AL;;;;100000;N;;;;;
+1EC9F;INDIC SIYAQ NUMBER LAKHAN;No;0;AL;;;;200000;N;;;;;
+1ECA0;INDIC SIYAQ LAKH MARK;No;0;AL;;;;100000;N;;;;;
+1ECA1;INDIC SIYAQ NUMBER KAROR;No;0;AL;;;;10000000;N;;;;;
+1ECA2;INDIC SIYAQ NUMBER KARORAN;No;0;AL;;;;20000000;N;;;;;
+1ECA3;INDIC SIYAQ NUMBER PREFIXED ONE;No;0;AL;;;;1;N;;;;;
+1ECA4;INDIC SIYAQ NUMBER PREFIXED TWO;No;0;AL;;;;2;N;;;;;
+1ECA5;INDIC SIYAQ NUMBER PREFIXED THREE;No;0;AL;;;;3;N;;;;;
+1ECA6;INDIC SIYAQ NUMBER PREFIXED FOUR;No;0;AL;;;;4;N;;;;;
+1ECA7;INDIC SIYAQ NUMBER PREFIXED FIVE;No;0;AL;;;;5;N;;;;;
+1ECA8;INDIC SIYAQ NUMBER PREFIXED SIX;No;0;AL;;;;6;N;;;;;
+1ECA9;INDIC SIYAQ NUMBER PREFIXED SEVEN;No;0;AL;;;;7;N;;;;;
+1ECAA;INDIC SIYAQ NUMBER PREFIXED EIGHT;No;0;AL;;;;8;N;;;;;
+1ECAB;INDIC SIYAQ NUMBER PREFIXED NINE;No;0;AL;;;;9;N;;;;;
+1ECAC;INDIC SIYAQ PLACEHOLDER;So;0;AL;;;;;N;;;;;
+1ECAD;INDIC SIYAQ FRACTION ONE QUARTER;No;0;AL;;;;1/4;N;;;;;
+1ECAE;INDIC SIYAQ FRACTION ONE HALF;No;0;AL;;;;1/2;N;;;;;
+1ECAF;INDIC SIYAQ FRACTION THREE QUARTERS;No;0;AL;;;;3/4;N;;;;;
+1ECB0;INDIC SIYAQ RUPEE MARK;Sc;0;AL;;;;;N;;;;;
+1ECB1;INDIC SIYAQ NUMBER ALTERNATE ONE;No;0;AL;;;;1;N;;;;;
+1ECB2;INDIC SIYAQ NUMBER ALTERNATE TWO;No;0;AL;;;;2;N;;;;;
+1ECB3;INDIC SIYAQ NUMBER ALTERNATE TEN THOUSAND;No;0;AL;;;;10000;N;;;;;
+1ECB4;INDIC SIYAQ ALTERNATE LAKH MARK;No;0;AL;;;;100000;N;;;;;
1EE00;ARABIC MATHEMATICAL ALEF;Lo;0;AL;<font> 0627;;;;N;;;;;
1EE01;ARABIC MATHEMATICAL BEH;Lo;0;AL;<font> 0628;;;;N;;;;;
1EE02;ARABIC MATHEMATICAL JEEM;Lo;0;AL;<font> 062C;;;;N;;;;;
@@ -29012,6 +29601,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F12C;CIRCLED ITALIC LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;;
1F12D;CIRCLED CD;So;0;L;<circle> 0043 0044;;;;N;;;;;
1F12E;CIRCLED WZ;So;0;L;<circle> 0057 005A;;;;N;;;;;
+1F12F;COPYLEFT SYMBOL;So;0;ON;;;;;N;;;;;
1F130;SQUARED LATIN CAPITAL LETTER A;So;0;L;<square> 0041;;;;N;;;;;
1F131;SQUARED LATIN CAPITAL LETTER B;So;0;L;<square> 0042;;;;N;;;;;
1F132;SQUARED LATIN CAPITAL LETTER C;So;0;L;<square> 0043;;;;N;;;;;
@@ -30226,6 +30816,7 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F6F6;CANOE;So;0;ON;;;;;N;;;;;
1F6F7;SLED;So;0;ON;;;;;N;;;;;
1F6F8;FLYING SAUCER;So;0;ON;;;;;N;;;;;
+1F6F9;SKATEBOARD;So;0;ON;;;;;N;;;;;
1F700;ALCHEMICAL SYMBOL FOR QUINTESSENCE;So;0;ON;;;;;N;;;;;
1F701;ALCHEMICAL SYMBOL FOR AIR;So;0;ON;;;;;N;;;;;
1F702;ALCHEMICAL SYMBOL FOR FIRE;So;0;ON;;;;;N;;;;;
@@ -30427,6 +31018,10 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F7D2;LIGHT TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
1F7D3;HEAVY TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
1F7D4;HEAVY TWELVE POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+1F7D5;CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F7D6;NEGATIVE CIRCLED TRIANGLE;So;0;ON;;;;;N;;;;;
+1F7D7;CIRCLED SQUARE;So;0;ON;;;;;N;;;;;
+1F7D8;NEGATIVE CIRCLED SQUARE;So;0;ON;;;;;N;;;;;
1F800;LEFTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
1F801;UPWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
1F802;RIGHTWARDS ARROW WITH SMALL TRIANGLE ARROWHEAD;So;0;ON;;;;;N;;;;;
@@ -30647,6 +31242,9 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F94A;BOXING GLOVE;So;0;ON;;;;;N;;;;;
1F94B;MARTIAL ARTS UNIFORM;So;0;ON;;;;;N;;;;;
1F94C;CURLING STONE;So;0;ON;;;;;N;;;;;
+1F94D;LACROSSE STICK AND BALL;So;0;ON;;;;;N;;;;;
+1F94E;SOFTBALL;So;0;ON;;;;;N;;;;;
+1F94F;FLYING DISC;So;0;ON;;;;;N;;;;;
1F950;CROISSANT;So;0;ON;;;;;N;;;;;
1F951;AVOCADO;So;0;ON;;;;;N;;;;;
1F952;CUCUMBER;So;0;ON;;;;;N;;;;;
@@ -30675,6 +31273,20 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F969;CUT OF MEAT;So;0;ON;;;;;N;;;;;
1F96A;SANDWICH;So;0;ON;;;;;N;;;;;
1F96B;CANNED FOOD;So;0;ON;;;;;N;;;;;
+1F96C;LEAFY GREEN;So;0;ON;;;;;N;;;;;
+1F96D;MANGO;So;0;ON;;;;;N;;;;;
+1F96E;MOON CAKE;So;0;ON;;;;;N;;;;;
+1F96F;BAGEL;So;0;ON;;;;;N;;;;;
+1F970;SMILING FACE WITH SMILING EYES AND THREE HEARTS;So;0;ON;;;;;N;;;;;
+1F973;FACE WITH PARTY HORN AND PARTY HAT;So;0;ON;;;;;N;;;;;
+1F974;FACE WITH UNEVEN EYES AND WAVY MOUTH;So;0;ON;;;;;N;;;;;
+1F975;OVERHEATED FACE;So;0;ON;;;;;N;;;;;
+1F976;FREEZING FACE;So;0;ON;;;;;N;;;;;
+1F97A;FACE WITH PLEADING EYES;So;0;ON;;;;;N;;;;;
+1F97C;LAB COAT;So;0;ON;;;;;N;;;;;
+1F97D;GOGGLES;So;0;ON;;;;;N;;;;;
+1F97E;HIKING BOOT;So;0;ON;;;;;N;;;;;
+1F97F;FLAT SHOE;So;0;ON;;;;;N;;;;;
1F980;CRAB;So;0;ON;;;;;N;;;;;
1F981;LION FACE;So;0;ON;;;;;N;;;;;
1F982;SCORPION;So;0;ON;;;;;N;;;;;
@@ -30699,7 +31311,30 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F995;SAUROPOD;So;0;ON;;;;;N;;;;;
1F996;T-REX;So;0;ON;;;;;N;;;;;
1F997;CRICKET;So;0;ON;;;;;N;;;;;
+1F998;KANGAROO;So;0;ON;;;;;N;;;;;
+1F999;LLAMA;So;0;ON;;;;;N;;;;;
+1F99A;PEACOCK;So;0;ON;;;;;N;;;;;
+1F99B;HIPPOPOTAMUS;So;0;ON;;;;;N;;;;;
+1F99C;PARROT;So;0;ON;;;;;N;;;;;
+1F99D;RACCOON;So;0;ON;;;;;N;;;;;
+1F99E;LOBSTER;So;0;ON;;;;;N;;;;;
+1F99F;MOSQUITO;So;0;ON;;;;;N;;;;;
+1F9A0;MICROBE;So;0;ON;;;;;N;;;;;
+1F9A1;BADGER;So;0;ON;;;;;N;;;;;
+1F9A2;SWAN;So;0;ON;;;;;N;;;;;
+1F9B0;EMOJI COMPONENT RED HAIR;So;0;ON;;;;;N;;;;;
+1F9B1;EMOJI COMPONENT CURLY HAIR;So;0;ON;;;;;N;;;;;
+1F9B2;EMOJI COMPONENT BALD;So;0;ON;;;;;N;;;;;
+1F9B3;EMOJI COMPONENT WHITE HAIR;So;0;ON;;;;;N;;;;;
+1F9B4;BONE;So;0;ON;;;;;N;;;;;
+1F9B5;LEG;So;0;ON;;;;;N;;;;;
+1F9B6;FOOT;So;0;ON;;;;;N;;;;;
+1F9B7;TOOTH;So;0;ON;;;;;N;;;;;
+1F9B8;SUPERHERO;So;0;ON;;;;;N;;;;;
+1F9B9;SUPERVILLAIN;So;0;ON;;;;;N;;;;;
1F9C0;CHEESE WEDGE;So;0;ON;;;;;N;;;;;
+1F9C1;CUPCAKE;So;0;ON;;;;;N;;;;;
+1F9C2;SALT SHAKER;So;0;ON;;;;;N;;;;;
1F9D0;FACE WITH MONOCLE;So;0;ON;;;;;N;;;;;
1F9D1;ADULT;So;0;ON;;;;;N;;;;;
1F9D2;CHILD;So;0;ON;;;;;N;;;;;
@@ -30723,6 +31358,45 @@ FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
1F9E4;GLOVES;So;0;ON;;;;;N;;;;;
1F9E5;COAT;So;0;ON;;;;;N;;;;;
1F9E6;SOCKS;So;0;ON;;;;;N;;;;;
+1F9E7;RED GIFT ENVELOPE;So;0;ON;;;;;N;;;;;
+1F9E8;FIRECRACKER;So;0;ON;;;;;N;;;;;
+1F9E9;JIGSAW PUZZLE PIECE;So;0;ON;;;;;N;;;;;
+1F9EA;TEST TUBE;So;0;ON;;;;;N;;;;;
+1F9EB;PETRI DISH;So;0;ON;;;;;N;;;;;
+1F9EC;DNA DOUBLE HELIX;So;0;ON;;;;;N;;;;;
+1F9ED;COMPASS;So;0;ON;;;;;N;;;;;
+1F9EE;ABACUS;So;0;ON;;;;;N;;;;;
+1F9EF;FIRE EXTINGUISHER;So;0;ON;;;;;N;;;;;
+1F9F0;TOOLBOX;So;0;ON;;;;;N;;;;;
+1F9F1;BRICK;So;0;ON;;;;;N;;;;;
+1F9F2;MAGNET;So;0;ON;;;;;N;;;;;
+1F9F3;LUGGAGE;So;0;ON;;;;;N;;;;;
+1F9F4;LOTION BOTTLE;So;0;ON;;;;;N;;;;;
+1F9F5;SPOOL OF THREAD;So;0;ON;;;;;N;;;;;
+1F9F6;BALL OF YARN;So;0;ON;;;;;N;;;;;
+1F9F7;SAFETY PIN;So;0;ON;;;;;N;;;;;
+1F9F8;TEDDY BEAR;So;0;ON;;;;;N;;;;;
+1F9F9;BROOM;So;0;ON;;;;;N;;;;;
+1F9FA;BASKET;So;0;ON;;;;;N;;;;;
+1F9FB;ROLL OF PAPER;So;0;ON;;;;;N;;;;;
+1F9FC;BAR OF SOAP;So;0;ON;;;;;N;;;;;
+1F9FD;SPONGE;So;0;ON;;;;;N;;;;;
+1F9FE;RECEIPT;So;0;ON;;;;;N;;;;;
+1F9FF;NAZAR AMULET;So;0;ON;;;;;N;;;;;
+1FA60;XIANGQI RED GENERAL;So;0;ON;;;;;N;;;;;
+1FA61;XIANGQI RED MANDARIN;So;0;ON;;;;;N;;;;;
+1FA62;XIANGQI RED ELEPHANT;So;0;ON;;;;;N;;;;;
+1FA63;XIANGQI RED HORSE;So;0;ON;;;;;N;;;;;
+1FA64;XIANGQI RED CHARIOT;So;0;ON;;;;;N;;;;;
+1FA65;XIANGQI RED CANNON;So;0;ON;;;;;N;;;;;
+1FA66;XIANGQI RED SOLDIER;So;0;ON;;;;;N;;;;;
+1FA67;XIANGQI BLACK GENERAL;So;0;ON;;;;;N;;;;;
+1FA68;XIANGQI BLACK MANDARIN;So;0;ON;;;;;N;;;;;
+1FA69;XIANGQI BLACK ELEPHANT;So;0;ON;;;;;N;;;;;
+1FA6A;XIANGQI BLACK HORSE;So;0;ON;;;;;N;;;;;
+1FA6B;XIANGQI BLACK CHARIOT;So;0;ON;;;;;N;;;;;
+1FA6C;XIANGQI BLACK CANNON;So;0;ON;;;;;N;;;;;
+1FA6D;XIANGQI BLACK SOLDIER;So;0;ON;;;;;N;;;;;
20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
2A700;<CJK Ideograph Extension C, First>;Lo;0;L;;;;;N;;;;;
diff --git a/lib/stdlib/uc_spec/emoji-data.txt b/lib/stdlib/uc_spec/emoji-data.txt
new file mode 100644
index 0000000000..6e66455252
--- /dev/null
+++ b/lib/stdlib/uc_spec/emoji-data.txt
@@ -0,0 +1,714 @@
+# emoji-data.txt
+# Date: 2018-02-07, 07:55:18 GMT
+# © 2018 Unicode®, Inc.
+# Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries.
+# For terms of use, see http://www.unicode.org/terms_of_use.html
+#
+# Emoji Data for UTS #51
+# Version: 11.0
+#
+# For documentation and usage, see http://www.unicode.org/reports/tr51
+#
+# Format:
+# <codepoint(s)> ; <property> # <comments>
+# Note: there is no guarantee as to the structure of whitespace or comments
+#
+# Characters and sequences are listed in code point order. Users should be shown a more natural order.
+# See the CLDR collation order for Emoji.
+
+
+# ================================================
+
+# All omitted code points have Emoji=No
+# @missing: 0000..10FFFF ; Emoji ; No
+
+0023 ; Emoji # 1.1 [1] (#️) number sign
+002A ; Emoji # 1.1 [1] (*️) asterisk
+0030..0039 ; Emoji # 1.1 [10] (0️..9️) digit zero..digit nine
+00A9 ; Emoji # 1.1 [1] (©️) copyright
+00AE ; Emoji # 1.1 [1] (®️) registered
+203C ; Emoji # 1.1 [1] (‼️) double exclamation mark
+2049 ; Emoji # 3.0 [1] (⁉️) exclamation question mark
+2122 ; Emoji # 1.1 [1] (™️) trade mark
+2139 ; Emoji # 3.0 [1] (ℹ️) information
+2194..2199 ; Emoji # 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Emoji # 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Emoji # 1.1 [2] (⌚..⌛) watch..hourglass done
+2328 ; Emoji # 1.1 [1] (⌨️) keyboard
+23CF ; Emoji # 4.0 [1] (⏏️) eject button
+23E9..23F3 ; Emoji # 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done
+23F8..23FA ; Emoji # 7.0 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Emoji # 1.1 [1] (Ⓜ️) circled M
+25AA..25AB ; Emoji # 1.1 [2] (▪️..▫️) black small square..white small square
+25B6 ; Emoji # 1.1 [1] (▶️) play button
+25C0 ; Emoji # 1.1 [1] (◀️) reverse button
+25FB..25FE ; Emoji # 3.2 [4] (◻️..◾) white medium square..black medium-small square
+2600..2604 ; Emoji # 1.1 [5] (☀️..☄️) sun..comet
+260E ; Emoji # 1.1 [1] (☎️) telephone
+2611 ; Emoji # 1.1 [1] (☑️) ballot box with check
+2614..2615 ; Emoji # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2618 ; Emoji # 4.1 [1] (☘️) shamrock
+261D ; Emoji # 1.1 [1] (☝️) index pointing up
+2620 ; Emoji # 1.1 [1] (☠️) skull and crossbones
+2622..2623 ; Emoji # 1.1 [2] (☢️..☣️) radioactive..biohazard
+2626 ; Emoji # 1.1 [1] (☦️) orthodox cross
+262A ; Emoji # 1.1 [1] (☪️) star and crescent
+262E..262F ; Emoji # 1.1 [2] (☮️..☯️) peace symbol..yin yang
+2638..263A ; Emoji # 1.1 [3] (☸️..☺️) wheel of dharma..smiling face
+2640 ; Emoji # 1.1 [1] (♀️) female sign
+2642 ; Emoji # 1.1 [1] (♂️) male sign
+2648..2653 ; Emoji # 1.1 [12] (♈..♓) Aries..Pisces
+265F..2660 ; Emoji # 1.1 [2] (♟️..♠️) chess pawn..spade suit
+2663 ; Emoji # 1.1 [1] (♣️) club suit
+2665..2666 ; Emoji # 1.1 [2] (♥️..♦️) heart suit..diamond suit
+2668 ; Emoji # 1.1 [1] (♨️) hot springs
+267B ; Emoji # 3.2 [1] (♻️) recycling symbol
+267E..267F ; Emoji # 4.1 [2] (♾️..♿) infinity..wheelchair symbol
+2692..2697 ; Emoji # 4.1 [6] (⚒️..⚗️) hammer and pick..alembic
+2699 ; Emoji # 4.1 [1] (⚙️) gear
+269B..269C ; Emoji # 4.1 [2] (⚛️..⚜️) atom symbol..fleur-de-lis
+26A0..26A1 ; Emoji # 4.0 [2] (⚠️..⚡) warning..high voltage
+26AA..26AB ; Emoji # 4.1 [2] (⚪..⚫) white circle..black circle
+26B0..26B1 ; Emoji # 4.1 [2] (⚰️..⚱️) coffin..funeral urn
+26BD..26BE ; Emoji # 5.2 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26C8 ; Emoji # 5.2 [1] (⛈️) cloud with lightning and rain
+26CE ; Emoji # 6.0 [1] (⛎) Ophiuchus
+26CF ; Emoji # 5.2 [1] (⛏️) pick
+26D1 ; Emoji # 5.2 [1] (⛑️) rescue worker’s helmet
+26D3..26D4 ; Emoji # 5.2 [2] (⛓️..⛔) chains..no entry
+26E9..26EA ; Emoji # 5.2 [2] (⛩️..⛪) shinto shrine..church
+26F0..26F5 ; Emoji # 5.2 [6] (⛰️..⛵) mountain..sailboat
+26F7..26FA ; Emoji # 5.2 [4] (⛷️..⛺) skier..tent
+26FD ; Emoji # 5.2 [1] (⛽) fuel pump
+2702 ; Emoji # 1.1 [1] (✂️) scissors
+2705 ; Emoji # 6.0 [1] (✅) white heavy check mark
+2708..2709 ; Emoji # 1.1 [2] (✈️..✉️) airplane..envelope
+270A..270B ; Emoji # 6.0 [2] (✊..✋) raised fist..raised hand
+270C..270D ; Emoji # 1.1 [2] (✌️..✍️) victory hand..writing hand
+270F ; Emoji # 1.1 [1] (✏️) pencil
+2712 ; Emoji # 1.1 [1] (✒️) black nib
+2714 ; Emoji # 1.1 [1] (✔️) heavy check mark
+2716 ; Emoji # 1.1 [1] (✖️) heavy multiplication x
+271D ; Emoji # 1.1 [1] (✝️) latin cross
+2721 ; Emoji # 1.1 [1] (✡️) star of David
+2728 ; Emoji # 6.0 [1] (✨) sparkles
+2733..2734 ; Emoji # 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Emoji # 1.1 [1] (❄️) snowflake
+2747 ; Emoji # 1.1 [1] (❇️) sparkle
+274C ; Emoji # 6.0 [1] (❌) cross mark
+274E ; Emoji # 6.0 [1] (❎) cross mark button
+2753..2755 ; Emoji # 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Emoji # 5.2 [1] (❗) exclamation mark
+2763..2764 ; Emoji # 1.1 [2] (❣️..❤️) heavy heart exclamation..red heart
+2795..2797 ; Emoji # 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27A1 ; Emoji # 1.1 [1] (➡️) right arrow
+27B0 ; Emoji # 6.0 [1] (➰) curly loop
+27BF ; Emoji # 6.0 [1] (➿) double curly loop
+2934..2935 ; Emoji # 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Emoji # 4.0 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Emoji # 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji # 5.1 [1] (⭐) star
+2B55 ; Emoji # 5.2 [1] (⭕) heavy large circle
+3030 ; Emoji # 1.1 [1] (〰️) wavy dash
+303D ; Emoji # 3.2 [1] (〽️) part alternation mark
+3297 ; Emoji # 1.1 [1] (㊗️) Japanese “congratulations” button
+3299 ; Emoji # 1.1 [1] (㊙️) Japanese “secret” button
+1F004 ; Emoji # 5.1 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji # 6.0 [1] (🃏) joker
+1F170..1F171 ; Emoji # 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E ; Emoji # 6.0 [1] (🅾️) O button (blood type)
+1F17F ; Emoji # 5.2 [1] (🅿️) P button
+1F18E ; Emoji # 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji # 6.0 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201..1F202 ; Emoji # 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F21A ; Emoji # 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji # 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Emoji # 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F250..1F251 ; Emoji # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F320 ; Emoji # 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F321 ; Emoji # 7.0 [1] (🌡️) thermometer
+1F324..1F32C ; Emoji # 7.0 [9] (🌤️..🌬️) sun behind small cloud..wind face
+1F32D..1F32F ; Emoji # 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Emoji # 6.0 [6] (🌰..🌵) chestnut..cactus
+1F336 ; Emoji # 7.0 [1] (🌶️) hot pepper
+1F337..1F37C ; Emoji # 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37D ; Emoji # 7.0 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Emoji # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji # 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F396..1F397 ; Emoji # 7.0 [2] (🎖️..🎗️) military medal..reminder ribbon
+1F399..1F39B ; Emoji # 7.0 [3] (🎙️..🎛️) studio microphone..control knobs
+1F39E..1F39F ; Emoji # 7.0 [2] (🎞️..🎟️) film frames..admission tickets
+1F3A0..1F3C4 ; Emoji # 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji # 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Emoji # 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CB..1F3CE ; Emoji # 7.0 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Emoji # 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Emoji # 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3F0 ; Emoji # 6.0 [17] (🏠..🏰) house..castle
+1F3F3..1F3F5 ; Emoji # 7.0 [3] (🏳️..🏵️) white flag..rosette
+1F3F7 ; Emoji # 7.0 [1] (🏷️) label
+1F3F8..1F3FF ; Emoji # 8.0 [8] (🏸..🏿) badminton..dark skin tone
+1F400..1F43E ; Emoji # 6.0 [63] (🐀..🐾) rat..paw prints
+1F43F ; Emoji # 7.0 [1] (🐿️) chipmunk
+1F440 ; Emoji # 6.0 [1] (👀) eyes
+1F441 ; Emoji # 7.0 [1] (👁️) eye
+1F442..1F4F7 ; Emoji # 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Emoji # 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji # 6.0 [4] (📹..📼) video camera..videocassette
+1F4FD ; Emoji # 7.0 [1] (📽️) film projector
+1F4FF ; Emoji # 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Emoji # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F549..1F54A ; Emoji # 7.0 [2] (🕉️..🕊️) om..dove
+1F54B..1F54E ; Emoji # 8.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F567 ; Emoji # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F56F..1F570 ; Emoji # 7.0 [2] (🕯️..🕰️) candle..mantelpiece clock
+1F573..1F579 ; Emoji # 7.0 [7] (🕳️..🕹️) hole..joystick
+1F57A ; Emoji # 9.0 [1] (🕺) man dancing
+1F587 ; Emoji # 7.0 [1] (🖇️) linked paperclips
+1F58A..1F58D ; Emoji # 7.0 [4] (🖊️..🖍️) pen..crayon
+1F590 ; Emoji # 7.0 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji # 9.0 [1] (🖤) black heart
+1F5A5 ; Emoji # 7.0 [1] (🖥️) desktop computer
+1F5A8 ; Emoji # 7.0 [1] (🖨️) printer
+1F5B1..1F5B2 ; Emoji # 7.0 [2] (🖱️..🖲️) computer mouse..trackball
+1F5BC ; Emoji # 7.0 [1] (🖼️) framed picture
+1F5C2..1F5C4 ; Emoji # 7.0 [3] (🗂️..🗄️) card index dividers..file cabinet
+1F5D1..1F5D3 ; Emoji # 7.0 [3] (🗑️..🗓️) wastebasket..spiral calendar
+1F5DC..1F5DE ; Emoji # 7.0 [3] (🗜️..🗞️) clamp..rolled-up newspaper
+1F5E1 ; Emoji # 7.0 [1] (🗡️) dagger
+1F5E3 ; Emoji # 7.0 [1] (🗣️) speaking head
+1F5E8 ; Emoji # 7.0 [1] (🗨️) left speech bubble
+1F5EF ; Emoji # 7.0 [1] (🗯️) right anger bubble
+1F5F3 ; Emoji # 7.0 [1] (🗳️) ballot box with ballot
+1F5FA ; Emoji # 7.0 [1] (🗺️) world map
+1F5FB..1F5FF ; Emoji # 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji # 6.1 [1] (😀) grinning face
+1F601..1F610 ; Emoji # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Emoji # 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Emoji # 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji # 6.1 [1] (😕) confused face
+1F616 ; Emoji # 6.0 [1] (😖) confounded face
+1F617 ; Emoji # 6.1 [1] (😗) kissing face
+1F618 ; Emoji # 6.0 [1] (😘) face blowing a kiss
+1F619 ; Emoji # 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji # 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji # 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji # 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji # 6.1 [1] (😟) worried face
+1F620..1F625 ; Emoji # 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji # 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji # 6.1 [1] (😬) grimacing face
+1F62D ; Emoji # 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji # 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji # 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji # 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Emoji # 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Emoji # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Emoji # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Emoji # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Emoji # 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6CB..1F6CF ; Emoji # 7.0 [5] (🛋️..🛏️) couch and lamp..bed
+1F6D0 ; Emoji # 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji # 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6E0..1F6E5 ; Emoji # 7.0 [6] (🛠️..🛥️) hammer and wrench..motor boat
+1F6E9 ; Emoji # 7.0 [1] (🛩️) small airplane
+1F6EB..1F6EC ; Emoji # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F0 ; Emoji # 7.0 [1] (🛰️) satellite
+1F6F3 ; Emoji # 7.0 [1] (🛳️) passenger ship
+1F6F4..1F6F6 ; Emoji # 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji # 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji # 11.0 [1] (🛹) skateboard
+1F910..1F918 ; Emoji # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji # 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji # 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji # 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji # 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F940..1F945 ; Emoji # 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji # 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji # 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji # 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji # 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji # 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F973..1F976 ; Emoji # 11.0 [4] (🥳..🥶) partying face..cold face
+1F97A ; Emoji # 11.0 [1] (🥺) pleading face
+1F97C..1F97F ; Emoji # 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Emoji # 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Emoji # 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji # 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji # 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9B0..1F9B9 ; Emoji # 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9C0 ; Emoji # 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji # 11.0 [2] (🧁..🧂) cupcake..salt
+1F9D0..1F9E6 ; Emoji # 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji # 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+
+# Total elements: 1250
+
+# ================================================
+
+# All omitted code points have Emoji_Presentation=No
+# @missing: 0000..10FFFF ; Emoji_Presentation ; No
+
+231A..231B ; Emoji_Presentation # 1.1 [2] (⌚..⌛) watch..hourglass done
+23E9..23EC ; Emoji_Presentation # 6.0 [4] (⏩..⏬) fast-forward button..fast down button
+23F0 ; Emoji_Presentation # 6.0 [1] (⏰) alarm clock
+23F3 ; Emoji_Presentation # 6.0 [1] (⏳) hourglass not done
+25FD..25FE ; Emoji_Presentation # 3.2 [2] (◽..◾) white medium-small square..black medium-small square
+2614..2615 ; Emoji_Presentation # 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2648..2653 ; Emoji_Presentation # 1.1 [12] (♈..♓) Aries..Pisces
+267F ; Emoji_Presentation # 4.1 [1] (♿) wheelchair symbol
+2693 ; Emoji_Presentation # 4.1 [1] (⚓) anchor
+26A1 ; Emoji_Presentation # 4.0 [1] (⚡) high voltage
+26AA..26AB ; Emoji_Presentation # 4.1 [2] (⚪..⚫) white circle..black circle
+26BD..26BE ; Emoji_Presentation # 5.2 [2] (⚽..⚾) soccer ball..baseball
+26C4..26C5 ; Emoji_Presentation # 5.2 [2] (⛄..⛅) snowman without snow..sun behind cloud
+26CE ; Emoji_Presentation # 6.0 [1] (⛎) Ophiuchus
+26D4 ; Emoji_Presentation # 5.2 [1] (⛔) no entry
+26EA ; Emoji_Presentation # 5.2 [1] (⛪) church
+26F2..26F3 ; Emoji_Presentation # 5.2 [2] (⛲..⛳) fountain..flag in hole
+26F5 ; Emoji_Presentation # 5.2 [1] (⛵) sailboat
+26FA ; Emoji_Presentation # 5.2 [1] (⛺) tent
+26FD ; Emoji_Presentation # 5.2 [1] (⛽) fuel pump
+2705 ; Emoji_Presentation # 6.0 [1] (✅) white heavy check mark
+270A..270B ; Emoji_Presentation # 6.0 [2] (✊..✋) raised fist..raised hand
+2728 ; Emoji_Presentation # 6.0 [1] (✨) sparkles
+274C ; Emoji_Presentation # 6.0 [1] (❌) cross mark
+274E ; Emoji_Presentation # 6.0 [1] (❎) cross mark button
+2753..2755 ; Emoji_Presentation # 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Emoji_Presentation # 5.2 [1] (❗) exclamation mark
+2795..2797 ; Emoji_Presentation # 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27B0 ; Emoji_Presentation # 6.0 [1] (➰) curly loop
+27BF ; Emoji_Presentation # 6.0 [1] (➿) double curly loop
+2B1B..2B1C ; Emoji_Presentation # 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Emoji_Presentation # 5.1 [1] (⭐) star
+2B55 ; Emoji_Presentation # 5.2 [1] (⭕) heavy large circle
+1F004 ; Emoji_Presentation # 5.1 [1] (🀄) mahjong red dragon
+1F0CF ; Emoji_Presentation # 6.0 [1] (🃏) joker
+1F18E ; Emoji_Presentation # 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Emoji_Presentation # 6.0 [10] (🆑..🆚) CL button..VS button
+1F1E6..1F1FF ; Emoji_Presentation # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F201 ; Emoji_Presentation # 6.0 [1] (🈁) Japanese “here” button
+1F21A ; Emoji_Presentation # 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Emoji_Presentation # 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F236 ; Emoji_Presentation # 6.0 [5] (🈲..🈶) Japanese “prohibited” button..Japanese “not free of charge” button
+1F238..1F23A ; Emoji_Presentation # 6.0 [3] (🈸..🈺) Japanese “application” button..Japanese “open for business” button
+1F250..1F251 ; Emoji_Presentation # 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F300..1F320 ; Emoji_Presentation # 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F32D..1F32F ; Emoji_Presentation # 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Emoji_Presentation # 6.0 [6] (🌰..🌵) chestnut..cactus
+1F337..1F37C ; Emoji_Presentation # 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37E..1F37F ; Emoji_Presentation # 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Emoji_Presentation # 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F3A0..1F3C4 ; Emoji_Presentation # 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Emoji_Presentation # 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Emoji_Presentation # 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CF..1F3D3 ; Emoji_Presentation # 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3E0..1F3F0 ; Emoji_Presentation # 6.0 [17] (🏠..🏰) house..castle
+1F3F4 ; Emoji_Presentation # 7.0 [1] (🏴) black flag
+1F3F8..1F3FF ; Emoji_Presentation # 8.0 [8] (🏸..🏿) badminton..dark skin tone
+1F400..1F43E ; Emoji_Presentation # 6.0 [63] (🐀..🐾) rat..paw prints
+1F440 ; Emoji_Presentation # 6.0 [1] (👀) eyes
+1F442..1F4F7 ; Emoji_Presentation # 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Emoji_Presentation # 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Emoji_Presentation # 6.0 [4] (📹..📼) video camera..videocassette
+1F4FF ; Emoji_Presentation # 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Emoji_Presentation # 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F54B..1F54E ; Emoji_Presentation # 8.0 [4] (🕋..🕎) kaaba..menorah
+1F550..1F567 ; Emoji_Presentation # 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F57A ; Emoji_Presentation # 9.0 [1] (🕺) man dancing
+1F595..1F596 ; Emoji_Presentation # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F5A4 ; Emoji_Presentation # 9.0 [1] (🖤) black heart
+1F5FB..1F5FF ; Emoji_Presentation # 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Emoji_Presentation # 6.1 [1] (😀) grinning face
+1F601..1F610 ; Emoji_Presentation # 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Emoji_Presentation # 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Emoji_Presentation # 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Emoji_Presentation # 6.1 [1] (😕) confused face
+1F616 ; Emoji_Presentation # 6.0 [1] (😖) confounded face
+1F617 ; Emoji_Presentation # 6.1 [1] (😗) kissing face
+1F618 ; Emoji_Presentation # 6.0 [1] (😘) face blowing a kiss
+1F619 ; Emoji_Presentation # 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Emoji_Presentation # 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Emoji_Presentation # 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Emoji_Presentation # 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Emoji_Presentation # 6.1 [1] (😟) worried face
+1F620..1F625 ; Emoji_Presentation # 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Emoji_Presentation # 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Emoji_Presentation # 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Emoji_Presentation # 6.1 [1] (😬) grimacing face
+1F62D ; Emoji_Presentation # 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Emoji_Presentation # 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Emoji_Presentation # 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Emoji_Presentation # 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Emoji_Presentation # 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Emoji_Presentation # 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Emoji_Presentation # 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Emoji_Presentation # 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Emoji_Presentation # 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6CC ; Emoji_Presentation # 7.0 [1] (🛌) person in bed
+1F6D0 ; Emoji_Presentation # 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Emoji_Presentation # 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6EB..1F6EC ; Emoji_Presentation # 7.0 [2] (🛫..🛬) airplane departure..airplane arrival
+1F6F4..1F6F6 ; Emoji_Presentation # 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Emoji_Presentation # 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Emoji_Presentation # 11.0 [1] (🛹) skateboard
+1F910..1F918 ; Emoji_Presentation # 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Emoji_Presentation # 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Emoji_Presentation # 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Emoji_Presentation # 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Emoji_Presentation # 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Emoji_Presentation # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Presentation # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Emoji_Presentation # 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Emoji_Presentation # 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F940..1F945 ; Emoji_Presentation # 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Emoji_Presentation # 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Emoji_Presentation # 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Emoji_Presentation # 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Emoji_Presentation # 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Emoji_Presentation # 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Emoji_Presentation # 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F973..1F976 ; Emoji_Presentation # 11.0 [4] (🥳..🥶) partying face..cold face
+1F97A ; Emoji_Presentation # 11.0 [1] (🥺) pleading face
+1F97C..1F97F ; Emoji_Presentation # 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Emoji_Presentation # 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Emoji_Presentation # 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Emoji_Presentation # 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Emoji_Presentation # 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9B0..1F9B9 ; Emoji_Presentation # 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9C0 ; Emoji_Presentation # 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Emoji_Presentation # 11.0 [2] (🧁..🧂) cupcake..salt
+1F9D0..1F9E6 ; Emoji_Presentation # 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Emoji_Presentation # 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+
+# Total elements: 1032
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier=No
+# @missing: 0000..10FFFF ; Emoji_Modifier ; No
+
+1F3FB..1F3FF ; Emoji_Modifier # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone
+
+# Total elements: 5
+
+# ================================================
+
+# All omitted code points have Emoji_Modifier_Base=No
+# @missing: 0000..10FFFF ; Emoji_Modifier_Base ; No
+
+261D ; Emoji_Modifier_Base # 1.1 [1] (☝️) index pointing up
+26F9 ; Emoji_Modifier_Base # 5.2 [1] (⛹️) person bouncing ball
+270A..270B ; Emoji_Modifier_Base # 6.0 [2] (✊..✋) raised fist..raised hand
+270C..270D ; Emoji_Modifier_Base # 1.1 [2] (✌️..✍️) victory hand..writing hand
+1F385 ; Emoji_Modifier_Base # 6.0 [1] (🎅) Santa Claus
+1F3C2..1F3C4 ; Emoji_Modifier_Base # 6.0 [3] (🏂..🏄) snowboarder..person surfing
+1F3C7 ; Emoji_Modifier_Base # 6.0 [1] (🏇) horse racing
+1F3CA ; Emoji_Modifier_Base # 6.0 [1] (🏊) person swimming
+1F3CB..1F3CC ; Emoji_Modifier_Base # 7.0 [2] (🏋️..🏌️) person lifting weights..person golfing
+1F442..1F443 ; Emoji_Modifier_Base # 6.0 [2] (👂..👃) ear..nose
+1F446..1F450 ; Emoji_Modifier_Base # 6.0 [11] (👆..👐) backhand index pointing up..open hands
+1F466..1F469 ; Emoji_Modifier_Base # 6.0 [4] (👦..👩) boy..woman
+1F46E ; Emoji_Modifier_Base # 6.0 [1] (👮) police officer
+1F470..1F478 ; Emoji_Modifier_Base # 6.0 [9] (👰..👸) bride with veil..princess
+1F47C ; Emoji_Modifier_Base # 6.0 [1] (👼) baby angel
+1F481..1F483 ; Emoji_Modifier_Base # 6.0 [3] (💁..💃) person tipping hand..woman dancing
+1F485..1F487 ; Emoji_Modifier_Base # 6.0 [3] (💅..💇) nail polish..person getting haircut
+1F4AA ; Emoji_Modifier_Base # 6.0 [1] (💪) flexed biceps
+1F574..1F575 ; Emoji_Modifier_Base # 7.0 [2] (🕴️..🕵️) man in suit levitating..detective
+1F57A ; Emoji_Modifier_Base # 9.0 [1] (🕺) man dancing
+1F590 ; Emoji_Modifier_Base # 7.0 [1] (🖐️) hand with fingers splayed
+1F595..1F596 ; Emoji_Modifier_Base # 7.0 [2] (🖕..🖖) middle finger..vulcan salute
+1F645..1F647 ; Emoji_Modifier_Base # 6.0 [3] (🙅..🙇) person gesturing NO..person bowing
+1F64B..1F64F ; Emoji_Modifier_Base # 6.0 [5] (🙋..🙏) person raising hand..folded hands
+1F6A3 ; Emoji_Modifier_Base # 6.0 [1] (🚣) person rowing boat
+1F6B4..1F6B6 ; Emoji_Modifier_Base # 6.0 [3] (🚴..🚶) person biking..person walking
+1F6C0 ; Emoji_Modifier_Base # 6.0 [1] (🛀) person taking bath
+1F6CC ; Emoji_Modifier_Base # 7.0 [1] (🛌) person in bed
+1F918 ; Emoji_Modifier_Base # 8.0 [1] (🤘) sign of the horns
+1F919..1F91C ; Emoji_Modifier_Base # 9.0 [4] (🤙..🤜) call me hand..right-facing fist
+1F91E ; Emoji_Modifier_Base # 9.0 [1] (🤞) crossed fingers
+1F91F ; Emoji_Modifier_Base # 10.0 [1] (🤟) love-you gesture
+1F926 ; Emoji_Modifier_Base # 9.0 [1] (🤦) person facepalming
+1F930 ; Emoji_Modifier_Base # 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Emoji_Modifier_Base # 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F939 ; Emoji_Modifier_Base # 9.0 [7] (🤳..🤹) selfie..person juggling
+1F93D..1F93E ; Emoji_Modifier_Base # 9.0 [2] (🤽..🤾) person playing water polo..person playing handball
+1F9B5..1F9B6 ; Emoji_Modifier_Base # 11.0 [2] (🦵..🦶) leg..foot
+1F9B8..1F9B9 ; Emoji_Modifier_Base # 11.0 [2] (🦸..🦹) superhero..supervillain
+1F9D1..1F9DD ; Emoji_Modifier_Base # 10.0 [13] (🧑..🧝) adult..elf
+
+# Total elements: 106
+
+# ================================================
+
+# All omitted code points have Emoji_Component=No
+# @missing: 0000..10FFFF ; Emoji_Component ; No
+
+0023 ; Emoji_Component # 1.1 [1] (#️) number sign
+002A ; Emoji_Component # 1.1 [1] (*️) asterisk
+0030..0039 ; Emoji_Component # 1.1 [10] (0️..9️) digit zero..digit nine
+200D ; Emoji_Component # 1.1 [1] (‍) zero width joiner
+20E3 ; Emoji_Component # 3.0 [1] (⃣) combining enclosing keycap
+FE0F ; Emoji_Component # 3.2 [1] () VARIATION SELECTOR-16
+1F1E6..1F1FF ; Emoji_Component # 6.0 [26] (🇦..🇿) regional indicator symbol letter a..regional indicator symbol letter z
+1F3FB..1F3FF ; Emoji_Component # 8.0 [5] (🏻..🏿) light skin tone..dark skin tone
+1F9B0..1F9B3 ; Emoji_Component # 11.0 [4] (🦰..🦳) red-haired..white-haired
+E0020..E007F ; Emoji_Component # 3.1 [96] (󠀠..󠁿) tag space..cancel tag
+
+# Total elements: 146
+
+# ================================================
+
+# All omitted code points have Extended_Pictographic=No
+# @missing: 0000..10FFFF ; Extended_Pictographic ; No
+
+00A9 ; Extended_Pictographic# 1.1 [1] (©️) copyright
+00AE ; Extended_Pictographic# 1.1 [1] (®️) registered
+203C ; Extended_Pictographic# 1.1 [1] (‼️) double exclamation mark
+2049 ; Extended_Pictographic# 3.0 [1] (⁉️) exclamation question mark
+2122 ; Extended_Pictographic# 1.1 [1] (™️) trade mark
+2139 ; Extended_Pictographic# 3.0 [1] (ℹ️) information
+2194..2199 ; Extended_Pictographic# 1.1 [6] (↔️..↙️) left-right arrow..down-left arrow
+21A9..21AA ; Extended_Pictographic# 1.1 [2] (↩️..↪️) right arrow curving left..left arrow curving right
+231A..231B ; Extended_Pictographic# 1.1 [2] (⌚..⌛) watch..hourglass done
+2328 ; Extended_Pictographic# 1.1 [1] (⌨️) keyboard
+2388 ; Extended_Pictographic# 3.0 [1] (⎈️) HELM SYMBOL
+23CF ; Extended_Pictographic# 4.0 [1] (⏏️) eject button
+23E9..23F3 ; Extended_Pictographic# 6.0 [11] (⏩..⏳) fast-forward button..hourglass not done
+23F8..23FA ; Extended_Pictographic# 7.0 [3] (⏸️..⏺️) pause button..record button
+24C2 ; Extended_Pictographic# 1.1 [1] (Ⓜ️) circled M
+25AA..25AB ; Extended_Pictographic# 1.1 [2] (▪️..▫️) black small square..white small square
+25B6 ; Extended_Pictographic# 1.1 [1] (▶️) play button
+25C0 ; Extended_Pictographic# 1.1 [1] (◀️) reverse button
+25FB..25FE ; Extended_Pictographic# 3.2 [4] (◻️..◾) white medium square..black medium-small square
+2600..2605 ; Extended_Pictographic# 1.1 [6] (☀️..★️) sun..BLACK STAR
+2607..2612 ; Extended_Pictographic# 1.1 [12] (☇️..☒️) LIGHTNING..BALLOT BOX WITH X
+2614..2615 ; Extended_Pictographic# 4.0 [2] (☔..☕) umbrella with rain drops..hot beverage
+2616..2617 ; Extended_Pictographic# 3.2 [2] (☖️..☗️) WHITE SHOGI PIECE..BLACK SHOGI PIECE
+2618 ; Extended_Pictographic# 4.1 [1] (☘️) shamrock
+2619 ; Extended_Pictographic# 3.0 [1] (☙️) REVERSED ROTATED FLORAL HEART BULLET
+261A..266F ; Extended_Pictographic# 1.1 [86] (☚️..♯️) BLACK LEFT POINTING INDEX..MUSIC SHARP SIGN
+2670..2671 ; Extended_Pictographic# 3.0 [2] (♰️..♱️) WEST SYRIAC CROSS..EAST SYRIAC CROSS
+2672..267D ; Extended_Pictographic# 3.2 [12] (♲️..♽️) UNIVERSAL RECYCLING SYMBOL..PARTIALLY-RECYCLED PAPER SYMBOL
+267E..267F ; Extended_Pictographic# 4.1 [2] (♾️..♿) infinity..wheelchair symbol
+2680..2685 ; Extended_Pictographic# 3.2 [6] (⚀️..⚅️) DIE FACE-1..DIE FACE-6
+2690..2691 ; Extended_Pictographic# 4.0 [2] (⚐️..⚑️) WHITE FLAG..BLACK FLAG
+2692..269C ; Extended_Pictographic# 4.1 [11] (⚒️..⚜️) hammer and pick..fleur-de-lis
+269D ; Extended_Pictographic# 5.1 [1] (⚝️) OUTLINED WHITE STAR
+269E..269F ; Extended_Pictographic# 5.2 [2] (⚞️..⚟️) THREE LINES CONVERGING RIGHT..THREE LINES CONVERGING LEFT
+26A0..26A1 ; Extended_Pictographic# 4.0 [2] (⚠️..⚡) warning..high voltage
+26A2..26B1 ; Extended_Pictographic# 4.1 [16] (⚢️..⚱️) DOUBLED FEMALE SIGN..funeral urn
+26B2 ; Extended_Pictographic# 5.0 [1] (⚲️) NEUTER
+26B3..26BC ; Extended_Pictographic# 5.1 [10] (⚳️..⚼️) CERES..SESQUIQUADRATE
+26BD..26BF ; Extended_Pictographic# 5.2 [3] (⚽..⚿️) soccer ball..SQUARED KEY
+26C0..26C3 ; Extended_Pictographic# 5.1 [4] (⛀️..⛃️) WHITE DRAUGHTS MAN..BLACK DRAUGHTS KING
+26C4..26CD ; Extended_Pictographic# 5.2 [10] (⛄..⛍️) snowman without snow..DISABLED CAR
+26CE ; Extended_Pictographic# 6.0 [1] (⛎) Ophiuchus
+26CF..26E1 ; Extended_Pictographic# 5.2 [19] (⛏️..⛡️) pick..RESTRICTED LEFT ENTRY-2
+26E2 ; Extended_Pictographic# 6.0 [1] (⛢️) ASTRONOMICAL SYMBOL FOR URANUS
+26E3 ; Extended_Pictographic# 5.2 [1] (⛣️) HEAVY CIRCLE WITH STROKE AND TWO DOTS ABOVE
+26E4..26E7 ; Extended_Pictographic# 6.0 [4] (⛤️..⛧️) PENTAGRAM..INVERTED PENTAGRAM
+26E8..26FF ; Extended_Pictographic# 5.2 [24] (⛨️..⛿️) BLACK CROSS ON SHIELD..WHITE FLAG WITH HORIZONTAL MIDDLE BLACK STRIPE
+2700 ; Extended_Pictographic# 7.0 [1] (✀️) BLACK SAFETY SCISSORS
+2701..2704 ; Extended_Pictographic# 1.1 [4] (✁️..✄️) UPPER BLADE SCISSORS..WHITE SCISSORS
+2705 ; Extended_Pictographic# 6.0 [1] (✅) white heavy check mark
+2708..2709 ; Extended_Pictographic# 1.1 [2] (✈️..✉️) airplane..envelope
+270A..270B ; Extended_Pictographic# 6.0 [2] (✊..✋) raised fist..raised hand
+270C..2712 ; Extended_Pictographic# 1.1 [7] (✌️..✒️) victory hand..black nib
+2714 ; Extended_Pictographic# 1.1 [1] (✔️) heavy check mark
+2716 ; Extended_Pictographic# 1.1 [1] (✖️) heavy multiplication x
+271D ; Extended_Pictographic# 1.1 [1] (✝️) latin cross
+2721 ; Extended_Pictographic# 1.1 [1] (✡️) star of David
+2728 ; Extended_Pictographic# 6.0 [1] (✨) sparkles
+2733..2734 ; Extended_Pictographic# 1.1 [2] (✳️..✴️) eight-spoked asterisk..eight-pointed star
+2744 ; Extended_Pictographic# 1.1 [1] (❄️) snowflake
+2747 ; Extended_Pictographic# 1.1 [1] (❇️) sparkle
+274C ; Extended_Pictographic# 6.0 [1] (❌) cross mark
+274E ; Extended_Pictographic# 6.0 [1] (❎) cross mark button
+2753..2755 ; Extended_Pictographic# 6.0 [3] (❓..❕) question mark..white exclamation mark
+2757 ; Extended_Pictographic# 5.2 [1] (❗) exclamation mark
+2763..2767 ; Extended_Pictographic# 1.1 [5] (❣️..❧️) heavy heart exclamation..ROTATED FLORAL HEART BULLET
+2795..2797 ; Extended_Pictographic# 6.0 [3] (➕..➗) heavy plus sign..heavy division sign
+27A1 ; Extended_Pictographic# 1.1 [1] (➡️) right arrow
+27B0 ; Extended_Pictographic# 6.0 [1] (➰) curly loop
+27BF ; Extended_Pictographic# 6.0 [1] (➿) double curly loop
+2934..2935 ; Extended_Pictographic# 3.2 [2] (⤴️..⤵️) right arrow curving up..right arrow curving down
+2B05..2B07 ; Extended_Pictographic# 4.0 [3] (⬅️..⬇️) left arrow..down arrow
+2B1B..2B1C ; Extended_Pictographic# 5.1 [2] (⬛..⬜) black large square..white large square
+2B50 ; Extended_Pictographic# 5.1 [1] (⭐) star
+2B55 ; Extended_Pictographic# 5.2 [1] (⭕) heavy large circle
+3030 ; Extended_Pictographic# 1.1 [1] (〰️) wavy dash
+303D ; Extended_Pictographic# 3.2 [1] (〽️) part alternation mark
+3297 ; Extended_Pictographic# 1.1 [1] (㊗️) Japanese “congratulations” button
+3299 ; Extended_Pictographic# 1.1 [1] (㊙️) Japanese “secret” button
+1F000..1F02B ; Extended_Pictographic# 5.1 [44] (🀀️..🀫️) MAHJONG TILE EAST WIND..MAHJONG TILE BACK
+1F02C..1F02F ; Extended_Pictographic# NA [4] (🀬️..🀯️) <reserved-1F02C>..<reserved-1F02F>
+1F030..1F093 ; Extended_Pictographic# 5.1[100] (🀰️..🂓️) DOMINO TILE HORIZONTAL BACK..DOMINO TILE VERTICAL-06-06
+1F094..1F09F ; Extended_Pictographic# NA [12] (🂔️..🂟️) <reserved-1F094>..<reserved-1F09F>
+1F0A0..1F0AE ; Extended_Pictographic# 6.0 [15] (🂠️..🂮️) PLAYING CARD BACK..PLAYING CARD KING OF SPADES
+1F0AF..1F0B0 ; Extended_Pictographic# NA [2] (🂯️..🂰️) <reserved-1F0AF>..<reserved-1F0B0>
+1F0B1..1F0BE ; Extended_Pictographic# 6.0 [14] (🂱️..🂾️) PLAYING CARD ACE OF HEARTS..PLAYING CARD KING OF HEARTS
+1F0BF ; Extended_Pictographic# 7.0 [1] (🂿️) PLAYING CARD RED JOKER
+1F0C0 ; Extended_Pictographic# NA [1] (🃀️) <reserved-1F0C0>
+1F0C1..1F0CF ; Extended_Pictographic# 6.0 [15] (🃁️..🃏) PLAYING CARD ACE OF DIAMONDS..joker
+1F0D0 ; Extended_Pictographic# NA [1] (🃐️) <reserved-1F0D0>
+1F0D1..1F0DF ; Extended_Pictographic# 6.0 [15] (🃑️..🃟️) PLAYING CARD ACE OF CLUBS..PLAYING CARD WHITE JOKER
+1F0E0..1F0F5 ; Extended_Pictographic# 7.0 [22] (🃠️..🃵️) PLAYING CARD FOOL..PLAYING CARD TRUMP-21
+1F0F6..1F0FF ; Extended_Pictographic# NA [10] (🃶️..🃿️) <reserved-1F0F6>..<reserved-1F0FF>
+1F10D..1F10F ; Extended_Pictographic# NA [3] (🄍️..🄏️) <reserved-1F10D>..<reserved-1F10F>
+1F12F ; Extended_Pictographic# 11.0 [1] (🄯️) COPYLEFT SYMBOL
+1F16C..1F16F ; Extended_Pictographic# NA [4] (🅬️..🅯️) <reserved-1F16C>..<reserved-1F16F>
+1F170..1F171 ; Extended_Pictographic# 6.0 [2] (🅰️..🅱️) A button (blood type)..B button (blood type)
+1F17E ; Extended_Pictographic# 6.0 [1] (🅾️) O button (blood type)
+1F17F ; Extended_Pictographic# 5.2 [1] (🅿️) P button
+1F18E ; Extended_Pictographic# 6.0 [1] (🆎) AB button (blood type)
+1F191..1F19A ; Extended_Pictographic# 6.0 [10] (🆑..🆚) CL button..VS button
+1F1AD..1F1E5 ; Extended_Pictographic# NA [57] (🆭️..🇥️) <reserved-1F1AD>..<reserved-1F1E5>
+1F201..1F202 ; Extended_Pictographic# 6.0 [2] (🈁..🈂️) Japanese “here” button..Japanese “service charge” button
+1F203..1F20F ; Extended_Pictographic# NA [13] (🈃️..🈏️) <reserved-1F203>..<reserved-1F20F>
+1F21A ; Extended_Pictographic# 5.2 [1] (🈚) Japanese “free of charge” button
+1F22F ; Extended_Pictographic# 5.2 [1] (🈯) Japanese “reserved” button
+1F232..1F23A ; Extended_Pictographic# 6.0 [9] (🈲..🈺) Japanese “prohibited” button..Japanese “open for business” button
+1F23C..1F23F ; Extended_Pictographic# NA [4] (🈼️..🈿️) <reserved-1F23C>..<reserved-1F23F>
+1F249..1F24F ; Extended_Pictographic# NA [7] (🉉️..🉏️) <reserved-1F249>..<reserved-1F24F>
+1F250..1F251 ; Extended_Pictographic# 6.0 [2] (🉐..🉑) Japanese “bargain” button..Japanese “acceptable” button
+1F252..1F25F ; Extended_Pictographic# NA [14] (🉒️..🉟️) <reserved-1F252>..<reserved-1F25F>
+1F260..1F265 ; Extended_Pictographic# 10.0 [6] (🉠️..🉥️) ROUNDED SYMBOL FOR FU..ROUNDED SYMBOL FOR CAI
+1F266..1F2FF ; Extended_Pictographic# NA[154] (🉦️..🋿️) <reserved-1F266>..<reserved-1F2FF>
+1F300..1F320 ; Extended_Pictographic# 6.0 [33] (🌀..🌠) cyclone..shooting star
+1F321..1F32C ; Extended_Pictographic# 7.0 [12] (🌡️..🌬️) thermometer..wind face
+1F32D..1F32F ; Extended_Pictographic# 8.0 [3] (🌭..🌯) hot dog..burrito
+1F330..1F335 ; Extended_Pictographic# 6.0 [6] (🌰..🌵) chestnut..cactus
+1F336 ; Extended_Pictographic# 7.0 [1] (🌶️) hot pepper
+1F337..1F37C ; Extended_Pictographic# 6.0 [70] (🌷..🍼) tulip..baby bottle
+1F37D ; Extended_Pictographic# 7.0 [1] (🍽️) fork and knife with plate
+1F37E..1F37F ; Extended_Pictographic# 8.0 [2] (🍾..🍿) bottle with popping cork..popcorn
+1F380..1F393 ; Extended_Pictographic# 6.0 [20] (🎀..🎓) ribbon..graduation cap
+1F394..1F39F ; Extended_Pictographic# 7.0 [12] (🎔️..🎟️) HEART WITH TIP ON THE LEFT..admission tickets
+1F3A0..1F3C4 ; Extended_Pictographic# 6.0 [37] (🎠..🏄) carousel horse..person surfing
+1F3C5 ; Extended_Pictographic# 7.0 [1] (🏅) sports medal
+1F3C6..1F3CA ; Extended_Pictographic# 6.0 [5] (🏆..🏊) trophy..person swimming
+1F3CB..1F3CE ; Extended_Pictographic# 7.0 [4] (🏋️..🏎️) person lifting weights..racing car
+1F3CF..1F3D3 ; Extended_Pictographic# 8.0 [5] (🏏..🏓) cricket game..ping pong
+1F3D4..1F3DF ; Extended_Pictographic# 7.0 [12] (🏔️..🏟️) snow-capped mountain..stadium
+1F3E0..1F3F0 ; Extended_Pictographic# 6.0 [17] (🏠..🏰) house..castle
+1F3F1..1F3F7 ; Extended_Pictographic# 7.0 [7] (🏱️..🏷️) WHITE PENNANT..label
+1F3F8..1F3FA ; Extended_Pictographic# 8.0 [3] (🏸..🏺) badminton..amphora
+1F400..1F43E ; Extended_Pictographic# 6.0 [63] (🐀..🐾) rat..paw prints
+1F43F ; Extended_Pictographic# 7.0 [1] (🐿️) chipmunk
+1F440 ; Extended_Pictographic# 6.0 [1] (👀) eyes
+1F441 ; Extended_Pictographic# 7.0 [1] (👁️) eye
+1F442..1F4F7 ; Extended_Pictographic# 6.0[182] (👂..📷) ear..camera
+1F4F8 ; Extended_Pictographic# 7.0 [1] (📸) camera with flash
+1F4F9..1F4FC ; Extended_Pictographic# 6.0 [4] (📹..📼) video camera..videocassette
+1F4FD..1F4FE ; Extended_Pictographic# 7.0 [2] (📽️..📾️) film projector..PORTABLE STEREO
+1F4FF ; Extended_Pictographic# 8.0 [1] (📿) prayer beads
+1F500..1F53D ; Extended_Pictographic# 6.0 [62] (🔀..🔽) shuffle tracks button..downwards button
+1F546..1F54A ; Extended_Pictographic# 7.0 [5] (🕆️..🕊️) WHITE LATIN CROSS..dove
+1F54B..1F54F ; Extended_Pictographic# 8.0 [5] (🕋..🕏️) kaaba..BOWL OF HYGIEIA
+1F550..1F567 ; Extended_Pictographic# 6.0 [24] (🕐..🕧) one o’clock..twelve-thirty
+1F568..1F579 ; Extended_Pictographic# 7.0 [18] (🕨️..🕹️) RIGHT SPEAKER..joystick
+1F57A ; Extended_Pictographic# 9.0 [1] (🕺) man dancing
+1F57B..1F5A3 ; Extended_Pictographic# 7.0 [41] (🕻️..🖣️) LEFT HAND TELEPHONE RECEIVER..BLACK DOWN POINTING BACKHAND INDEX
+1F5A4 ; Extended_Pictographic# 9.0 [1] (🖤) black heart
+1F5A5..1F5FA ; Extended_Pictographic# 7.0 [86] (🖥️..🗺️) desktop computer..world map
+1F5FB..1F5FF ; Extended_Pictographic# 6.0 [5] (🗻..🗿) mount fuji..moai
+1F600 ; Extended_Pictographic# 6.1 [1] (😀) grinning face
+1F601..1F610 ; Extended_Pictographic# 6.0 [16] (😁..😐) beaming face with smiling eyes..neutral face
+1F611 ; Extended_Pictographic# 6.1 [1] (😑) expressionless face
+1F612..1F614 ; Extended_Pictographic# 6.0 [3] (😒..😔) unamused face..pensive face
+1F615 ; Extended_Pictographic# 6.1 [1] (😕) confused face
+1F616 ; Extended_Pictographic# 6.0 [1] (😖) confounded face
+1F617 ; Extended_Pictographic# 6.1 [1] (😗) kissing face
+1F618 ; Extended_Pictographic# 6.0 [1] (😘) face blowing a kiss
+1F619 ; Extended_Pictographic# 6.1 [1] (😙) kissing face with smiling eyes
+1F61A ; Extended_Pictographic# 6.0 [1] (😚) kissing face with closed eyes
+1F61B ; Extended_Pictographic# 6.1 [1] (😛) face with tongue
+1F61C..1F61E ; Extended_Pictographic# 6.0 [3] (😜..😞) winking face with tongue..disappointed face
+1F61F ; Extended_Pictographic# 6.1 [1] (😟) worried face
+1F620..1F625 ; Extended_Pictographic# 6.0 [6] (😠..😥) angry face..sad but relieved face
+1F626..1F627 ; Extended_Pictographic# 6.1 [2] (😦..😧) frowning face with open mouth..anguished face
+1F628..1F62B ; Extended_Pictographic# 6.0 [4] (😨..😫) fearful face..tired face
+1F62C ; Extended_Pictographic# 6.1 [1] (😬) grimacing face
+1F62D ; Extended_Pictographic# 6.0 [1] (😭) loudly crying face
+1F62E..1F62F ; Extended_Pictographic# 6.1 [2] (😮..😯) face with open mouth..hushed face
+1F630..1F633 ; Extended_Pictographic# 6.0 [4] (😰..😳) anxious face with sweat..flushed face
+1F634 ; Extended_Pictographic# 6.1 [1] (😴) sleeping face
+1F635..1F640 ; Extended_Pictographic# 6.0 [12] (😵..🙀) dizzy face..weary cat face
+1F641..1F642 ; Extended_Pictographic# 7.0 [2] (🙁..🙂) slightly frowning face..slightly smiling face
+1F643..1F644 ; Extended_Pictographic# 8.0 [2] (🙃..🙄) upside-down face..face with rolling eyes
+1F645..1F64F ; Extended_Pictographic# 6.0 [11] (🙅..🙏) person gesturing NO..folded hands
+1F680..1F6C5 ; Extended_Pictographic# 6.0 [70] (🚀..🛅) rocket..left luggage
+1F6C6..1F6CF ; Extended_Pictographic# 7.0 [10] (🛆️..🛏️) TRIANGLE WITH ROUNDED CORNERS..bed
+1F6D0 ; Extended_Pictographic# 8.0 [1] (🛐) place of worship
+1F6D1..1F6D2 ; Extended_Pictographic# 9.0 [2] (🛑..🛒) stop sign..shopping cart
+1F6D3..1F6D4 ; Extended_Pictographic# 10.0 [2] (🛓️..🛔️) STUPA..PAGODA
+1F6D5..1F6DF ; Extended_Pictographic# NA [11] (🛕️..🛟️) <reserved-1F6D5>..<reserved-1F6DF>
+1F6E0..1F6EC ; Extended_Pictographic# 7.0 [13] (🛠️..🛬) hammer and wrench..airplane arrival
+1F6ED..1F6EF ; Extended_Pictographic# NA [3] (🛭️..🛯️) <reserved-1F6ED>..<reserved-1F6EF>
+1F6F0..1F6F3 ; Extended_Pictographic# 7.0 [4] (🛰️..🛳️) satellite..passenger ship
+1F6F4..1F6F6 ; Extended_Pictographic# 9.0 [3] (🛴..🛶) kick scooter..canoe
+1F6F7..1F6F8 ; Extended_Pictographic# 10.0 [2] (🛷..🛸) sled..flying saucer
+1F6F9 ; Extended_Pictographic# 11.0 [1] (🛹) skateboard
+1F6FA..1F6FF ; Extended_Pictographic# NA [6] (🛺️..🛿️) <reserved-1F6FA>..<reserved-1F6FF>
+1F774..1F77F ; Extended_Pictographic# NA [12] (🝴️..🝿️) <reserved-1F774>..<reserved-1F77F>
+1F7D5..1F7D8 ; Extended_Pictographic# 11.0 [4] (🟕️..🟘️) CIRCLED TRIANGLE..NEGATIVE CIRCLED SQUARE
+1F7D9..1F7FF ; Extended_Pictographic# NA [39] (🟙️..🟿️) <reserved-1F7D9>..<reserved-1F7FF>
+1F80C..1F80F ; Extended_Pictographic# NA [4] (🠌️..🠏️) <reserved-1F80C>..<reserved-1F80F>
+1F848..1F84F ; Extended_Pictographic# NA [8] (🡈️..🡏️) <reserved-1F848>..<reserved-1F84F>
+1F85A..1F85F ; Extended_Pictographic# NA [6] (🡚️..🡟️) <reserved-1F85A>..<reserved-1F85F>
+1F888..1F88F ; Extended_Pictographic# NA [8] (🢈️..🢏️) <reserved-1F888>..<reserved-1F88F>
+1F8AE..1F8FF ; Extended_Pictographic# NA [82] (🢮️..🣿️) <reserved-1F8AE>..<reserved-1F8FF>
+1F90C..1F90F ; Extended_Pictographic# NA [4] (🤌️..🤏️) <reserved-1F90C>..<reserved-1F90F>
+1F910..1F918 ; Extended_Pictographic# 8.0 [9] (🤐..🤘) zipper-mouth face..sign of the horns
+1F919..1F91E ; Extended_Pictographic# 9.0 [6] (🤙..🤞) call me hand..crossed fingers
+1F91F ; Extended_Pictographic# 10.0 [1] (🤟) love-you gesture
+1F920..1F927 ; Extended_Pictographic# 9.0 [8] (🤠..🤧) cowboy hat face..sneezing face
+1F928..1F92F ; Extended_Pictographic# 10.0 [8] (🤨..🤯) face with raised eyebrow..exploding head
+1F930 ; Extended_Pictographic# 9.0 [1] (🤰) pregnant woman
+1F931..1F932 ; Extended_Pictographic# 10.0 [2] (🤱..🤲) breast-feeding..palms up together
+1F933..1F93A ; Extended_Pictographic# 9.0 [8] (🤳..🤺) selfie..person fencing
+1F93C..1F93E ; Extended_Pictographic# 9.0 [3] (🤼..🤾) people wrestling..person playing handball
+1F93F ; Extended_Pictographic# NA [1] (🤿️) <reserved-1F93F>
+1F940..1F945 ; Extended_Pictographic# 9.0 [6] (🥀..🥅) wilted flower..goal net
+1F947..1F94B ; Extended_Pictographic# 9.0 [5] (🥇..🥋) 1st place medal..martial arts uniform
+1F94C ; Extended_Pictographic# 10.0 [1] (🥌) curling stone
+1F94D..1F94F ; Extended_Pictographic# 11.0 [3] (🥍..🥏) lacrosse..flying disc
+1F950..1F95E ; Extended_Pictographic# 9.0 [15] (🥐..🥞) croissant..pancakes
+1F95F..1F96B ; Extended_Pictographic# 10.0 [13] (🥟..🥫) dumpling..canned food
+1F96C..1F970 ; Extended_Pictographic# 11.0 [5] (🥬..🥰) leafy green..smiling face with 3 hearts
+1F971..1F972 ; Extended_Pictographic# NA [2] (🥱️..🥲️) <reserved-1F971>..<reserved-1F972>
+1F973..1F976 ; Extended_Pictographic# 11.0 [4] (🥳..🥶) partying face..cold face
+1F977..1F979 ; Extended_Pictographic# NA [3] (🥷️..🥹️) <reserved-1F977>..<reserved-1F979>
+1F97A ; Extended_Pictographic# 11.0 [1] (🥺) pleading face
+1F97B ; Extended_Pictographic# NA [1] (🥻️) <reserved-1F97B>
+1F97C..1F97F ; Extended_Pictographic# 11.0 [4] (🥼..🥿) lab coat..woman’s flat shoe
+1F980..1F984 ; Extended_Pictographic# 8.0 [5] (🦀..🦄) crab..unicorn face
+1F985..1F991 ; Extended_Pictographic# 9.0 [13] (🦅..🦑) eagle..squid
+1F992..1F997 ; Extended_Pictographic# 10.0 [6] (🦒..🦗) giraffe..cricket
+1F998..1F9A2 ; Extended_Pictographic# 11.0 [11] (🦘..🦢) kangaroo..swan
+1F9A3..1F9AF ; Extended_Pictographic# NA [13] (🦣️..🦯️) <reserved-1F9A3>..<reserved-1F9AF>
+1F9B0..1F9B9 ; Extended_Pictographic# 11.0 [10] (🦰..🦹) red-haired..supervillain
+1F9BA..1F9BF ; Extended_Pictographic# NA [6] (🦺️..🦿️) <reserved-1F9BA>..<reserved-1F9BF>
+1F9C0 ; Extended_Pictographic# 8.0 [1] (🧀) cheese wedge
+1F9C1..1F9C2 ; Extended_Pictographic# 11.0 [2] (🧁..🧂) cupcake..salt
+1F9C3..1F9CF ; Extended_Pictographic# NA [13] (🧃️..🧏️) <reserved-1F9C3>..<reserved-1F9CF>
+1F9D0..1F9E6 ; Extended_Pictographic# 10.0 [23] (🧐..🧦) face with monocle..socks
+1F9E7..1F9FF ; Extended_Pictographic# 11.0 [25] (🧧..🧿) red envelope..nazar amulet
+1FA00..1FA5F ; Extended_Pictographic# NA [96] (🨀️..🩟️) <reserved-1FA00>..<reserved-1FA5F>
+1FA60..1FA6D ; Extended_Pictographic# 11.0 [14] (🩠️..🩭️) XIANGQI RED GENERAL..XIANGQI BLACK SOLDIER
+1FA6E..1FFFD ; Extended_Pictographic# NA[1424] (🩮️..🿽️) <reserved-1FA6E>..<reserved-1FFFD>
+
+# Total elements: 3793
+
+#EOF
diff --git a/lib/stdlib/uc_spec/gen_unicode_mod.escript b/lib/stdlib/uc_spec/gen_unicode_mod.escript
index fe5a860d45..70eec1a6f2 100755
--- a/lib/stdlib/uc_spec/gen_unicode_mod.escript
+++ b/lib/stdlib/uc_spec/gen_unicode_mod.escript
@@ -48,13 +48,18 @@ main(_) ->
ok = file:close(ExclF),
%% GraphemeBreakProperty table
+ {ok, Emoji} = file:open("../uc_spec/emoji-data.txt", [read, raw, {read_ahead, 1000000}]),
+ Props00 = foldl(fun parse_properties/2, [], Emoji),
+ %% Filter Extended_Pictographic class which we are interested in.
+ Props0 = [EP || {extended_pictographic, _} = EP <- Props00],
+ ok = file:close(Emoji),
{ok, GBPF} = file:open("../uc_spec/GraphemeBreakProperty.txt", [read, raw, {read_ahead, 1000000}]),
- Props0 = foldl(fun parse_properties/2, [], GBPF),
+ Props1 = foldl(fun parse_properties/2, Props0, GBPF),
ok = file:close(GBPF),
{ok, PropF} = file:open("../uc_spec/PropList.txt", [read, raw, {read_ahead, 1000000}]),
- Props1 = foldl(fun parse_properties/2, Props0, PropF),
+ Props2 = foldl(fun parse_properties/2, Props1, PropF),
ok = file:close(PropF),
- Props = sofs:to_external(sofs:relation_to_family(sofs:relation(Props1))),
+ Props = sofs:to_external(sofs:relation_to_family(sofs:relation(Props2))),
%% Make module
{ok, Out} = file:open(?MOD++".erl", [write]),
@@ -170,7 +175,7 @@ gen_header(Fd) ->
io:put_chars(Fd, "-export([spec_version/0, lookup/1, get_case/1]).\n"),
io:put_chars(Fd, "-inline([class/1]).\n"),
io:put_chars(Fd, "-compile(nowarn_unused_vars).\n"),
- io:put_chars(Fd, "-dialyzer({no_improper_lists, [cp/1, gc/1, gc_prepend/2, gc_e_cont/2]}).\n"),
+ io:put_chars(Fd, "-dialyzer({no_improper_lists, [cp/1, gc/1, gc_prepend/2]}).\n"),
io:put_chars(Fd, "-type gc() :: char()|[char()].\n\n\n"),
ok.
@@ -186,7 +191,7 @@ gen_static(Fd) ->
" {U,L} -> #{upper=>U,lower=>L,title=>U,fold=>L};\n"
" {U,L,T,F} -> #{upper=>U,lower=>L,title=>T,fold=>F}\n"
" end.\n\n"),
- io:put_chars(Fd, "spec_version() -> {10,0}.\n\n\n"),
+ io:put_chars(Fd, "spec_version() -> {11,0}.\n\n\n"),
io:put_chars(Fd, "class(Codepoint) -> {CCC,_,_} = unicode_table(Codepoint),\n CCC.\n\n"),
io:put_chars(Fd, "-spec uppercase(unicode:chardata()) -> "
"maybe_improper_list(gc(),unicode:chardata()).\n"),
@@ -495,33 +500,34 @@ gen_gc(Fd, GBP) ->
" [$\\n|R1] -> [[$\\r,$\\n]|R1];\n"
" _ -> R\n"
" end;\n"
- %% "gc_1([CP1, CP2|_]=T) when CP1 < 256, CP2 < 256 ->\n"
- %% " T; %% Fast path\n"
- %% "gc_1([CP1|<<CP2/utf8, _/binary>>]=T) when CP1 < 256, CP2 < 256 ->\n"
- %% " T; %% Fast path\n"
),
- io:put_chars(Fd, "%% Handle control\n"),
+ GenExtP = fun(Range) -> io:format(Fd, "gc_1~s gc_ext_pict(R1,[CP]);\n", [gen_clause(Range)]) end,
+ ExtendedPictographic0 = merge_ranges(maps:get(extended_pictographic,GBP)),
+ %% Pick codepoints below 256 (some data knowledge here)
+ {ExtendedPictographicLow,ExtendedPictographicHigh} =
+ lists:splitwith(fun({Start,undefined}) -> Start < 256 end,ExtendedPictographic0),
+
+ io:put_chars(Fd, "\n%% Handle control\n"),
GenControl = fun(Range) -> io:format(Fd, "gc_1~s R0;\n", [gen_clause(Range)]) end,
CRs0 = merge_ranges(maps:get(cr, GBP) ++ maps:get(lf, GBP) ++ maps:get(control, GBP), false),
[R1,R2,R3|Crs] = CRs0,
[GenControl(CP) || CP <- merge_ranges([R1,R2,R3], split), CP =/= {$\r, undefined}],
%%GenControl(R1),GenControl(R2),GenControl(R3),
- io:format(Fd, "gc_1([CP|R]) when CP < 256 -> gc_extend(R,CP);\n", []),
+ io:put_chars(Fd, "\n%% Optimize Latin-1\n"),
+ [GenExtP(CP) || CP <- merge_ranges(ExtendedPictographicLow)],
+ io:format(Fd, "gc_1([CP|R]) when CP < 256 -> gc_extend(R,CP);\n\n", []),
+ io:put_chars(Fd, "\n%% Continue control\n"),
[GenControl(CP) || CP <- Crs],
%% One clause per CP
%% CRs0 = merge_ranges(maps:get(cr, GBP) ++ maps:get(lf, GBP) ++ maps:get(control, GBP)),
%% [GenControl(CP) || CP <- CRs0, CP =/= {$\r, undefined}],
- io:put_chars(Fd, "%% Handle ZWJ\n"),
- GenZWJ = fun(Range) -> io:format(Fd, "gc_1~s gc_zwj(R1, [CP]);\n", [gen_clause(Range)]) end,
- [GenZWJ(CP) || CP <- merge_ranges(maps:get(zwj,GBP))],
-
- io:put_chars(Fd, "%% Handle prepend\n"),
+ io:put_chars(Fd, "\n%% Handle prepend\n"),
GenPrepend = fun(Range) -> io:format(Fd, "gc_1~s gc_prepend(R1, CP);\n", [gen_clause(Range)]) end,
[GenPrepend(CP) || CP <- merge_ranges(maps:get(prepend,GBP))],
- io:put_chars(Fd, "%% Handle Hangul L\n"),
+ io:put_chars(Fd, "\n%% Handle Hangul L\n"),
GenHangulL = fun(Range) -> io:format(Fd, "gc_1~s gc_h_L(R1,[CP]);\n", [gen_clause(Range)]) end,
[GenHangulL(CP) || CP <- merge_ranges(maps:get(l,GBP))],
io:put_chars(Fd, "%% Handle Hangul V\n"),
@@ -533,16 +539,19 @@ gen_gc(Fd, GBP) ->
io:put_chars(Fd, "%% Handle Hangul LV and LVT special, since they are large\n"),
io:put_chars(Fd, "gc_1([CP|_]=R0) when 44000 < CP, CP < 56000 -> gc_h_lv_lvt(R0, []);\n"),
- io:put_chars(Fd, "%% Handle Regional\n"),
+ io:put_chars(Fd, "\n%% Handle Regional\n"),
GenRegional = fun(Range) -> io:format(Fd, "gc_1~s gc_regional(R1,[CP]);\n", [gen_clause(Range)]) end,
[GenRegional(CP) || CP <- merge_ranges(maps:get(regional_indicator,GBP))],
- io:put_chars(Fd, "%% Handle E_Base\n"),
- GenEBase = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
- [GenEBase(CP) || CP <- merge_ranges(maps:get(e_base,GBP))],
- io:put_chars(Fd, "%% Handle EBG\n"),
- GenEBG = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
- [GenEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
-
+ %% io:put_chars(Fd, "%% Handle E_Base\n"),
+ %% GenEBase = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
+ %% [GenEBase(CP) || CP <- merge_ranges(maps:get(e_base,GBP))],
+ %% io:put_chars(Fd, "%% Handle EBG\n"),
+ %% GenEBG = fun(Range) -> io:format(Fd, "gc_1~s gc_e_cont(R1,[CP]);\n", [gen_clause(Range)]) end,
+ %% [GenEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
+
+ io:put_chars(Fd, "%% Handle extended_pictographic\n"),
+ [GenExtP(CP) || CP <- merge_ranges(ExtendedPictographicHigh)],
+ io:put_chars(Fd, "\n%% default clauses\n"),
io:put_chars(Fd, "gc_1([CP|R]) -> gc_extend(R, CP);\n"),
io:put_chars(Fd, "gc_1([]) -> [];\n"),
io:put_chars(Fd, "gc_1({error,_}=Error) -> Error.\n\n"),
@@ -577,21 +586,16 @@ gen_gc(Fd, GBP) ->
io:put_chars(Fd,
"gc_extend([CP|T], T0, Acc0) ->\n"
" case is_extend(CP) of\n"
- " zwj ->\n"
- " case Acc0 of\n"
- " [_|_] -> gc_zwj(T, [CP|Acc0]);\n"
- " Acc -> gc_zwj(T, [CP,Acc])\n"
- " end;\n"
- " true ->\n"
- " case Acc0 of\n"
- " [_|_] -> gc_extend(T, [CP|Acc0]);\n"
- " Acc -> gc_extend(T, [CP,Acc])\n"
- " end;\n"
" false ->\n"
" case Acc0 of\n"
" [Acc] -> [Acc|T0];\n"
" [_|_]=Acc -> [lists:reverse(Acc)|T0];\n"
" Acc -> [Acc|T0]\n"
+ " end;\n"
+ " _TrueOrZWJ ->\n"
+ " case Acc0 of\n"
+ " [_|_] -> gc_extend(T, [CP|Acc0]);\n"
+ " Acc -> gc_extend(T, [CP,Acc])\n"
" end\n"
" end;\n"
"gc_extend([], _, Acc0) ->\n"
@@ -612,49 +616,46 @@ gen_gc(Fd, GBP) ->
io:put_chars(Fd, "is_extend(_) -> false.\n\n"),
io:put_chars(Fd,
- "gc_e_cont(R0, Acc) ->\n"
- " case cp(R0) of\n"
- " [CP|R1] ->\n"
- " case is_extend(CP) of\n"
- " zwj -> gc_zwj(R1, [CP|Acc]);\n"
- " true -> gc_e_cont(R1, [CP|Acc]);\n"
- " false ->\n"
- " case is_emodifier(CP) of\n"
- " true -> [lists:reverse([CP|Acc])|R1];\n"
- " false ->\n"
- " case Acc of\n"
- " [A] -> [A|R0];\n"
- " _ -> [lists:reverse(Acc)|R0]\n"
- " end\n"
- " end\n"
- " end;\n"
- " [] ->\n"
+ "gc_ext_pict(T, Acc) ->\n"
+ " gc_ext_pict(cp(T), T, Acc).\n\n"
+ "gc_ext_pict([CP|R1], T0, Acc) ->\n"
+ " case is_extend(CP) of\n"
+ " zwj -> gc_ext_pict_zwj(cp(R1), R1, [CP|Acc]);\n"
+ " true -> gc_ext_pict(R1, [CP|Acc]);\n"
+ " false ->\n"
" case Acc of\n"
- " [A] -> [A];\n"
- " _ -> [lists:reverse(Acc)]\n"
- " end;\n"
- " {error,R} ->\n"
+ " [A] -> [A|T0];\n"
+ " _ -> [lists:reverse(Acc)|T0]\n"
+ " end\n"
+ " end;\n"
+ "gc_ext_pict([], _T0, Acc) ->\n"
+ " case Acc of\n"
+ " [A] -> [A];\n"
+ " _ -> [lists:reverse(Acc)]\n"
+ " end;\n"
+ "gc_ext_pict({error,R}, T, Acc) ->\n"
+ " gc_ext_pict([], T, Acc) ++ [R].\n\n"),
+ io:put_chars(Fd,
+ "gc_ext_pict_zwj([CP|R1], T0, Acc) ->\n"
+ " case is_ext_pict(CP) of\n"
+ " true -> gc_ext_pict(R1, [CP|Acc]);\n"
+ " false ->\n"
" case Acc of\n"
- " [A] -> [A|R];\n"
- " _ -> [lists:reverse(Acc)|R]\n"
+ " [A] -> [A|T0];\n"
+ " _ -> [lists:reverse(Acc)|T0]\n"
" end\n"
- " end.\n\n"),
-
- GenEMod = fun(Range) -> io:format(Fd, "is_emodifier~s true;\n", [gen_single_clause(Range)]) end,
- EMods = merge_ranges(maps:get(e_modifier, GBP), split),
- [GenEMod(CP) || CP <- EMods],
- io:put_chars(Fd, "is_emodifier(_) -> false.\n\n"),
-
- io:put_chars(Fd, "gc_zwj(R0, Acc) ->\n case cp(R0) of\n"),
- GenZWJGlue = fun(Range) -> io:format(Fd, "~8c~s gc_extend(R1, R0, [CP|Acc]);\n",
- [$\s,gen_case_clause(Range)]) end,
- [GenZWJGlue(CP) || CP <- merge_ranges(maps:get(glue_after_zwj,GBP))],
- GenZWJEBG = fun(Range) -> io:format(Fd, "~8c~s gc_e_cont(R1, [CP|Acc]);\n",
- [$\s,gen_case_clause(Range)]) end,
- [GenZWJEBG(CP) || CP <- merge_ranges(maps:get(e_base_gaz,GBP))],
- io:put_chars(Fd," R1 -> gc_extend(R1, R0, Acc)\n"
- " end.\n\n"),
+ " end;\n"
+ "gc_ext_pict_zwj([], _, Acc) ->\n"
+ " case Acc of\n"
+ " [A] -> [A];\n"
+ " _ -> [lists:reverse(Acc)]\n"
+ " end;\n"
+ "gc_ext_pict_zwj({error,R}, T, Acc) ->\n"
+ " gc_ext_pict_zwj([], T, Acc) ++ [R].\n\n"),
+ GenExtPict = fun(Range) -> io:format(Fd, "is_ext_pict~s true;\n", [gen_single_clause(Range)]) end,
+ [GenExtPict(CP) || CP <- ExtendedPictographic0],
+ io:put_chars(Fd, "is_ext_pict(_) -> false.\n\n"),
%% --------------------
io:put_chars(Fd, "%% Handle Regional\n"),
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 1d833430f1..caf5ecdbb4 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.5.1
+STDLIB_VSN = 3.6
diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml
index 76c2d6ecbd..dc13fe474b 100644
--- a/lib/syntax_tools/doc/src/notes.xml
+++ b/lib/syntax_tools/doc/src/notes.xml
@@ -32,6 +32,44 @@
<p>This document describes the changes made to the Syntax_Tools
application.</p>
+<section><title>Syntax_Tools 2.1.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the <c>TypeName</c> type in erl_syntax_lib.</p>
+ <p>
+ Own Id: OTP-15207 Aux Id: PR-1888 </p>
+ </item>
+ <item>
+ <p> Correct unfolding of the stacktrace variable. </p>
+ <p>
+ Own Id: OTP-15291 Aux Id: ERL-719 </p>
+ </item>
+ <item>
+ <p> Correct <c>erl_syntax:revert/1</c> bug regarding the
+ types <c>map()</c> and <c>tuple()</c>. </p>
+ <p>
+ Own Id: OTP-15294</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p> Support bitstrings as literals in module
+ <c>erl_syntax</c>. </p>
+ <p>
+ Own Id: OTP-15165 Aux Id: PR-1842 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.1.5</title>
<section><title>Improvements and New Features</title>
<list>
@@ -108,6 +146,20 @@
</section>
+<section><title>Syntax_Tools 2.1.1.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p> Fix a bug regarding reverting map types. </p>
+ <p>
+ Own Id: OTP-15098 Aux Id: ERIERL-177 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Syntax_Tools 2.1.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 758aff32fd..1be644c620 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -3897,7 +3897,7 @@ unfold_try_clauses(Cs) ->
unfold_try_clause({clause, Pos, [{tuple, _, [{atom, _, throw},
V,
- [{var, _, '_'}]]}],
+ {var, _, '_'}]}],
Guard, Body}) ->
{clause, Pos, [V], Guard, Body};
unfold_try_clause({clause, Pos, [{tuple, _, [C, V, Stacktrace]}],
@@ -5455,8 +5455,12 @@ map_type(Fields) ->
revert_map_type(Node) ->
Pos = get_pos(Node),
- {type, Pos, map, map_type_fields(Node)}.
-
+ case map_type_fields(Node) of
+ any_size ->
+ {type, Pos, map, any};
+ Fields ->
+ {type, Pos, map, Fields}
+ end.
%% =====================================================================
%% @doc Returns the list of field subtrees of a `map_type' node.
@@ -5714,7 +5718,12 @@ tuple_type(Elements) ->
revert_tuple_type(Node) ->
Pos = get_pos(Node),
- {type, Pos, tuple, tuple_type_elements(Node)}.
+ case tuple_type_elements(Node) of
+ any_size ->
+ {type, Pos, tuple, any};
+ TypeElements ->
+ {type, Pos, tuple, TypeElements}
+ end.
%% =====================================================================
diff --git a/lib/syntax_tools/src/erl_syntax_lib.erl b/lib/syntax_tools/src/erl_syntax_lib.erl
index ced0dba3e2..352165893f 100644
--- a/lib/syntax_tools/src/erl_syntax_lib.erl
+++ b/lib/syntax_tools/src/erl_syntax_lib.erl
@@ -1981,7 +1981,7 @@ analyze_application(Node) ->
%%
%% @see analyze_type_name/1
--type typeName() :: atom() | {module(), atom(), arity()} | {atom(), arity()}.
+-type typeName() :: atom() | {module(), {atom(), arity()}} | {atom(), arity()}.
-spec analyze_type_application(erl_syntax:syntaxTree()) -> typeName().
diff --git a/lib/syntax_tools/src/igor.erl b/lib/syntax_tools/src/igor.erl
index 16e3511734..b712b77e9f 100644
--- a/lib/syntax_tools/src/igor.erl
+++ b/lib/syntax_tools/src/igor.erl
@@ -660,7 +660,7 @@ merge_files1(Files, Opts) ->
%% transitions), code replacement is expected to be detected. Then, if
%% we in the merged code do not check at these points if the
%% <em>target</em> module (the result of the merge) has been replaced,
-%% we can not be sure in general that we will be able to do code
+%% we cannot be sure in general that we will be able to do code
%% replacement of the merged state machine - it could run forever
%% without detecting the code change. Therefore, all such calls must
%% remain remote-calls (detecting code changes), but may call the target
diff --git a/lib/syntax_tools/test/merl_SUITE.erl b/lib/syntax_tools/test/merl_SUITE.erl
index 52bbd9b3b8..6389ad7738 100644
--- a/lib/syntax_tools/test/merl_SUITE.erl
+++ b/lib/syntax_tools/test/merl_SUITE.erl
@@ -30,13 +30,14 @@
%% Test cases
-export([merl_smoke_test/1,
- transform_parse_error_test/1]).
+ transform_parse_error_test/1, otp_15291/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[merl_smoke_test,
- transform_parse_error_test].
+ transform_parse_error_test,
+ otp_15291].
groups() ->
[].
@@ -101,6 +102,15 @@ transform_parse_error_test(_Config) ->
[?Q("merl:qquote(2, \"{\", [{var, V}])")], []))),
ok.
+otp_15291(_Config) ->
+ C0 = merl:quote("() -> ok"),
+ {clause,1,[],[],[{atom,1,ok}]} = C0,
+ C2 = merl:quote("(_,_) -> ok"),
+ {clause,1,[{var,1,'_'},{var,1,'_'}],[],[{atom,1,ok}]} = C2,
+ C1 = merl:quote("(_) -> ok"),
+ {clause,1,[{var,1,'_'}],[],[{atom,1,ok}]} = C1,
+ ok.
+
%% utilities
f(Ts) when is_list(Ts) ->
diff --git a/lib/syntax_tools/test/syntax_tools_SUITE.erl b/lib/syntax_tools/test/syntax_tools_SUITE.erl
index 4cddf8f0c3..9dbd0e302a 100644
--- a/lib/syntax_tools/test/syntax_tools_SUITE.erl
+++ b/lib/syntax_tools/test/syntax_tools_SUITE.erl
@@ -25,14 +25,14 @@
%% Test cases
-export([app_test/1,appup_test/1,smoke_test/1,revert/1,revert_map/1,
revert_map_type/1,
- t_abstract_type/1,t_erl_parse_type/1,t_epp_dodger/1,
+ t_abstract_type/1,t_erl_parse_type/1,t_type/1, t_epp_dodger/1,
t_comment_scan/1,t_igor/1,t_erl_tidy/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app_test,appup_test,smoke_test,revert,revert_map,revert_map_type,
- t_abstract_type,t_erl_parse_type,t_epp_dodger,
+ t_abstract_type,t_erl_parse_type,t_type,t_epp_dodger,
t_comment_scan,t_igor,t_erl_tidy].
groups() ->
@@ -145,6 +145,74 @@ revert_map_type(Config) when is_list(Config) ->
%% api tests
+t_type(Config) when is_list(Config) ->
+ F0 = fun validate_basic_type/1,
+ Appl0 = fun(Name) ->
+ Atom = erl_syntax:atom(Name),
+ erl_syntax:type_application(none, Atom, [])
+ end,
+ User0 = fun(Name) ->
+ Atom = erl_syntax:atom(Name),
+ erl_syntax:user_type_application(Atom, [])
+ end,
+ ok = validate(F0,[{"tuple()", erl_syntax:tuple_type()}
+ ,{"{}", erl_syntax:tuple_type([])}
+ ,{"integer()", Appl0(integer)}
+ ,{"foo()", User0(foo)}
+ ,{"map()", erl_syntax:map_type()}
+ ,{"#{}", erl_syntax:map_type([])}
+ ,{"1..2", erl_syntax:integer_range_type
+ (erl_syntax:integer(1), erl_syntax:integer(2))}
+ ,{"<<_:1,_:_*2>>", erl_syntax:bitstring_type
+ (erl_syntax:integer(1), erl_syntax:integer(2))}
+ ,{"fun()", erl_syntax:fun_type()}
+ ]),
+
+ F = fun validate_type/1,
+ ok = validate(F,[{"{}", tuple_type, false}
+ ,{"tuple()", tuple_type, true}
+ ,{"{atom()}", tuple_type, false}
+ ,{"{atom(),integer()}", tuple_type, false}
+ ,{"integer()", type_application, false}
+ ,{"foo()", user_type_application, false}
+ ,{"foo(integer())", user_type_application, false}
+ ,{"module:function()", type_application, false}
+ ,{"map()", map_type, true}
+ ,{"#{}", map_type, false}
+ ,{"#{atom() => integer()}", map_type, false}
+ ,{"#{atom() := integer()}", map_type, false}
+ ,{"#r{}", record_type, false}
+ ,{"#r{a :: integer()}", record_type, false}
+ ,{"[]", type_application, false}
+ ,{"nil()", type_application, false}
+ ,{"[atom()]", type_application, false}
+ ,{"1..2", integer_range_type, false}
+ ,{"<<_:1,_:_*2>>", bitstring_type, false}
+ ,{"fun()", fun_type, true}
+ ,{"integer() | atom()", type_union, false}
+ ,{"A :: fun()", annotated_type, false}
+ ,{"fun((...) -> atom())", function_type, false}
+ ,{"fun((integer()) -> atom())", function_type, false}
+ ,{"V", variable, true}
+ ]),
+ ok.
+
+validate_basic_type({String, Tree}) ->
+ ErlT = string_to_type(String),
+ ErlT = erl_syntax:revert(Tree),
+ ok.
+
+validate_type({String, Type, Leaf}) ->
+ ErlT = string_to_type(String),
+ Type = erl_syntax:type(ErlT),
+ Leaf = erl_syntax:is_leaf(ErlT),
+ Tree = erl_syntax_lib:map(fun(Node) -> Node end, ErlT),
+ Type = erl_syntax:type(Tree),
+ _ = erl_syntax:meta(Tree),
+ RevT = erl_syntax:revert(Tree),
+ Type = erl_syntax:type(RevT),
+ ok.
+
t_abstract_type(Config) when is_list(Config) ->
F = fun validate_abstract_type/1,
ok = validate(F,[{hi,atom},
@@ -451,6 +519,13 @@ string_to_expr(String) ->
{ok,[Expr]} = erl_parse:parse_exprs(Ts),
Expr.
+string_to_type(String) ->
+ io:format("Str: ~p~n", [String]),
+ {ok,Ts,_} = erl_scan:string("-type foo() :: "++String++".", 0),
+ {ok,Form} = erl_parse:parse_form(Ts),
+ {attribute,_,type,{foo,Type,_NoParms=[]}} = Form,
+ Type.
+
p_run(Test, List) ->
N = erlang:system_info(schedulers),
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 4d13267f16..8959ebbd04 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 2.1.5
+SYNTAX_TOOLS_VSN = 2.1.6
diff --git a/lib/tftp/doc/src/notes.xml b/lib/tftp/doc/src/notes.xml
index 3a4d97a008..ff6113a89d 100644
--- a/lib/tftp/doc/src/notes.xml
+++ b/lib/tftp/doc/src/notes.xml
@@ -33,7 +33,22 @@
<file>notes.xml</file>
</header>
- <section><title>TFTP 1.0</title>
+ <section><title>Tftp 1.0.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>TFTP 1.0</title>
<section><title>First released version</title>
<list>
diff --git a/lib/tftp/doc/src/tftp.xml b/lib/tftp/doc/src/tftp.xml
index 481e5446ad..4ed54bc462 100644
--- a/lib/tftp/doc/src/tftp.xml
+++ b/lib/tftp/doc/src/tftp.xml
@@ -150,7 +150,7 @@
<tag><c>{logger, Module}</c></tag>
<item>
- <p><c>Module = module()()</c></p>
+ <p><c>Module = module()</c></p>
<p>Callback module for customized logging of errors, warnings, and
info messages. The callback module must implement the
@@ -220,7 +220,7 @@
<name>info(daemons) -> [{Pid, Options}]</name>
<fsummary>Returns information about all daemons.</fsummary>
<type>
- <v>Pid = [pid()()]</v>
+ <v>Pid = [pid()]</v>
<v>Options = [option()]</v>
<v>Reason = term()</v>
</type>
@@ -233,7 +233,7 @@
<name>info(servers) -> [{Pid, Options}]</name>
<fsummary>Returns information about all servers.</fsummary>
<type>
- <v>Pid = [pid()()]</v>
+ <v>Pid = [pid()]</v>
<v>Options = [option()]</v>
<v>Reason = term()</v>
</type>
diff --git a/lib/tftp/src/tftp.app.src b/lib/tftp/src/tftp.app.src
index 2a87d39ada..9e79fe32bf 100644
--- a/lib/tftp/src/tftp.app.src
+++ b/lib/tftp/src/tftp.app.src
@@ -1,6 +1,6 @@
{application, tftp,
[{description, "TFTP application"},
- {vsn, "1.0"},
+ {vsn, "%VSN%"},
{registered, []},
{mod, { tftp_app, []}},
{applications,
diff --git a/lib/tftp/vsn.mk b/lib/tftp/vsn.mk
index f1b0851a8f..1a547fbe9b 100644
--- a/lib/tftp/vsn.mk
+++ b/lib/tftp/vsn.mk
@@ -19,6 +19,6 @@
# %CopyrightEnd%
APPLICATION = tftp
-TFTP_VSN = 1.0
+TFTP_VSN = 1.0.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(TFTP_VSN)$(PRE_VSN)"
diff --git a/lib/tools/doc/src/cover.xml b/lib/tools/doc/src/cover.xml
index 15cd784253..6c6b20aad8 100644
--- a/lib/tools/doc/src/cover.xml
+++ b/lib/tools/doc/src/cover.xml
@@ -234,7 +234,7 @@
<c>{already_cover_compiled,no_beam_found,Module}</c> is
returned.</p>
<p><c>{error,BeamFile}</c> is returned if the compiled code
- can not be loaded on the node.</p>
+ cannot be loaded on the node.</p>
<p>If a list of <c>ModFiles</c> is given as input, a list
of <c>Result</c> will be returned. The order of the returned
list is undefined.</p>
@@ -470,7 +470,7 @@
<p>Exports the current coverage data for <c>Module</c> to the
file <c>ExportFile</c>. It is recommended to name the
<c>ExportFile</c> with the extension <c>.coverdata</c>, since
- other filenames can not be read by the web based interface to
+ other filenames cannot be read by the web based interface to
cover.</p>
<p>If <c>Module</c> is not given, data for all Cover compiled
or earlier imported modules is exported.</p>
@@ -496,7 +496,7 @@
<p>Coverage data from several export files can be imported
into one system. The coverage data is then added up when
analysing.</p>
- <p>Coverage data for a module can not be imported from the
+ <p>Coverage data for a module cannot be imported from the
same file twice unless the module is first reset or
compiled. The check is based on the filename, so you can
easily fool the system by renaming your export file.</p>
diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml
index 8b0a2ca283..f10953774f 100644
--- a/lib/tools/doc/src/notes.xml
+++ b/lib/tools/doc/src/notes.xml
@@ -31,6 +31,28 @@
</header>
<p>This document describes the changes made to the Tools application.</p>
+<section><title>Tools 3.0.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ The HTML pages generated by cover:analyse_to_file/1 and
+ related functions is improved for readability.</p>
+ <p>
+ Own Id: OTP-15213 Aux Id: PR-1807 </p>
+ </item>
+ <item>
+ <p>
+ Add alignment functionality in emacs.</p>
+ <p>
+ Own Id: OTP-15239 Aux Id: PR-1728 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Tools 3.0</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile
index ea4d6cb723..b7775d1c8c 100644
--- a/lib/tools/emacs/Makefile
+++ b/lib/tools/emacs/Makefile
@@ -46,6 +46,7 @@ EMACS_FILES= \
erlang-eunit \
erlang-edoc \
erlang-flymake \
+ erlang-test \
erlang
README_FILES= README
diff --git a/lib/tools/emacs/erlang-edoc.el b/lib/tools/emacs/erlang-edoc.el
index d0dcc81028..ea1e263faf 100644
--- a/lib/tools/emacs/erlang-edoc.el
+++ b/lib/tools/emacs/erlang-edoc.el
@@ -28,6 +28,7 @@
(defcustom erlang-edoc-indent-level 2
"Indentation level of xhtml in Erlang edoc."
+ :type '(integer)
:safe 'integerp
:group 'erlang)
diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el
index 38c40927f4..53543d7b01 100644
--- a/lib/tools/emacs/erlang-eunit.el
+++ b/lib/tools/emacs/erlang-eunit.el
@@ -23,6 +23,7 @@
(eval-when-compile
(require 'cl))
+(require 'erlang)
(defvar erlang-eunit-src-candidate-dirs '("../src" ".")
"*Name of directories which to search for source files matching
@@ -331,8 +332,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
t)
(apply test-fun test-args)
(if under-cover
- (save-excursion
- (set-buffer (find-file-noselect src-filename))
+ (with-current-buffer (find-file-noselect src-filename)
(erlang-eunit-analyze-coverage)))))))
(defun erlang-eunit-compile-and-run-module-tests-under-cover ()
@@ -348,8 +348,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
(defun erlang-eunit-compile-file (file-path &optional under-cover)
(if (file-readable-p file-path)
- (save-excursion
- (set-buffer (find-file-noselect file-path))
+ (with-current-buffer (find-file-noselect file-path)
;; In order to run a code coverage analysis on a
;; module, we have two options:
;;
@@ -376,8 +375,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set."
(error msg))))
(defun erlang-eunit-last-compilation-successful-p ()
- (save-excursion
- (set-buffer inferior-erlang-buffer)
+ (with-current-buffer inferior-erlang-buffer
(goto-char compilation-parsing-end)
(erlang-eunit-all-list-elems-fulfill-p
(lambda (re) (let ((continue t)
diff --git a/lib/tools/emacs/erlang-pkg.el b/lib/tools/emacs/erlang-pkg.el
index 02d6bebbf4..7e95e4050e 100644
--- a/lib/tools/emacs/erlang-pkg.el
+++ b/lib/tools/emacs/erlang-pkg.el
@@ -1,3 +1,6 @@
(define-package "erlang" "2.7.0"
"Erlang major mode"
'((emacs "24.1")))
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
diff --git a/lib/tools/emacs/erlang-skels.el b/lib/tools/emacs/erlang-skels.el
index 534f50ab33..3ebc6e8e1e 100644
--- a/lib/tools/emacs/erlang-skels.el
+++ b/lib/tools/emacs/erlang-skels.el
@@ -1985,7 +1985,7 @@ configured off."
The first character of DD is space if the value is less than 10."
(let ((date (current-time-string)))
(format "%2d %s %s"
- (string-to-int (substring date 8 10))
+ (string-to-number (substring date 8 10))
(substring date 4 7)
(substring date -4))))
diff --git a/lib/tools/emacs/erlang-test.el b/lib/tools/emacs/erlang-test.el
index efe3d515e9..2ee584d11a 100644
--- a/lib/tools/emacs/erlang-test.el
+++ b/lib/tools/emacs/erlang-test.el
@@ -29,7 +29,7 @@
;; This library require GNU Emacs 25 or later.
;;
-;; There are two ways to run emacs unit tests.
+;; There are three ways to run the erlang emacs unit tests.
;;
;; 1. Within a running emacs process. Load this file. Then to run
;; all defined test cases:
@@ -49,11 +49,15 @@
;;
;; The -L option adds a directory to the load-path. It should be the
;; directory containing erlang.el and erlang-test.el.
+;;
+;; 3. Call the script test-erlang-mode in this directory. This script
+;; use the second method.
;;; Code:
+(eval-when-compile
+ (require 'cl))
(require 'ert)
-(require 'cl-lib)
(require 'erlang)
(defvar erlang-test-code
@@ -63,7 +67,7 @@
("SYMBOL" . "-define(SYMBOL, value).")
("MACRO" . "-define(MACRO(X), X + X).")
("struct" . "-record(struct, {until,maps,are,everywhere}).")
- ("function". "function() -> #struct{}."))
+ ("function" . "function() -> #struct{}."))
"Alist of erlang test code.
Each entry have the format (TAGNAME . ERLANG_CODE). If TAGNAME
is nil there is no definitions in the ERLANG_CODE. The
@@ -116,8 +120,8 @@ concatenated to form an erlang file to test on.")
(defun erlang-test-create-erlang-file (erlang-file)
(with-temp-file erlang-file
- (cl-loop for (_ . code) in erlang-test-code
- do (insert code "\n"))))
+ (loop for (_ . code) in erlang-test-code
+ do (insert code "\n"))))
(defun erlang-test-compile-tags (erlang-file tags-file)
(should (zerop (call-process "etags" nil nil nil
@@ -132,19 +136,20 @@ concatenated to form an erlang file to test on.")
(sort (erlang-expected-completion-table) #'string-lessp))))
(defun erlang-expected-completion-table ()
- (append (cl-loop for (symbol . _) in erlang-test-code
- when (stringp symbol)
- append (list symbol (concat "erlang_test:" symbol)))
+ (append (loop for (symbol . _) in erlang-test-code
+ when (stringp symbol)
+ append (list symbol (concat "erlang_test:" symbol)))
(list "erlang_test:" "erlang_test:module_info")))
(defun erlang-test-xref-find-definitions (erlang-file erlang-buffer)
- (cl-loop for (tagname . code) in erlang-test-code
- for line = 1 then (1+ line)
- do (when tagname
- (switch-to-buffer erlang-buffer)
- (erlang-test-xref-jump tagname erlang-file line)
- (erlang-test-xref-jump (concat "erlang_test:" tagname)
- erlang-file line)))
+ (loop for (tagname . code) in erlang-test-code
+ for line = 1 then (1+ line)
+ do (when tagname
+ (switch-to-buffer erlang-buffer)
+ (erlang-test-xref-jump tagname erlang-file line)
+ (when (string-equal tagname "function")
+ (erlang-test-xref-jump (concat "erlang_test:" tagname)
+ erlang-file line))))
(erlang-test-xref-jump "erlang_test:" erlang-file 1))
(defun erlang-test-xref-jump (id expected-file expected-line)
@@ -213,27 +218,27 @@ concatenated to form an erlang file to test on.")
(ert-deftest erlang-test-parse-id ()
- (cl-loop for id-string in '("fun/10"
- "qualified-function module:fun/10"
- "record reko"
- "macro _SYMBOL"
- "macro MACRO/10"
- "module modula"
- "macro"
- nil)
- for id-list in '((nil nil "fun" 10)
- (qualified-function "module" "fun" 10)
- (record nil "reko" nil)
- (macro nil "_SYMBOL" nil)
- (macro nil "MACRO" 10)
- (module nil "modula" nil)
- (nil nil "macro" nil)
- nil)
- for id-list2 = (erlang-id-to-list id-string)
- do (should (equal id-list id-list2))
- for id-string2 = (erlang-id-to-string id-list)
- do (should (equal id-string id-string2))
- collect id-list2))
+ (loop for id-string in '("fun/10"
+ "qualified-function module:fun/10"
+ "record reko"
+ "macro _SYMBOL"
+ "macro MACRO/10"
+ "module modula"
+ "macro"
+ nil)
+ for id-list in '((nil nil "fun" 10)
+ (qualified-function "module" "fun" 10)
+ (record nil "reko" nil)
+ (macro nil "_SYMBOL" nil)
+ (macro nil "MACRO" 10)
+ (module nil "modula" nil)
+ (nil nil "macro" nil)
+ nil)
+ for id-list2 = (erlang-id-to-list id-string)
+ do (should (equal id-list id-list2))
+ for id-string2 = (erlang-id-to-string id-list)
+ do (should (equal id-string id-string2))
+ collect id-list2))
(provide 'erlang-test)
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 3211132254..3cbe9daa60 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -77,6 +77,9 @@
;;; Code:
(eval-when-compile (require 'cl))
+(require 'align)
+(require 'comint)
+(require 'tempo)
;; Variables:
@@ -333,6 +336,7 @@ when a new function header is generated. When nil, no blank line is
inserted between the current line and the new header. When bound to a
number it represents the number of blank lines which should be
inserted."
+ :type '(restricted-sexp :match-alternatives (integerp 'nil))
:group 'erlang)
(defvar erlang-electric-semicolon-criteria
@@ -1405,6 +1409,19 @@ Other commands:
(add-function :before-until (local 'eldoc-documentation-function)
#'erldoc-eldoc-function))
(run-hooks 'erlang-mode-hook)
+
+ ;; Align maps.
+ (add-to-list 'align-rules-list
+ '(erlang-maps
+ (regexp . "\\(\\s-*\\)\\(=>\\)\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
+ ;; Align records and :: specs
+ (add-to-list 'align-rules-list
+ '(erlang-record-specs
+ (regexp . "\\(\\s-*\\)\\(=\\).*\\(::\\)*\\s-*")
+ (modes . '(erlang-mode))
+ (repeat . t)))
(if (zerop (buffer-size))
(run-hooks 'erlang-new-file-hook)))
@@ -1697,10 +1714,10 @@ Personal extensions could be added to `erlang-menu-personal-items'.
This function should be called if any variable describing the
menu configuration is changed."
- (erlang-menu-install "Erlang" erlang-menu-items erlang-mode-map t))
+ (erlang-menu-install "Erlang" erlang-menu-items erlang-mode-map))
-(defun erlang-menu-install (name items keymap &optional popup)
+(defun erlang-menu-install (name items keymap)
"Install a menu in Emacs based on an abstract description.
NAME is the name of the menu.
@@ -3680,16 +3697,17 @@ retried without regard to module.
4. Arity - Integer in case of functions and macros if the number
of arguments could be found, otherwise nil."
(save-excursion
- (save-match-data
- (if (eq (char-syntax (following-char)) ? )
- (skip-chars-backward " \t"))
- (skip-chars-backward "[:word:]_:'")
- (cond ((looking-at erlang-module-function-regexp)
- (erlang-get-qualified-function-id-at-point))
- ((looking-at (concat erlang-atom-regexp ":"))
- (erlang-get-module-id-at-point))
- ((looking-at erlang-name-regexp)
- (erlang-get-some-other-id-at-point))))))
+ (let (case-fold-search)
+ (save-match-data
+ (if (eq (char-syntax (following-char)) ? )
+ (skip-chars-backward " \t"))
+ (skip-chars-backward "[:word:]_:'")
+ (cond ((looking-at erlang-module-function-regexp)
+ (erlang-get-qualified-function-id-at-point))
+ ((looking-at (concat erlang-atom-regexp ":"))
+ (erlang-get-module-id-at-point))
+ ((looking-at erlang-name-regexp)
+ (erlang-get-some-other-id-at-point)))))))
(defun erlang-get-qualified-function-id-at-point ()
(let ((kind 'qualified-function)
@@ -4193,22 +4211,18 @@ Return t if criteria fulfilled, nil otherwise."
nil)))))
-(defun erlang-in-literal (&optional lim)
+(defun erlang-in-literal ()
"Test if point is in string, quoted atom or comment.
Return one of the three atoms `atom', `string', and `comment'.
Should the point be inside none of the above mentioned types of
context, nil is returned."
(save-excursion
- (let* ((lim (or lim (save-excursion
- (erlang-beginning-of-clause)
- (point))))
- (state (funcall (symbol-function 'syntax-ppss))))
- (cond
- ((eq (nth 3 state) ?') 'atom)
- ((nth 3 state) 'string)
- ((nth 4 state) 'comment)
- (t nil)))))
+ (let ((state (funcall (symbol-function 'syntax-ppss))))
+ (cond ((eq (nth 3 state) ?') 'atom)
+ ((nth 3 state) 'string)
+ ((nth 4 state) 'comment)
+ (t nil)))))
(defun erlang-at-end-of-function-p ()
@@ -5027,7 +5041,10 @@ considered first when it is time to jump to the definition.")
(defun erlang-visit-tags-table-buffer (cont cbuf)
(if (< emacs-major-version 26)
(visit-tags-table-buffer cont)
- (visit-tags-table-buffer cont cbuf)))
+ ;; Remove this with-no-warnings when Emacs 26 is the required
+ ;; version minimum.
+ (with-no-warnings
+ (visit-tags-table-buffer cont cbuf))))
(defun erlang-xref-find-definitions-module-tag (module
tag
@@ -5522,7 +5539,7 @@ Return the position after the newly inserted command."
(+ insert-point insert-length)))
-(defun inferior-erlang-strip-delete (&optional s)
+(defun inferior-erlang-strip-delete (&optional _s)
"Remove `^H' (delete) and the characters it was supposed to remove."
(interactive)
(if (and (boundp 'comint-last-input-end)
@@ -5540,7 +5557,7 @@ Return the position after the newly inserted command."
;; Basically `comint-strip-ctrl-m', with a few extra checks.
-(defun inferior-erlang-strip-ctrl-m (&optional string)
+(defun inferior-erlang-strip-ctrl-m (&optional _string)
"Strip trailing `^M' characters from the current output group."
(interactive)
(if (and (boundp 'comint-last-input-end)
@@ -5577,8 +5594,8 @@ There exists two workarounds for this bug:
(let* ((dir (inferior-erlang-compile-outdir))
(noext (substring (erlang-local-buffer-file-name) 0 -4))
(opts (append (list (cons 'outdir dir))
- (if current-prefix-arg
- (list 'debug_info 'export_all))
+ (when arg
+ (list 'debug_info 'export_all))
erlang-compile-extra-opts))
end)
(with-current-buffer inferior-erlang-buffer
@@ -5627,7 +5644,6 @@ unless the optional NO-DISPLAY is non-nil."
(defun inferior-erlang-compute-compile-command (module-name opts)
(let ((ccfn erlang-compile-command-function-alist)
- (res (inferior-erlang-compute-erl-compile-command module-name opts))
ccfn-entry
done
result)
diff --git a/lib/tools/emacs/erlang_appwiz.el b/lib/tools/emacs/erlang_appwiz.el
index ecbce66f47..b71c180739 100644
--- a/lib/tools/emacs/erlang_appwiz.el
+++ b/lib/tools/emacs/erlang_appwiz.el
@@ -103,6 +103,10 @@
;;
;;
+(defvar appwiz-erlang-modulename "foo")
+(defvar appwiz-erlang-ext "_work")
+
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Erlang application wizard
@@ -245,13 +249,6 @@ creating the root directory and for naming application files."
(insert "Application specification file for " name ".")
(save-buffer)))
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;
-;; These are setq:ed
-;;
-
-(defvar appwiz-erlang-modulename "foo")
-(defvar appwiz-erlang-ext "_work")
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
@@ -468,7 +465,7 @@ Call the function `erlang-menu-init' after modifying this variable.")
The first character of DD is *not* space if the value is less than 10."
(let ((date (current-time-string)))
(format "%d %s %s"
- (string-to-int (substring date 8 10))
+ (string-to-number (substring date 8 10))
(substring date 4 7)
(substring date -4))))
diff --git a/lib/tools/priv/styles.css b/lib/tools/priv/styles.css
new file mode 100644
index 0000000000..e10e94e3ad
--- /dev/null
+++ b/lib/tools/priv/styles.css
@@ -0,0 +1,91 @@
+body {
+ font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ color: #000;
+ border-top: 2px solid #ddd;
+ background-color: #fff;
+
+ min-height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+h1 {
+ width: 100%;
+ border-bottom: 1px solid #eee;
+ margin-bottom: 0;
+ font-weight: 100;
+ font-size: 1.1em;
+ letter-spacing: 1px;
+}
+
+h1 code {
+ font-size: 0.96em;
+}
+
+code {
+ font: 12px monospace;
+}
+
+footer {
+ background: #eee;
+ width: 100%;
+ padding: 10px 0;
+ text-align: right;
+ border-top: 1px solid #ddd;
+ display: flex;
+ flex: 1;
+ order: 2;
+ justify-content: center;
+}
+
+table {
+ width: 100%;
+ margin-top: 10px;
+ border-collapse: collapse;
+ border: 1px solid #cbcbcb;
+ color: #000;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+}
+table thead {
+ display: none;
+}
+table td.line,
+table td.hits {
+ width: 20px;
+ background: #eaeaea;
+ text-align: center;
+ font-size: 11px;
+ padding: 0 10px;
+ color: #949494;
+}
+table td.hits {
+ width: 10px;
+ padding: 2px 5px;
+ color: rgba(0, 0, 0, 0.6);
+ background-color: #f0f0f0;
+}
+tr.miss td.line,
+tr.miss td.hits {
+ background-color: #ffdce0;
+ border-color: #fdaeb7;
+}
+tr.miss td {
+ background-color: #ffeef0;
+}
+tr.hit td.line,
+tr.hit td.hits {
+ background-color: #cdffd8;
+ border-color: #bef5cb;
+}
+tr.hit td {
+ background-color: #e6ffed;
+}
+td.source {
+ padding-left: 15px;
+ line-height: 15px;
+ white-space: pre;
+ font: 12px monospace;
+}
diff --git a/lib/tools/src/Makefile b/lib/tools/src/Makefile
index 032bd612db..cc5bee9a8f 100644
--- a/lib/tools/src/Makefile
+++ b/lib/tools/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2016. All Rights Reserved.
+# Copyright Ericsson AB 1996-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -72,6 +72,9 @@ APP_TARGET = $(EBIN)/$(APP_FILE)
APPUP_SRC = $(APPUP_FILE).src
APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+PRIVDIR = ../priv
+CSS = $(PRIVDIR)/styles.css
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -110,5 +113,7 @@ release_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)/ebin"
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
"$(RELSYSDIR)/ebin"
+ $(INSTALL_DIR) "$(RELSYSDIR)/priv"
+ $(INSTALL_DATA) $(CSS) "$(RELSYSDIR)/priv"
release_docs_spec:
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index bf5faa165d..d7269e3f27 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -144,6 +144,8 @@
end).
-define(SPAWN_DBG(Tag,Value),put(Tag,Value)).
+-define(STYLESHEET, "styles.css").
+-define(TOOLS_APP, tools).
-include_lib("stdlib/include/ms_transform.hrl").
@@ -2415,20 +2417,8 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
case file:open(OutFile, [write,raw,delayed_write]) of
{ok, OutFd} ->
Enc = encoding(ErlFile),
- if HTML ->
- Header =
- ["<!DOCTYPE HTML PUBLIC "
- "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<html>\n"
- "<head>\n"
- "<meta http-equiv=\"Content-Type\""
- " content=\"text/html; charset=",
- html_encoding(Enc),"\"/>\n"
- "<title>",OutFile,"</title>\n"
- "</head>"
- "<body style='background-color: white;"
- " color: black'>\n"
- "<pre>\n"],
+ if HTML ->
+ Header = create_header(OutFile, Enc),
H1Bin = unicode:characters_to_binary(Header,Enc,Enc),
ok = file:write(OutFd,H1Bin);
true -> ok
@@ -2445,14 +2435,19 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
string:pad(integer_to_list(Mi), 2, leading, $0),
string:pad(integer_to_list(S), 2, leading, $0)]),
- H2Bin = unicode:characters_to_binary(
- ["File generated from ",ErlFile," by COVER ",
- Timestamp,"\n\n"
- "**************************************"
- "**************************************"
- "\n\n"],
- Enc, Enc),
- ok = file:write(OutFd, H2Bin),
+ OutFileInfo =
+ if HTML ->
+ create_footer(ErlFile, Timestamp);
+ true ->
+ ["File generated from ",ErlFile," by COVER ",
+ Timestamp, "\n\n",
+ "**************************************"
+ "**************************************"
+ "\n\n"]
+ end,
+
+ H2Bin = unicode:characters_to_binary(OutFileInfo,Enc,Enc),
+ ok = file:write(OutFd, H2Bin),
Pattern = {#bump{module=Module,line='$1',_='_'},'$2'},
MS = [{Pattern,[{is_integer,'$1'},{'>','$1',0}],[{{'$1','$2'}}]}],
@@ -2462,7 +2457,7 @@ do_analyse_to_file1(Module, OutFile, ErlFile, HTML) ->
print_lines(Module, CovLines, InFd, OutFd, 1, HTML),
if HTML ->
- ok = file:write(OutFd, "</pre>\n</body>\n</html>\n");
+ ok = file:write(OutFd, close_html());
true -> ok
end,
@@ -2497,12 +2492,11 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
case CovLines of
[{L,N}|CovLines1] ->
if N=:=0, HTML=:=true ->
- LineNoNL = Line -- "\n",
- Str = " 0",
- %%Str = string:pad("0", 6, leading, $\s),
- RedLine = ["<font color=red>",Str,fill1(),
- LineNoNL,"</font>\n"],
- ok = file:write(OutFd, RedLine);
+ MissedLine = table_row("miss", Line, L, N),
+ ok = file:write(OutFd, MissedLine);
+ HTML=:=true ->
+ HitLine = table_row("hit", Line, L, N),
+ ok = file:write(OutFd, HitLine);
N < 1000000 ->
Str = string:pad(integer_to_list(N), 6, leading, $\s),
ok = file:write(OutFd, [Str,fill1(),Line]);
@@ -2515,7 +2509,11 @@ print_lines(Module, CovLines, InFd, OutFd, L, HTML) ->
end,
print_lines(Module, CovLines1, InFd, OutFd, L+1, HTML);
_ -> %Including comment lines
- ok = file:write(OutFd, [tab(),Line]),
+ NonCoveredContent =
+ if HTML -> table_row(Line, L);
+ true -> [tab(),Line]
+ end,
+ ok = file:write(OutFd, NonCoveredContent),
print_lines(Module, CovLines, InFd, OutFd, L+1, HTML)
end
end.
@@ -2525,6 +2523,59 @@ fill1() -> "..| ".
fill2() -> ".| ".
fill3() -> "| ".
+%% HTML sections
+create_header(OutFile, Enc) ->
+ ["<!doctype html>\n"
+ "<html>\n"
+ "<head>\n"
+ "<meta charset=\"",html_encoding(Enc),"\">\n"
+ "<title>",OutFile,"</title>\n"
+ "<style>"] ++
+ read_stylesheet() ++
+ ["</style>\n",
+ "</head>\n"
+ "<body>\n"
+ "<h1><code>",OutFile,"</code></h1>\n"].
+
+create_footer(ErlFile, Timestamp) ->
+ ["<footer><p>File generated from <code>",ErlFile,
+ "</code> by <a href=\"http://erlang.org/doc/man/cover.html\">cover</a> at ",
+ Timestamp,"</p></footer>\n<table>\n<tbody>\n"].
+
+close_html() ->
+ ["</tbody>\n",
+ "<thead>\n",
+ "<tr>\n",
+ "<th>Line</th>\n",
+ "<th>Hits</th>\n",
+ "<th>Source</th>\n",
+ "</tr>\n",
+ "</thead>\n",
+ "</table>\n",
+ "</body>\n"
+ "</html>\n"].
+
+table_row(CssClass, Line, L, N) ->
+ ["<tr class=\"",CssClass,"\">\n", table_data(Line, L, N)].
+table_row(Line, L) ->
+ ["<tr>\n", table_data(Line, L, "")].
+
+table_data(Line, L, N) ->
+ LineNoNL = Line -- "\n",
+ ["<td class=\"line\" id=\"L",integer_to_list(L),"\">",
+ integer_to_list(L),
+ "</td>\n",
+ "<td class=\"hits\">",maybe_integer_to_list(N),"</td>\n",
+ "<td class=\"source\"><code>",LineNoNL,"</code></td>\n</tr>\n"].
+
+maybe_integer_to_list(N) when is_integer(N) -> integer_to_list(N);
+maybe_integer_to_list(_) -> "".
+
+read_stylesheet() ->
+ PrivDir = code:priv_dir(?TOOLS_APP),
+ {ok, Css} = file:read_file(filename:join(PrivDir, ?STYLESHEET)),
+ [Css].
+
%%%--Export--------------------------------------------------------------
do_export(Module, OutFile, From, State) ->
case file:open(OutFile,[write,binary,raw,delayed_write]) of
diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl
index 5839f9ce5b..a6d43d1816 100644
--- a/lib/tools/test/emacs_SUITE.erl
+++ b/lib/tools/test/emacs_SUITE.erl
@@ -23,18 +23,28 @@
-export([all/0, init_per_testcase/2, end_per_testcase/2]).
--export([bif_highlight/1, indent/1]).
+-export([bif_highlight/1,
+ load_interpreted/1, compile_and_load/1,
+ indent/1,
+ tests_interpreted/1, tests_compiled/1
+ ]).
all() ->
- [bif_highlight, indent].
+ [bif_highlight, load_interpreted, compile_and_load,
+ indent,
+ tests_interpreted, tests_compiled
+ ].
-init_per_testcase(_Case, Config) ->
+init_per_testcase(Case, Config) ->
ErlangEl = filename:join([code:lib_dir(tools),"emacs","erlang.el"]),
case file:read_file_info(ErlangEl) of
- {ok, _} ->
- [{el, ErlangEl}|Config];
- _ ->
- {skip, "Could not find erlang.el"}
+ {ok, _} ->
+ case Case =:= bif_highlight orelse emacs_version_ok(24.1) of
+ false -> {skip, "Old or no emacs found"};
+ _ -> [{el, ErlangEl}|Config]
+ end;
+ _ ->
+ {skip, "Could not find erlang.el"}
end.
end_per_testcase(_Case, _Config) ->
@@ -46,26 +56,26 @@ bif_highlight(Config) ->
%% All auto-imported bifs
IntBifs = lists:usort(
- [F || {F,A} <- erlang:module_info(exports),
- erl_internal:bif(F,A)]),
+ [F || {F,A} <- erlang:module_info(exports),
+ erl_internal:bif(F,A)]),
%% all bif which need erlang: prefix and are not operands
ExtBifs = lists:usort(
- [F || {F,A} <- erlang:module_info(exports),
- not erl_internal:bif(F,A) andalso
- not is_atom(catch erl_internal:op_type(F,A))]),
+ [F || {F,A} <- erlang:module_info(exports),
+ not erl_internal:bif(F,A) andalso
+ not is_atom(catch erl_internal:op_type(F,A))]),
check_bif_highlight(Bin, <<"erlang-int-bifs">>, IntBifs),
check_bif_highlight(Bin, <<"erlang-ext-bifs">>, ExtBifs).
-
+
check_bif_highlight(Bin, Tag, Compare) ->
- [_H,IntMatch,_T] =
- re:split(Bin,<<"defvar ",Tag/binary,
- "[^(]*\\(([^)]*)">>,[]),
- EmacsIntBifs = [list_to_atom(S) ||
- S <- string:tokens(binary_to_list(IntMatch)," '\"\n")],
-
+ [_H,IntMatch,_T] =
+ re:split(Bin,<<"defvar ",Tag/binary,
+ "[^(]*\\(([^)]*)">>,[]),
+ EmacsIntBifs = [list_to_atom(S) ||
+ S <- string:tokens(binary_to_list(IntMatch)," '\"\n")],
+
ct:log("Emacs ~p",[EmacsIntBifs]),
ct:log("Int ~p",[Compare]),
@@ -73,27 +83,92 @@ check_bif_highlight(Bin, Tag, Compare) ->
ct:log("Diff2 ~p",[EmacsIntBifs -- Compare]),
[] = Compare -- EmacsIntBifs,
[] = EmacsIntBifs -- Compare.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-indent(Config) ->
- case emacs_version_ok() of
+load_interpreted(_Config) ->
+ _ = emacs(["-l erlang.el -f erlang-mode"]),
+ ok.
+
+compile_and_load(_Config) ->
+ Dir = emacs_dir(),
+ Files0 = filelib:wildcard("*.el", Dir),
+ Files = case emacs_version_ok(24.3) of
+ %% erldoc.el depends on cl-lib which was introduced in 24.3.
+ false -> Files0 -- ["erldoc.el"];
+ _ -> Files0
+ end,
+ Unforgiving =
+ case emacs_version_ok(24) of
+ Ver when Ver < 25 ->
+ "";
+ Ver when Ver < 26 ->
+ %% Workaround byte-compile-error-on-warn which seem broken in
+ %% Emacs 25.
+ "\"(advice-add #'display-warning :after "
+ "(lambda (_ f _ _) (error \"%s\" f)))\"";
+ _ ->
+ "\"(setq byte-compile-error-on-warn t)\""
+ end,
+ %% Add files here whenever they are cleaned of warnings.
+ NoWarn = ["erlang.el", "erlang-test.el", "erlang-edoc.el", "erlang-start.el", "erldoc.el"],
+ Compile = fun(File) ->
+ Pedantic = case lists:member(File, NoWarn) andalso Unforgiving /= "" of
+ true -> ["--eval ", Unforgiving, " "];
+ false -> " "
+ end,
+ emacs([Pedantic,
+ " -f batch-byte-compile ",filename:join(Dir, File)]),
+ true
+ end,
+ lists:foreach(Compile, Files),
+ emacs(["-l erlang.elc -f erlang-mode"]),
+ ok.
+
+tests_interpreted(_Config) ->
+ case emacs_version_ok(25) of
false -> {skip, "Old or no emacs found"};
- true ->
- Def = filename:dirname(code:which(?MODULE)) ++ "/" ++ ?MODULE_STRING ++ "_data",
- Dir = proplists:get_value(data_dir, Config, Def),
- OrigFs = filelib:wildcard(Dir ++ "/*"),
- io:format("Dir: ~s~nFs: ~p~n", [Dir, OrigFs]),
- Fs = [{File, unindent(File)} || File <- OrigFs,
- filename:extension(File) =:= ""],
- Indent = fun emacs/1,
- [Indent(File) || {_, File} <- Fs],
- Res = [diff(Orig, File) || {Orig, File} <- Fs],
- [file:delete(File) || {ok, File} <- Res], %% Cleanup
- [] = [Fail || {fail, Fail} <- Res],
+ _ ->
+ emacs(["-l erlang.el ",
+ "-l erlang-test.el -f ert-run-tests-batch-and-exit"]),
ok
end.
+tests_compiled(_Config) ->
+ case emacs_version_ok(25) of
+ false -> {skip, "Old or no emacs found"};
+ _ ->
+ emacs(["-l erlang.elc ",
+ "-l erlang-test.elc -f ert-run-tests-batch-and-exit"]),
+ ok
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+indent(Config) ->
+ Def = filename:dirname(code:which(?MODULE))
+ ++ "/"
+ ++ ?MODULE_STRING
+ ++ "_data",
+ Dir = proplists:get_value(data_dir, Config, Def),
+ OrigFs = filelib:wildcard(Dir ++ "/*"),
+ io:format("Dir: ~s~nFs: ~p~n", [Dir, OrigFs]),
+ Fs = [{File, unindent(File)} || File <- OrigFs,
+ filename:extension(File) =:= ""],
+ Indent = fun(File) ->
+ emacs([
+ File, " ",
+ "--eval '(indent-region (point-min) (point-max) nil)' ",
+ "--eval '(save-buffer 0)'"
+ ]),
+ ok
+ end,
+ [Indent(File) || {_, File} <- Fs],
+ Res = [diff(Orig, File) || {Orig, File} <- Fs],
+ [file:delete(File) || {ok, File} <- Res], %% Cleanup
+ [] = [Fail || {fail, Fail} <- Res],
+ ok.
+
unindent(Input) ->
Output = Input ++ ".erl",
{ok, Bin} = file:read_file(Input),
@@ -112,14 +187,13 @@ diff(Orig, File) ->
{fail, File}
end.
-emacs_version_ok() ->
+emacs_version_ok(AcceptVer) ->
case os:cmd("emacs --version | head -1") of
"GNU Emacs " ++ Ver ->
case string:to_float(Ver) of
- {Vsn, _} when Vsn >= 24.1 ->
- true;
+ {Vsn, _} when Vsn >= AcceptVer ->
+ Vsn;
_ ->
- io:format("Emacs version fail~n~s~n~n",[Ver]),
false
end;
Res ->
@@ -127,16 +201,19 @@ emacs_version_ok() ->
false
end.
-emacs(File) ->
- EmacsErlDir = filename:join([code:lib_dir(tools), "emacs"]),
+emacs(EmacsCmds) when is_list(EmacsCmds) ->
Cmd = ["emacs ",
"--batch --quick ",
- "--directory ", EmacsErlDir, " ",
- "--eval \"(require 'erlang-start)\" ",
- File, " ",
- "--eval '(indent-region (point-min) (point-max) nil)' ",
- "--eval '(save-buffer 0)'"
- ],
- _Res = os:cmd(Cmd),
- % io:format("cmd ~s:~n=> ~s~n", [Cmd, _Res]),
- ok.
+ "--directory ", emacs_dir(), " ",
+ "--eval \"(require 'erlang-start)\" "
+ | EmacsCmds],
+ Res0 = os:cmd(Cmd ++ " ; echo $?"),
+ Rows = string:lexemes(Res0, ["\r\n", $\n]),
+ Res = lists:last(Rows),
+ Output = string:join(lists:droplast(Rows), "\n"),
+ io:format("Cmd ~s:~n => ~s ~ts~n", [Cmd, Res, Output]),
+ "0" = Res,
+ Output.
+
+emacs_dir() ->
+ filename:join([code:lib_dir(tools), "emacs"]).
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index 4ec75f7962..da4f56c09b 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index bb3f4c66c0..1bebb1c421 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 3.0
+TOOLS_VSN = 3.0.1
diff --git a/lib/wx/c_src/wxe_driver.c b/lib/wx/c_src/wxe_driver.c
index 8b8c625971..c9d299e0df 100644
--- a/lib/wx/c_src/wxe_driver.c
+++ b/lib/wx/c_src/wxe_driver.c
@@ -38,10 +38,8 @@
#define TEMP_BINARY_SIZE 512
-static ErlDrvData wxe_driver_start(ErlDrvPort port, char *buff);
-static int wxe_driver_load(void);
+static ErlDrvData wxe_driver_start(ErlDrvPort port, char *command);
static void wxe_driver_stop(ErlDrvData handle);
-static void wxe_driver_unload(void);
static ErlDrvSSizeT wxe_driver_control(ErlDrvData handle,
unsigned int command,
char* buf, ErlDrvSizeT count,
@@ -63,30 +61,30 @@ char * erl_wx_privdir;
** The driver struct
*/
static ErlDrvEntry wxe_driver_entry = {
- wxe_driver_load, /* F_PTR init, called at loading */
- wxe_driver_start, /* L_PTR start, called when port is opened */
- wxe_driver_stop, /* F_PTR stop, called when port is closed */
- NULL, /* F_PTR output, called when erlang has sent */
- NULL, /* F_PTR ready_input, called when input descriptor
- ready */
- NULL, /* F_PTR ready_output, called when output
- descriptor ready */
- "wxe_driver", /* char *driver_name, the argument to open_port */
- wxe_driver_unload, /* F_PTR finish, called when unloaded */
- NULL, /* void * that is not used (BC) */
- wxe_driver_control, /* F_PTR control, port_control callback */
- NULL, /* F_PTR timeout, reserved */
- standard_outputv, /* F_PTR outputv, reserved */
- NULL, /* async */
- NULL, /* flush */
- wxe_driver_call, /* call */
- NULL, /* Event */
+ NULL, /* F_PTR init, called at loading */
+ wxe_driver_start, /* L_PTR start, called when port is opened */
+ wxe_driver_stop, /* F_PTR stop, called when port is closed */
+ NULL, /* F_PTR output, called when erlang has sent */
+ NULL, /* F_PTR ready_input, called when
+ input descriptor ready */
+ NULL, /* F_PTR ready_output, called when
+ output descriptor ready */
+ "wxe_driver", /* char *driver_name, the argument to open_port */
+ NULL, /* F_PTR finish, called when unloaded */
+ NULL, /* void * that is not used (BC) */
+ wxe_driver_control, /* F_PTR control, port_control callback */
+ NULL, /* F_PTR timeout, reserved */
+ standard_outputv, /* F_PTR outputv, reserved */
+ NULL, /* async */
+ NULL, /* flush */
+ wxe_driver_call, /* call */
+ NULL, /* Event */
ERL_DRV_EXTENDED_MARKER,
ERL_DRV_EXTENDED_MAJOR_VERSION,
ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
- NULL, /* Reserved Handle */
- wxe_process_died, /* Process Exited */
+ ERL_DRV_FLAG_USE_PORT_LOCKING, /* Port lock */
+ NULL, /* Reserved Handle */
+ wxe_process_died, /* Process Exited */
};
DRIVER_INIT(wxe_driver)
@@ -94,60 +92,56 @@ DRIVER_INIT(wxe_driver)
return &wxe_driver_entry;
}
-int wxe_driver_load()
-{
- if(load_native_gui())
- return 0;
- else
- return -1;
-}
-
ErlDrvPort WXE_DRV_PORT_HANDLE = 0;
ErlDrvTermData WXE_DRV_PORT = 0;
static ErlDrvData
-wxe_driver_start(ErlDrvPort port, char *buff)
-{
- wxe_data *data;
-
- data = (wxe_data *) malloc(sizeof(wxe_data));
- wxe_debug = 0;
-
- if (data == NULL) {
- fprintf(stderr, " Couldn't alloc mem\r\n");
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- ErlDrvTermData term_port = driver_mk_port(port);
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- data->driver_data = NULL;
- data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
- data->bin[0].from = 0;
- data->bin[1].from = 0;
- data->bin[2].from = 0;
- data->max_bins = DEF_BINS;
- data->port_handle = port;
- data->port = term_port;
- data->pdl = driver_pdl_create(port);
- if(WXE_DRV_PORT_HANDLE == 0) {
- for(; *buff != 32; buff++);
- buff++;
- erl_wx_privdir = strdup(buff);
-
- WXE_DRV_PORT_HANDLE = port;
- WXE_DRV_PORT = term_port;
- wxe_master = data;
- if(!(start_native_gui(data) == 1))
- return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
- } else {
- meta_command(CREATE_PORT,data);
- }
- return (ErlDrvData) data;
- }
+wxe_driver_start(ErlDrvPort port, char *command)
+{
+ wxe_data *data;
+
+ data = (wxe_data *) malloc(sizeof(wxe_data));
+ wxe_debug = 0;
+
+ if (data == NULL) {
+ fprintf(stderr, " Couldn't alloc mem\r\n");
+ return(ERL_DRV_ERROR_GENERAL); /* ENOMEM */
+ } else {
+ ErlDrvTermData term_port = driver_mk_port(port);
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+ data->driver_data = NULL;
+ data->bin = (WXEBinRef*) driver_alloc(sizeof(WXEBinRef)*DEF_BINS);
+ data->bin[0].from = 0;
+ data->bin[1].from = 0;
+ data->bin[2].from = 0;
+ data->max_bins = DEF_BINS;
+ data->port_handle = port;
+ data->port = term_port;
+ data->pdl = driver_pdl_create(port);
+ if(WXE_DRV_PORT_HANDLE == 0) {
+ char *first_space = strchr(command, ' ');
+ if (first_space) {
+ char *priv_dir = first_space + 1;
+ erl_wx_privdir = strdup(priv_dir);
+
+ WXE_DRV_PORT_HANDLE = port;
+ WXE_DRV_PORT = term_port;
+ wxe_master = data;
+ if(start_native_gui(data) != 1)
+ return ERL_DRV_ERROR_GENERAL; /* ENOMEM */
+ } else {
+ return ERL_DRV_ERROR_BADARG;
+ }
+ } else {
+ meta_command(CREATE_PORT, data);
+ }
+ return (ErlDrvData) data;
+ }
}
static void
wxe_driver_stop(ErlDrvData handle)
-{
+{
wxe_data *sd = ((wxe_data *)handle);
if(sd->port_handle != WXE_DRV_PORT_HANDLE) {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
@@ -155,18 +149,11 @@ wxe_driver_stop(ErlDrvData handle)
} else {
// fprintf(stderr, "%s:%d: STOP \r\n", __FILE__,__LINE__);
stop_native_gui(wxe_master);
- unload_native_gui();
free(wxe_master);
wxe_master = NULL;
}
}
-static void
-wxe_driver_unload(void)
-{
- // fprintf(stderr, "%s:%d: UNLOAD \r\n", __FILE__,__LINE__);
-}
-
static ErlDrvSSizeT
wxe_driver_control(ErlDrvData handle, unsigned op,
char* buf, ErlDrvSizeT count,
@@ -194,7 +181,7 @@ wxe_driver_call(ErlDrvData handle, unsigned int command,
if (len > rlen)
*res = driver_alloc(len);
memcpy((void *) *res, (void *) buf, len);
- return len;
+ return len;
}
@@ -219,20 +206,20 @@ standard_outputv(ErlDrvData drv_data, ErlIOVec* ev)
int i, max;
for(i = 0; i < sd->max_bins; i++) {
- if(sd->bin[i].from == 0) {
- binref = &sd->bin[i];
- break;
- }
+ if(sd->bin[i].from == 0) {
+ binref = &sd->bin[i];
+ break;
+ }
}
if(binref == NULL) { /* realloc */
- max = sd->max_bins + DEF_BINS;
- driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
- for(i=sd->max_bins; i < max; i++) {
- sd->bin[i].from = 0;
- }
- binref = &sd->bin[sd->max_bins];
- sd->max_bins = max;
+ max = sd->max_bins + DEF_BINS;
+ driver_realloc(sd->bin, sizeof(WXEBinRef)*max);
+ for(i=sd->max_bins; i < max; i++) {
+ sd->bin[i].from = 0;
+ }
+ binref = &sd->bin[sd->max_bins];
+ sd->max_bins = max;
}
if(ev->size > 0) {
diff --git a/lib/wx/c_src/wxe_driver.h b/lib/wx/c_src/wxe_driver.h
index f9bca049c8..6d6a67fa85 100644
--- a/lib/wx/c_src/wxe_driver.h
+++ b/lib/wx/c_src/wxe_driver.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -56,10 +56,8 @@ typedef struct wxe_data_def {
void init_glexts(wxe_data*);
-int load_native_gui();
int start_native_gui(wxe_data *sd);
void stop_native_gui(wxe_data *sd);
-void unload_native_gui();
#define FUNC_CALL 13
#define CREATE_PORT 14
diff --git a/lib/wx/c_src/wxe_main.cpp b/lib/wx/c_src/wxe_main.cpp
index c7565e33bd..5b65d8a59b 100644
--- a/lib/wx/c_src/wxe_main.cpp
+++ b/lib/wx/c_src/wxe_main.cpp
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2014-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2014-2018. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -59,15 +59,9 @@ void *wxe_main_loop(void * );
* START AND STOP of driver thread
* ************************************************************/
-int load_native_gui()
-{
- return 1;
-}
-
int start_native_gui(wxe_data *sd)
{
int res;
- ErlDrvThreadOpts *opts = NULL;
wxe_status_m = erl_drv_mutex_create((char *) "wxe_status_m");
wxe_status_c = erl_drv_cond_create((char *)"wxe_status_c");
@@ -79,7 +73,7 @@ int start_native_gui(wxe_data *sd)
res = erl_drv_steal_main_thread((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,NULL);
#else
- opts = erl_drv_thread_opts_create((char *)"wx thread");
+ ErlDrvThreadOpts *opts = erl_drv_thread_opts_create((char *)"wx thread");
opts->suggested_stack_size = 8192;
res = erl_drv_thread_create((char *)"wxwidgets",
&wxe_thread,wxe_main_loop,(void *) sd->pdl,opts);
@@ -116,11 +110,6 @@ void stop_native_gui(wxe_data *sd)
erl_drv_cond_destroy(wxe_batch_locker_c);
}
-void unload_native_gui()
-{
-
-}
-
/* ************************************************************
* wxWidgets Thread
* ************************************************************/
diff --git a/lib/wx/doc/overview.edoc b/lib/wx/doc/overview.edoc
index 054016f515..843a9c1320 100644
--- a/lib/wx/doc/overview.edoc
+++ b/lib/wx/doc/overview.edoc
@@ -218,7 +218,7 @@ the <em>fun</em> returns.
The callbacks are always invoked by another process and have
exclusive usage of the GUI when invoked. This means that a callback <em>fun</em>
-can not use the process dictionary and should not make calls to other
+cannot use the process dictionary and should not make calls to other
processes. Calls to another process inside a callback <em>fun</em> may cause a
deadlock if the other process is waiting on completion of his call to
the GUI.
diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml
index 45638dff35..a925cf30d4 100644
--- a/lib/wx/doc/src/notes.xml
+++ b/lib/wx/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the wxErlang
application.</p>
+<section><title>Wx 1.8.5</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed compilation warning on Darwin.</p>
+ <p>
+ Own Id: OTP-15230 Aux Id: PR-1860 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Wx 1.8.4</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/wx/examples/demo/ex_graphicsContext.erl b/lib/wx/examples/demo/ex_graphicsContext.erl
index 1193578037..1e6ffce18d 100644
--- a/lib/wx/examples/demo/ex_graphicsContext.erl
+++ b/lib/wx/examples/demo/ex_graphicsContext.erl
@@ -74,7 +74,7 @@ do_init(Config) ->
pen = Pen, brush = Brush, font = Font}}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Sync events i.e. from callbacks must return ok, it can not return a new state.
+%% Sync events i.e. from callbacks must return ok, it cannot return a new state.
%% Do the redrawing here.
handle_sync_event(#wx{event = #wxPaint{}},_,
#state{win=Win, pen = Pen, brush = Brush, font = Font}) ->
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 7ecd9b7283..1cc194d569 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -347,9 +347,9 @@ connect_in_callback(Config) ->
%% such that new events are not fired until the previous
%% callback have returned.
- %% That means that a callback can not wait for other events
+ %% That means that a callback cannot wait for other events
%% in receive since they will not come.
- %% It also means that you can not attach a new callback directly from
+ %% It also means that you cannot attach a new callback directly from
%% the callback since that callback will be removed when the temporary
%% process that executes the outer callback (may) die(s) before the callback
%% is invoked
diff --git a/lib/wx/test/wxt b/lib/wx/test/wxt
index e720ed94f4..94513e88e9 100755
--- a/lib/wx/test/wxt
+++ b/lib/wx/test/wxt
@@ -2,7 +2,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2016. All Rights Reserved.
+# Copyright Ericsson AB 2008-2018. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
#
# %CopyrightEnd%
#
-# Usage: mt <args to erlang startup script>
+# Usage: wxt <args to erlang startup script>
log=test_log_$$
latest=test_log_latest
@@ -27,7 +27,7 @@ erlcmd="erl -sname test_server -smp -pa ../ebin $p $args -wx_test_verbose true -
echo "Give the following command in order to see the outcome:"
echo ""
-echo " less test_log$$"
+echo " less $log"
rm "$latest" 2>/dev/null
ln -s "$log" "$latest"
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index 37a5477631..e539ad36f6 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.8.4
+WX_VSN = 1.8.5
diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml
index b7d1db7dfc..a97036127e 100644
--- a/lib/xmerl/doc/src/notes.xml
+++ b/lib/xmerl/doc/src/notes.xml
@@ -32,6 +32,21 @@
<p>This document describes the changes made to the Xmerl application.</p>
+<section><title>Xmerl 1.3.18</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Improved documentation.</p>
+ <p>
+ Own Id: OTP-15190</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Xmerl 1.3.17</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
index 1dca9608cb..ef753c7148 100644
--- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
@@ -3679,7 +3679,7 @@ create_tempfile(Template) ->
false ->
case os:getenv("TEMP") of
false ->
- throw({error, "Variabel TMP or TEMP doesn't exist"});
+ throw({error, "Variable TMP or TEMP doesn't exist"});
P2 ->
P2
end;
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index a1f6ad4e2c..e543a5a11e 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2018. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -279,7 +279,7 @@ int_file_decl(F, Options,_ExtCharset) ->
%% @spec string(Text::list()) -> {xmlElement(),Rest}
%% Rest = list()
-%% @equiv string(Test, [])
+%% @equiv string(Text, [])
string(Str) ->
string(Str, []).
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
index c2533248d1..0379c18214 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
index 3b5d8ae2ad..3b9ccac0f4 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/eventp/CelloMOM.xml
@@ -276,7 +276,7 @@
</exception>
<exception name="UpgradeNotPossibleException">
- <description>Before an upgrade is started it was found that the upgrade can not take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
+ <description>Before an upgrade is started it was found that the upgrade cannot take place. A possible reason is that the upgrade package that is running in the node is not in the upgrade window of this upgrade package. </description>
<exceptionParameter name="message">
<dataType>
<string/>
@@ -1703,7 +1703,7 @@ Example:
<exception name="NoSuchAttributeException">
<description>Exception thrown when an MO attribute is requested to be accessed but the access
-method for the is not defined (the attribute can not be accessed)</description>
+method for the is not defined (the attribute cannot be accessed)</description>
</exception>
<exception name="MoCardinalityViolationException">
@@ -3125,7 +3125,7 @@ active = Synchronization is used in system clock generation.
<description>RefState can have the following values:
failed = synchronization reference is not capable to perform its required tasks.
degraded = capability of synchronization reference to perform its required tasks is degraded e.g. because of signal level degradation. This value is only applicable for traffic carrying (ET physical path termination) synchronization references. Note: attribute degradationIsFault controls whether synchronization reference degradation is interpreted as a synchronization reference fault or not.
-lossOfTracking = system clock regulation algorithm on TU board can not follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
+lossOfTracking = system clock regulation algorithm on TU board cannot follow the 8kHz synchronization reference signal either because of the poor quality of the signal or because of a HW fault at TU board. If all synchronization references repeatedly end up to state lossOfTracking, fault is likely in TU HW.
ok = synchronization reference is capable of performing its required tasks.
</description>
<enumMember name="failed">
@@ -11270,7 +11270,7 @@ Note! This action requires a transaction.</description>
The changing of the IP address with operation assignIpAddress might cause interruption of the communication if the network management tool is connected via the ethernet link.
-Note: The EthernetLink MO can not be deleted!
+Note: The EthernetLink MO cannot be deleted!
Note: The performance monitoring counters in the EthernetLink MO has a "Wrap-around time" of approximately 2 hours.
</description>
@@ -11532,8 +11532,8 @@ Note! This action requires a transaction.</description>
<description>This MO holds the IP routing table.
The IpRoutingTable MO is automatically created when the Ip MO is created.
-The IpRoutingTable MO can not be created manually.
-The IpRoutingTable MO can not be deleted.
+The IpRoutingTable MO cannot be created manually.
+The IpRoutingTable MO cannot be deleted.
</description>
<systemCreated/>
<attribute name="userLabel">
@@ -12967,7 +12967,7 @@ Note! When using fractional atm, timeslot 1 must be a part of the fraction.
Note! ETM1 does not support EPD and PPD
-Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic can not be guaranteed and shaping on UBR+ traffic is not possible.
+Note! ETM1 does not have a proper buffer management. Thus fairness of UBR+ traffic cannot be guaranteed and shaping on UBR+ traffic is not possible.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 per port.
</description>
@@ -13371,7 +13371,7 @@ Struct element description :
-Date is in string format, max length is 40. Format for date is: weekday month date hour:min:seconds year.
-Status is in string format, max length is 40.
-Note! The identity can not be the same as name. Identity should contain the product identity.
+Note! The identity cannot be the same as name. Identity should contain the product identity.
</description>
@@ -13562,7 +13562,7 @@ Note! For comment and operatorName spaces (' ') are also allowed within the stri
This action does not require a transaction.
-Note! The configurationVersionName and identity can not be the same. The identity should be the product identity.
+Note! The configurationVersionName and identity cannot be the same. The identity should be the product identity.
</description>
<returnType>
<void/>
@@ -17367,7 +17367,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileItuId">
<description>Reference to a Mtp2ProfileItu MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -17566,7 +17566,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.</description>
<attribute name="mtp2ProfileAnsiId">
<description>Reference to a Mtp2ProfileAnsi MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
@@ -21777,7 +21777,7 @@ Each E1/DS1/J1 channel can suport up to 2 VP connections.
The ET-MC41 board support one biderectional F4/F5 PM flow per E1 channel.
-Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group can not be selected randomly.
+Note! The ETMC41 supports IMA. However the E1 ports being part of the same IMA group cannot be selected randomly.
Note! The number of VCC TP+VPC TP with performance monitoring enabled (i.e. PM mode &lt;&gt; off) is restricted to 1 / port
@@ -21883,7 +21883,7 @@ NOTE: There is a restriction of a maximum of 32 Mtp2Tp's per MP.
<attribute name="mtp2ProfileChinaId">
<description>Reference to a Mtp2ProfileChina MO.
-Note: The bitRate can not be changed.</description>
+Note: The bitRate cannot be changed.</description>
<mandatory/>
<noNotification/>
<dataType>
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index be11935f2f..3a266a56bd 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.17
+XMERL_VSN = 1.3.18
diff --git a/configure.in b/make/configure.in
index 559049aca1..bf3fd0751f 100644
--- a/configure.in
+++ b/make/configure.in
@@ -44,7 +44,7 @@ case "X$ERL_TOP" in
X)
;;
X/*)
- test -f $ERL_TOP/erts/emulator/beam/beam_emu.c || {
+ test -f "$ERL_TOP/erts/emulator/beam/beam_emu.c" || {
AC_MSG_ERROR([Invalid \$ERL_TOP])
}
srcdir="$ERL_TOP";;
@@ -93,6 +93,8 @@ dnl
if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
AC_CANONICAL_HOST
+else
+ host_os=$host
fi
TARGET=$host
@@ -128,6 +130,8 @@ AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL(LD, [ld])
+LM_WINDOWS_ENVIRONMENT
+
_search_path=/bin:/usr/bin:/usr/local/bin:$PATH
AC_PATH_PROG(ENV, [env], false, $_search_path)
@@ -185,6 +189,10 @@ fi
AC_PROG_LN_S
AC_PROG_RANLIB
+LM_PROG_PERL5
+if test "$ac_cv_path_PERL" = false; then
+ AC_MSG_ERROR([Perl version 5 is required!])
+fi
#
# Get erts version from erts/vsn.mk
@@ -207,6 +215,9 @@ AC_MSG_CHECKING([OTP version])
AC_MSG_RESULT([$OTP_VSN])
AC_SUBST(OTP_VSN)
+AC_ARG_ENABLE(parallel-configure,
+AS_HELP_STRING([--disable-parallel-configure], [disable parallel execution of configure scripts]))
+
AC_ARG_ENABLE(dirty-schedulers,
AS_HELP_STRING([--enable-dirty-schedulers], [enable dirty scheduler support]))
@@ -412,77 +423,9 @@ if test $CROSS_COMPILING = no; then
esac
fi
-rm -f $ERL_TOP/lib/SKIP-APPLICATIONS
-for app in `cd lib && ls -d *`; do
- var=`eval echo \\$with_$app`
- if test X${var} = Xno; then
- echo "$app" >> $ERL_TOP/lib/SKIP-APPLICATIONS
- fi
-done
+ERL_DED
-export ERL_TOP
-AC_CONFIG_SUBDIRS(lib erts)
-
-AC_CONFIG_FILES([Makefile make/output.mk])
-AC_CONFIG_FILES([make/emd2exml], [chmod +x make/emd2exml])
+AC_CONFIG_FILES([../Makefile output.mk ../make/$host/otp_ded.mk:../make/otp_ded.mk.in])
+AC_CONFIG_FILES([emd2exml], [chmod +x emd2exml])
AC_OUTPUT
-
-pattern="lib/*/SKIP"
-files=`echo $pattern`
-if test "$files" != "$pattern" || test -f $ERL_TOP/lib/SKIP-APPLICATIONS; then
- echo '*********************************************************************'
- echo '********************** APPLICATIONS DISABLED **********************'
- echo '*********************************************************************'
- echo
- if test "$files" != "$pattern"; then
- for skipfile in $files; do
- app=`dirname $skipfile`; app=`basename $app`
- printf "%-15s: " $app; cat $skipfile
- done
- fi
- if test -f $ERL_TOP/lib/SKIP-APPLICATIONS; then
- for skipapp in `cat $ERL_TOP/lib/SKIP-APPLICATIONS`; do
- printf "%-15s: User gave --without-%s option\n" $skipapp $skipapp
- done
- fi
- echo
- echo '*********************************************************************'
-fi
-pattern="lib/*/CONF_INFO"
-files=`echo $pattern`
-if test "$files" != "$pattern" || test -f erts/CONF_INFO; then
- echo '*********************************************************************'
- echo '********************** APPLICATIONS INFORMATION *******************'
- echo '*********************************************************************'
- echo
- test "$files" != "$pattern" || files=""
- test ! -f erts/CONF_INFO || files="$files erts/CONF_INFO"
- for infofile in $files; do
- app=`dirname $infofile`; app=`basename $app`
- printf "%-15s: " $app; cat $infofile
- done
- echo
- echo '*********************************************************************'
-fi
-if test -f "erts/doc/CONF_INFO"; then
- echo '*********************************************************************'
- echo '********************** DOCUMENTATION INFORMATION ******************'
- echo '*********************************************************************'
- echo
- printf "%-15s: \n" documentation;
- havexsltproc="yes"
- for cmd in `cat erts/doc/CONF_INFO`; do
- echo " $cmd is missing."
- if test $cmd = "xsltproc"; then
- havexsltproc="no"
- fi
- done
- if test $havexsltproc = "no"; then
- echo ' The documentation can not be built.'
- else
- echo ' Using fakefop to generate placeholder PDF files.'
- fi
- echo
- echo '*********************************************************************'
-fi
diff --git a/make/emd2exml.in b/make/emd2exml.in
index 57bcaba24d..24837696f4 100755
--- a/make/emd2exml.in
+++ b/make/emd2exml.in
@@ -1214,7 +1214,7 @@ complete_output(#state{out = Out} = S) ->
complete_output(S, [], Out) ->
S#state{delayed_array = [],
- out = ["<?xml version=\"1.0\" encoding=\"utf8\" ?>", nl(),
+ out = ["<?xml version=\"1.0\" encoding=\"utf-8\" ?>", nl(),
"<!DOCTYPE chapter SYSTEM \"chapter.dtd\">", nl(),
Out]};
complete_output(S, [{delayed, IX}|Rest], Out) ->
diff --git a/make/fixup_development_runtime_dependencies b/make/fixup_development_runtime_dependencies
new file mode 100755
index 0000000000..e06bd5faca
--- /dev/null
+++ b/make/fixup_development_runtime_dependencies
@@ -0,0 +1,111 @@
+#!/usr/bin/env perl
+
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2018. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Replaces runtime_dependencies pointing to future not yet
+# resolved versions in the maint and master branches while under
+# development. Such dependencies may exist in .app files on the
+# form (<app name>-@<ticket>(:<ticket>)*@) and will be replaced
+# with the current version of the application in the source tree.
+# This in order not to break tests looking at runtime_dependencies.
+#
+
+use strict;
+use File::Basename;
+
+my $usage_text = <<"HERE";
+ usage: $0 <ERL_TOP>
+HERE
+
+my %app_vsn;
+my $exit_status = 0;
+
+@ARGV == 1 or die $usage_text;
+my $erl_top = shift @ARGV;
+
+chdir $erl_top or die "Failed to change directory into '$erl_top'";
+
+print "Fixup of development runtime dependencies\n";
+
+#
+# Determine versions of all applications in the source tree...
+#
+foreach my $vsn_mk (<lib/*/vsn.mk>, <erts/vsn.mk>) {
+ my $app_dir = dirname($vsn_mk);
+ my $app = basename($app_dir);
+
+ if (!open(VSN, $vsn_mk)) {
+ $exit_status = 1;
+ print STDERR "ERROR: Failed to open '$vsn_mk' for reading: $!\n";
+ }
+ else {
+ my $vsn = '';
+ while (<VSN>) {
+ if (/VSN\s*=\s*(\S+)/) {
+ $vsn = $1;
+ last;
+ }
+ }
+ close VSN;
+ if (!$vsn) {
+ $exit_status = 1;
+ print STDERR "ERROR: No version found in '$vsn_mk'\n"
+ }
+ else {
+ $app_vsn{$app} = "$app-$vsn";
+ }
+ }
+}
+
+my $valid_apps = join('|', keys %app_vsn);
+
+#
+# Replace all <app name>-@<ticket>(:<ticket>)*@ versions
+# in all *.app files with the versions currently used...
+#
+foreach my $app_file (<lib/*/ebin/*.app>, <erts/preloaded/ebin/erts.app>) {
+ if (!open(IN, "<", $app_file)) {
+ $exit_status = 1;
+ print STDERR "ERROR: Failed to open '$app_file' for reading: $!";
+ }
+ else {
+ local $/;
+ my $file = <IN>;
+ close IN;
+ my $old_file = $file;
+
+ $file =~ s/($valid_apps)-\@OTP-\d{4,5}(?::OTP-\d{4,5})*\@/$app_vsn{$1}/g;
+
+ if ($file ne $old_file) {
+ if (!open(OUT, ">", $app_file)) {
+ $exit_status = 1;
+ print STDERR "ERROR: Failed to open '$app_file' for writing: $!";
+ }
+ else {
+ print OUT $file;
+ close OUT;
+ }
+ }
+ }
+}
+
+exit $exit_status;
diff --git a/make/lazy_configure.mk b/make/lazy_configure.mk
deleted file mode 100644
index c74f216de0..0000000000
--- a/make/lazy_configure.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-# ``Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
-#
-
-ifndef EXPECTED_AUTOCONF_VERSION
-EXPECTED_AUTOCONF_VERSION=2.59
-endif
-SAVE_ARGS=$(ERL_TOP)/make/save_args
-CONFIG_STATUS=$(CONFIGURE_DIR)/$(TARGET)/config.status
-SAVED_CONFIG_FLAGS_FILE=$(CONFIGURE_DIR)/$(TARGET)/lazy.config.flags
-SAVED_CONFIG_LOG=$(CONFIGURE_DIR)/$(TARGET)/config.log
-CONFIG_CACHE_FILE=$(CONFIGURE_DIR)/$(TARGET)/lazy.config.cache
-ALL_CONFIG_FLAGS=$(CONFIGURE_FLAGS) --no-create --no-recursion --cache-file=$(CONFIG_CACHE_FILE)
-
-lazy_configure: save_config_flags $(CONFIG_STATUS)
- rm -f $(CONFIGURE_DIR)/config.log
- cd $(CONFIGURE_DIR) && $(CONFIG_STATUS)
- cat $(CONFIGURE_DIR)/config.log >> $(SAVED_CONFIG_LOG)
- rm -f $(CONFIGURE_DIR)/config.log
-
-save_config_flags:
- $(SAVE_ARGS) $(SAVED_CONFIG_FLAGS_FILE) --- $(ALL_CONFIG_FLAGS)
-
-$(SAVED_CONFIG_FLAGS_FILE): save_config_flags
-
-$(CONFIGURE_DIR)/configure: $(CONFIGURE_DIR)/configure.in $(EXTRA_CONFIGURE_DEPENDENCIES)
- rm -f $(CONFIG_CACHE_FILE)
- @ exp_ac_vsn=$(EXPECTED_AUTOCONF_VERSION) ; \
- ac_vsn_blob=`autoconf --version` ; \
- ac_vsn=`echo x$$ac_vsn_blob | sed "s|[^0-9]*\([0-9][^ \t\n]*\).*|\1|"` ; \
- case "$$ac_vsn" in \
- $$exp_ac_vsn) \
- ;; \
- *) \
- echo "***************************************************" 1>&2 ; \
- echo "***************************************************" 1>&2 ; \
- echo "*** WARNING: System might fail to configure or" 1>&2 ; \
- echo "*** might be erroneously configured" 1>&2 ; \
- echo "*** since autoconf version $$ac_vsn is used" 1>&2 ; \
- echo "*** instead of version $$exp_ac_vsn!" 1>&2 ; \
- echo "***************************************************" 1>&2 ; \
- echo "***************************************************" 1>&2 ; \
- ;; \
- esac
- cd $(CONFIGURE_DIR) && autoconf -f
-
-$(CONFIGURE_DIR)/config.h.in: $(CONFIGURE_DIR)/configure.in $(CONFIGURE_DIR)/aclocal.m4
- cd $(CONFIGURE_DIR) && autoheader ./configure.in > ./config.h.in
-
-$(CONFIG_STATUS): $(SAVED_CONFIG_FLAGS_FILE) $(CONFIGURE_DIR)/configure $(EXTRA_CONFIG_STATUS_DEPENDENCIES)
- rm -f $(CONFIGURE_DIR)/config.log
- cd $(CONFIGURE_DIR) && CONFIG_STATUS=$(CONFIG_STATUS) ./configure $(ALL_CONFIG_FLAGS)
- rm -f $(SAVED_CONFIG_LOG)
- mv $(CONFIGURE_DIR)/config.log $(SAVED_CONFIG_LOG)
-
-lazy_configure_target_clean:
- rm -f $(CONFIG_STATUS)
- rm -f $(CONFIG_CACHE_FILE)
- rm -f $(SAVED_CONFIG_FLAGS_FILE)
- rm -f $(SAVED_CONFIG_LOG)
-
-lazy_configure_clean: lazy_configure_target_clean
- rm -f $(CONFIGURE_DIR)/configure
- test ! -f $(CONFIGURE_DIR)/acconfig.h || rm -f $(CONFIGURE_DIR)/config.h.in
-
-.PHONY: lazy_configure save_config_flags lazy_configure_clean
-
diff --git a/make/otp_ded.mk.in b/make/otp_ded.mk.in
index 0b5311d75e..9c8df265de 100644
--- a/make/otp_ded.mk.in
+++ b/make/otp_ded.mk.in
@@ -24,27 +24,26 @@
# explicitly expressed here. Some applications need to
# be able to check this value *before* configure has
# been run and generated otp_ded.mk
-DED_MK_VSN = 1
+DED_MK_VSN = 2
# ----------------------------------------------------
# Variables needed for building Dynamic Erlang Drivers
# ----------------------------------------------------
-DED_CC = @CC@
-DED_GCC = @GCC@
+DED_CC = @DED_CC@
+DED_GCC = @DED_GCC@
DED_LD = @DED_LD@
DED_LDFLAGS = @DED_LDFLAGS@
-DED__NOWARN_NOTHR_CFLAGS = @DED_CFLAGS@
-DED__NOTHR_CFLAGS = @WFLAGS@ @DED_CFLAGS@
-DED__NOWARN_CFLAGS = @DED_EMU_THR_DEFS@ @DED_CFLAGS@
+DED_BASIC_CFLAGS = @DED_CFLAGS@
DED_THR_DEFS = @DED_THR_DEFS@
-DED_EMU_THR_DEFS = @DED_EMU_THR_DEFS@
-DED_WARN_FLAGS = @WFLAGS@
-DED_CFLAGS = @WERRORFLAGS@ @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_CFLAGS@
-DED_STATIC_CFLAGS = @WERRORFLAGS@ @WFLAGS@ @DED_EMU_THR_DEFS@ @DED_STATIC_CFLAGS@
-DED_LIBS = @LIBS@
+DED_WERRORFLAGS = @DED_WERRORFLAGS@
+DED_WARN_FLAGS = @DED_WARN_FLAGS@
+DED_CFLAGS = @DED_CFLAGS@
+DED_LD_FLAG_RUNTIME_LIBRARY_PATH = @DED_LD_FLAG_RUNTIME_LIBRARY_PATH@
+DED_STATIC_CFLAGS = @DED_STATIC_CFLAGS@
+DED_LIBS = @DED_LIBS@
DED_EXT = @DED_EXT@
-ERLANG_OSTYPE = @ERLANG_OSTYPE@
+DED_OSTYPE = @DED_OSTYPE@
PRIVDIR = ../priv
OBJDIR = $(PRIVDIR)/obj/$(TARGET)
LIBDIR = $(PRIVDIR)/lib/$(TARGET)
DED_SYS_INCLUDE = @DED_SYS_INCLUDE@
-DED_INCLUDES = $(DED_SYS_INCLUDE)
+DED_INCLUDES = @DED_INCLUDE@
diff --git a/make/otp_patch_solve_forward_merge_version b/make/otp_patch_solve_forward_merge_version
new file mode 100644
index 0000000000..b8626c4cff
--- /dev/null
+++ b/make/otp_patch_solve_forward_merge_version
@@ -0,0 +1 @@
+4
diff --git a/make/otp_version_tickets b/make/otp_version_tickets
new file mode 100644
index 0000000000..b8220e1a87
--- /dev/null
+++ b/make/otp_version_tickets
@@ -0,0 +1 @@
+DEVELOPMENT
diff --git a/otp_build b/otp_build
index 175c5fbcfe..21d520e101 100755
--- a/otp_build
+++ b/otp_build
@@ -21,11 +21,10 @@
# Global configuration variables
#
-# NOTE: lazy_configure depends on '.' always being last directory
if [ -z "$ONLY_ERTS" ]; then
AUTOCONF_SUBDIRS="lib lib/* lib/common_test/test_server"
fi
-AUTOCONF_SUBDIRS="$AUTOCONF_SUBDIRS erts ."
+AUTOCONF_SUBDIRS="$AUTOCONF_SUBDIRS make erts"
# `bootstrap_apps' should include application that are built, or
# partly built in one of the bootstrap phases. Applications that
@@ -212,55 +211,10 @@ set_config_flags ()
NL="\
"
-create_lib_configure_in()
-{
- cd $ERL_TOP
-
- # Multiple versions of autoconf generates code that
- # don't work on all platforms (e.g. SunOS 5.8) if
- # sub directories are soft links. Internally at Ericsson
- # some OTP application directories are soft links.
- # An added "/." solves this problem.
-
- sdirs=
- for lib_app in $bootstrap_apps; do
- case $lib_app in
- lib/*)
- if [ -f "$lib_app/configure.in" ]; then
- app=`echo "$lib_app" | sed "s|lib/\(.*\)|\1|"`
- sdirs="${sdirs}test ! -f $app/configure || AC_CONFIG_SUBDIRS($app/.)${NL}"
- fi;;
- *)
- ;;
- esac
- done
-
- sed_bootstrap="s%@BOOTSTRAP_CONFIGURE_APPS@%$sdirs%g"
-
- sdirs=
- for lib_app in lib/*; do
- is_bapp=false
- for bapp in $bootstrap_apps; do
- test $bapp != $lib_app || { is_bapp=true; break; }
- done
- if [ $is_bapp = false ] && [ -f "$lib_app/configure.in" ]; then
- app=`echo "$lib_app" | sed "s|lib/\(.*\)|\1|"`
- sdirs="${sdirs} test ! -f $app/configure || AC_CONFIG_SUBDIRS($app/.)${NL}"
- fi
- done
-
- sed_non_bootstrap="s%@NON_BOOTSTRAP_CONFIGURE_APPS@%$sdirs%g"
-
- rm -f lib/configure.in
- sed "$sed_bootstrap;$sed_non_bootstrap" > lib/configure.in < lib/configure.in.src || {
- echo "Failed to create lib/configure.in"
- exit 1
- }
-}
distribute_config_helpers ()
{
- aclocal_dirs=". ./lib/erl_interface ./lib/odbc ./lib/wx ./lib/megaco"
+ aclocal_dirs="make ./lib/crypto ./lib/erl_interface ./lib/odbc ./lib/wx ./lib/megaco"
autoconf_aux_dirs="./lib/common_test/priv/auxdir ./lib/erl_interface/src/auxdir ./lib/common_test/test_server ./lib/wx/autoconf"
aclocal_master="./erts/aclocal.m4"
@@ -282,7 +236,6 @@ distribute_config_helpers ()
do_autoconf ()
{
- create_lib_configure_in
distribute_config_helpers
if [ ! -z "$OVERRIDE_CONFIGURE" ]; then
@@ -323,6 +276,15 @@ do_autoconf ()
( cd "$d" && autoheader ) || exit 1
done
+ echo ""
+ echo "=== creating ./configure"
+ otp_version=`cat "$ERL_TOP/OTP_VERSION"`
+ bootstrap_lib_apps=`echo $bootstrap_apps | sed "s|erts||g"`
+ cat "$ERL_TOP/configure.src" \
+ | sed "s|@OTP_VERSION@|$otp_version|g;s|@BOOTSTRAP_LIB_APP_DIRS@|$bootstrap_lib_apps|" \
+ > "$ERL_TOP/configure"
+ chmod +x "$ERL_TOP/configure"
+
restore_vars OVERRIDE_TARGET TARGET
}
@@ -385,8 +347,8 @@ try_cross_configure ()
test "X$build_value" != "X" || build_value="$BUILDSYS"
- build_sys=`$ERL_TOP/erts/autoconf/config.sub "$build_value"` || exit 1
- host_sys=`$ERL_TOP/erts/autoconf/config.sub "$host_value"` || exit 1
+ build_sys=`"$ERL_TOP/erts/autoconf/config.sub" "$build_value"` || exit 1
+ host_sys=`"$ERL_TOP/erts/autoconf/config.sub" "$host_value"` || exit 1
test "$host_sys" = "$build_sys" || cross_configure=yes
@@ -500,7 +462,7 @@ do_configure ()
case $TARGET in
vxworks_*)
( cd erts/autoconf && \
- $ERL_TOP/erts/autoconf/configure.vxworks $TARGET )
+ "$ERL_TOP/erts/autoconf/configure.vxworks" $TARGET )
echo "Configuring for build system too..." >&2
hide_vars OVERRIDE_TARGET TARGET
TARGET=$BUILDSYS
@@ -526,105 +488,6 @@ do_configure ()
fi
}
-do_lazy_configure ()
-{
- setup_make
- if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
- echo "Not supported for cross compilation" >&2
- exit 1
- fi
- maybe_copy_static_cache
- CONFIG_FLAGS=
- set_config_flags "$@"
- CONFIGURE_FLAGS="$@"
- [ "$CONFIG_FLAGS" = "" ] || CONFIGURE_FLAGS="$CONFIG_FLAGS $CONFIGURE_FLAGS"
- for c_dir in $AUTOCONF_SUBDIRS; do
- if test -f $ERL_TOP/$c_dir/configure.in; then
- dir=$ERL_TOP/$c_dir
- echo ""
- echo "=== Begin configuring $dir"
- xc_dep= ;
- xcs_dep= ;
- test -d $dir/$TARGET || mkdir $dir/$TARGET
- test -f $dir/aclocal.m4 && xc_dep="$xcs_dep $dir/aclocal.m4"
- test -f $dir/acsite.m4 && xc_dep="$xcs_dep $dir/acsite.m4"
- test x$c_dir = x"erts" && xcs_dep="$xcs_dep $dir/config.h.in"
- $MAKE -f $ERL_TOP/make/lazy_configure.mk \
- MAKE="$MAKE" TARGET=$TARGET \
- ERL_TOP=$ERL_TOP \
- CONFIGURE_FLAGS="$CONFIGURE_FLAGS" \
- CONFIGURE_DIR=$dir \
- EXTRA_CONFIGURE_DEPENDENCIES=$xc_dep \
- EXTRA_CONFIG_STATUS_DEPENDENCIES=$xcs_dep \
- lazy_configure
- echo "=== Done configuring $dir"
- echo ""
- fi
- done
-}
-
-do_lazy_configure_clean ()
-{
- setup_make
- if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
- echo "Not supported for cross compilation" >&2
- exit 1
- fi
- for c_dir in $AUTOCONF_SUBDIRS; do
- if test -f $ERL_TOP/$c_dir/configure.in; then
- dir=$ERL_TOP/$c_dir
- echo ""
- echo "=== Begin cleaning configure in $dir"
- xc_dep= ;
- xcs_dep= ;
- test -d $dir/$TARGET || mkdir $dir/$TARGET
- test -f $dir/aclocal.m4 && xc_dep="$xcs_dep $dir/aclocal.m4"
- test -f $dir/acsite.m4 && xc_dep="$xcs_dep $dir/acsite.m4"
- test x$c_dir = x"erts" && xcs_dep="$xcs_dep $dir/config.h.in"
- $MAKE -f $ERL_TOP/make/lazy_configure.mk \
- MAKE="$MAKE" TARGET=$TARGET \
- ERL_TOP=$ERL_TOP \
- CONFIGURE_DIR=$dir \
- lazy_configure_clean
- echo "=== Done cleaning configure in $dir"
- echo ""
- fi
- done
-
-}
-
-do_lazy_configure_target_clean ()
-{
- setup_make
- if [ "x$OVERRIDE_TARGET" != "x" -a "x$OVERRIDE_TARGET" != "xwin32" ]; then
- echo "Not supported for cross compilation" >&2
- exit 1
- fi
- for c_dir in $AUTOCONF_SUBDIRS; do
- if test -f $ERL_TOP/$c_dir/configure.in; then
- dir=$ERL_TOP/$c_dir
- echo ""
- echo "=== Begin target cleaning configure in $dir"
- xc_dep= ;
- xcs_dep= ;
- test -d $dir/$TARGET || mkdir $dir/$TARGET
- test -f $dir/aclocal.m4 && xc_dep="$xcs_dep $dir/aclocal.m4"
- test -f $dir/acsite.m4 && xc_dep="$xcs_dep $dir/acsite.m4"
- test x$c_dir = x"erts" && xcs_dep="$xcs_dep $dir/config.h.in"
- $MAKE -f $ERL_TOP/make/lazy_configure.mk \
- MAKE="$MAKE" TARGET=$TARGET \
- ERL_TOP=$ERL_TOP \
- CONFIGURE_DIR=$dir \
- lazy_configure_target_clean
- echo "=== Done target cleaning configure in $dir"
- echo ""
- fi
- done
-
-}
-
-
-
echo_setenv ()
{
case "$DAILY_BUILD_SCRIPT$SHELL" in
@@ -1075,11 +938,11 @@ do_update_prel_git ()
{
get_do_commit $1
setup_make
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET clean)
+ (cd "$ERL_TOP/erts/preloaded/src" && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET clean)
$MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET preloaded || exit 1
- (cd $ERL_TOP/erts/preloaded/src && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET copy)
+ (cd "$ERL_TOP/erts/preloaded/src" && $MAKE MAKE="$MAKE" BOOTSTRAP_ROOT=$BOOTSTRAP_ROOT TARGET=$TARGET copy)
if [ $do_commit = true ]; then
- git add -A $ERL_TOP/erts/preloaded/ebin/*.beam
+ git add -A "$ERL_TOP/erts/preloaded/ebin/*.beam"
git commit -m 'Update preloaded modules'
echo "Preloaded updated and commited."
else
@@ -1149,11 +1012,11 @@ do_debuginfo_win32 ()
(cd erts/emulator && $MAKE MAKE="$MAKE" TARGET=$TARGET FLAVOR=smp debug &&\
$MAKE MAKE="$MAKE" TARGET=$TARGET FLAVOR=plain debug) || exit 1
if [ -z "$1" ]; then
- RELDIR=$ERL_TOP/release/$TARGET
+ RELDIR="$ERL_TOP/release/$TARGET"
else
RELDIR="$1"
fi
- BINDIR=$ERL_TOP/bin/$TARGET
+ BINDIR="$ERL_TOP/bin/$TARGET"
EVSN=`grep '^VSN' erts/vsn.mk | sed 's,^VSN.*=[^0-9]*\([0-9].*\)$,@\1,g;s,^[^@].*,,g;s,^@,,g'`
for f in beam.debug.dll beam.debug.smp.dll beam.pdb beam.smp.pdb erl.pdb werl.pdb erlexec.pdb; do
if [ -f $BINDIR/$f ]; then
@@ -1166,7 +1029,7 @@ do_debuginfo_win32 ()
do_installer_win32 ()
{
setup_make
- installer_dir=$ERL_TOP/erts/etc/win32/nsis
+ installer_dir="$ERL_TOP/erts/etc/win32/nsis"
(cd $installer_dir; $MAKE MAKE="$MAKE" TARGET=$TARGET TESTROOT=$1 release) || exit 1
}
@@ -1210,7 +1073,7 @@ do_copy_primary_bootstrap ()
cp -f $lib_src/compiler/ebin/*.beam $bootstrap/lib/compiler/ebin
# bootstrap bin
- if [ $bootstrap_src_top != $ERL_TOP ]; then
+ if [ $bootstrap_src_top != "$ERL_TOP" ]; then
test -d $bootstrap/bin || mkdir -p $bootstrap/bin
cp -f $bootstrap_src_top/bin/* $bootstrap/bin
fi
@@ -1219,22 +1082,22 @@ do_copy_primary_bootstrap ()
do_save_bootstrap ()
{
- if [ ! -f $ERL_TOP/prebuilt.files ]; then
+ if [ ! -f "$ERL_TOP/prebuilt.files" ]; then
echo "This is not a pre-built source distribution" 1>&2
exit 1
fi
- if [ -d $ERL_TOP/bootstrap/lib ]; then
+ if [ -d "$ERL_TOP/bootstrap/lib" ]; then
echo "Bootstrap already exist" 1>&2
exit 1
fi
- do_copy_primary_bootstrap $ERL_TOP $ERL_TOP
+ do_copy_primary_bootstrap "$ERL_TOP" "$ERL_TOP"
}
do_remove_prebuilt_files ()
{
do_save_bootstrap
- for file in $ERL_TOP/`cat $ERL_TOP/prebuilt.files` ; do
+ for file in "$ERL_TOP"/`cat "$ERL_TOP/prebuilt.files"` ; do
rm -f $file
done
}
@@ -1243,7 +1106,7 @@ do_remove_prebuilt_files ()
check_erltop
-cd $ERL_TOP
+cd "$ERL_TOP"
determine_version_controller
@@ -1257,7 +1120,7 @@ unset ${erl_otp_flags}
# Target first guess, won't necessarily hold, may be changed for
# certain parameters.
if [ X"$TARGET" = X"" ]; then
- TARGET=`$ERL_TOP/erts/autoconf/config.guess`
+ TARGET=`"$ERL_TOP/erts/autoconf/config.guess"`
fi
BUILDSYS=$TARGET
@@ -1335,27 +1198,11 @@ case "$1" in
do_autoconf;
do_configure "$@";
do_boot;;
- lazy_setup)
- shift;
- if [ $minus_a_flag = true ]; then
- shift
- fi;
- do_lazy_configure "$@";
- do_boot;;
autoconf)
do_autoconf;;
configure)
shift;
do_configure "$@";;
- lazy_configure)
- shift;
- do_lazy_configure "$@";;
- lazy_configure_clean)
- shift;
- do_lazy_configure_clean;;
- lazy_configure_target_clean)
- shift;
- do_lazy_configure_target_clean;;
opt)
do_boot;;
plain|smp)
diff --git a/otp_versions.table b/otp_versions.table
index ccaa082a7a..523b3d94ab 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,7 +1,24 @@
+OTP-21.1.1 : compiler-7.2.6 eldap-1.2.6 erts-10.1.1 ssl-9.0.3 # asn1-5.0.7 common_test-1.16.1 crypto-4.3.3 debugger-4.2.6 dialyzer-3.3.1 diameter-2.1.6 edoc-0.9.4 erl_docgen-0.8.1 erl_interface-3.10.4 et-1.6.3 eunit-2.3.7 ftp-1.0.1 hipe-3.18.1 inets-7.0.2 jinterface-1.9.1 kernel-6.1 megaco-3.18.4 mnesia-4.15.5 observer-2.8.1 odbc-2.12.2 os_mon-2.4.6 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.2 reltool-0.7.7 runtime_tools-1.13.1 sasl-3.2.1 snmp-5.2.12 ssh-4.7.1 stdlib-3.6 syntax_tools-2.1.6 tftp-1.0.1 tools-3.0.1 wx-1.8.5 xmerl-1.3.18 :
+OTP-21.1 : asn1-5.0.7 common_test-1.16.1 compiler-7.2.5 crypto-4.3.3 debugger-4.2.6 dialyzer-3.3.1 diameter-2.1.6 edoc-0.9.4 eldap-1.2.5 erl_docgen-0.8.1 erl_interface-3.10.4 erts-10.1 et-1.6.3 eunit-2.3.7 ftp-1.0.1 hipe-3.18.1 inets-7.0.2 jinterface-1.9.1 kernel-6.1 megaco-3.18.4 mnesia-4.15.5 observer-2.8.1 odbc-2.12.2 os_mon-2.4.6 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.2 reltool-0.7.7 runtime_tools-1.13.1 sasl-3.2.1 snmp-5.2.12 ssh-4.7.1 ssl-9.0.2 stdlib-3.6 syntax_tools-2.1.6 tftp-1.0.1 tools-3.0.1 wx-1.8.5 xmerl-1.3.18 # :
+OTP-21.0.9 : compiler-7.2.4 erts-10.0.8 # asn1-5.0.6 common_test-1.16 crypto-4.3.2 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0.1 jinterface-1.9 kernel-6.0.1 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0.1 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.8 : erts-10.0.7 kernel-6.0.1 # asn1-5.0.6 common_test-1.16 compiler-7.2.3 crypto-4.3.2 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0.1 jinterface-1.9 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0.1 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.7 : erts-10.0.6 # asn1-5.0.6 common_test-1.16 compiler-7.2.3 crypto-4.3.2 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0.1 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0.1 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.6 : crypto-4.3.2 inets-7.0.1 ssl-9.0.1 # asn1-5.0.6 common_test-1.16 compiler-7.2.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 erts-10.0.5 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.5 : compiler-7.2.3 crypto-4.3.1 erts-10.0.5 # asn1-5.0.6 common_test-1.16 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
+OTP-21.0.4 : erts-10.0.4 # asn1-5.0.6 common_test-1.16 compiler-7.2.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0.3 : erts-10.0.3 # asn1-5.0.6 common_test-1.16 compiler-7.2.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6.1 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5.1 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0.2 : compiler-7.2.2 erts-10.0.2 public_key-1.6.1 stdlib-3.5.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0.1 : compiler-7.2.1 erts-10.0.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0 : asn1-5.0.6 common_test-1.16 compiler-7.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 erts-10.0 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 mnesia-4.15.4 observer-2.8 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 # megaco-3.18.3 odbc-2.12.1 snmp-5.2.11 :
+OTP-20.3.8.11 : erts-9.3.3.5 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.10 : eldap-1.2.3.1 erts-9.3.3.4 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.9 : compiler-7.1.5.2 # asn1-5.0.5.1 common_test-1.15.4 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.8 : inets-6.5.2.4 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.1 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.7 : crypto-4.2.2.2 mnesia-4.15.3.2 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.1 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.3 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.6 : inets-6.5.2.3 # asn1-5.0.5.1 common_test-1.15.4 compiler-7.1.5.1 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.1 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.1 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.2 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.5 : compiler-7.1.5.1 crypto-4.2.2.1 erts-9.3.3.3 mnesia-4.15.3.1 ssl-8.2.6.2 # asn1-5.0.5.1 common_test-1.15.4 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.4 : asn1-5.0.5.1 # common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 erts-9.3.3.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.2 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
+OTP-20.3.8.3 : erts-9.3.3.2 ic-4.4.4.2 inets-6.5.2.2 kernel-5.4.3.2 ssl-8.2.6.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2.1 et-1.6.1 eunit-2.3.5 hipe-3.17.1 jinterface-1.8.1 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.8.2 : erl_interface-3.10.2.1 erts-9.3.3.1 ic-4.4.4.1 kernel-5.4.3.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 inets-6.5.2.1 jinterface-1.8.1 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssh-4.6.9.1 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4.1 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.8.1 : inets-6.5.2.1 ssh-4.6.9.1 syntax_tools-2.1.4.1 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2 erts-9.3.3 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11 ssl-8.2.6 stdlib-3.4.5 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
OTP-20.3.8 : erts-9.3.3 snmp-5.2.11 # asn1-5.0.5 common_test-1.15.4 compiler-7.1.5 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4 edoc-0.9.2 eldap-1.2.3 erl_docgen-0.7.3 erl_interface-3.10.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4 inets-6.5.2 jinterface-1.8.1 kernel-5.4.3 megaco-3.18.3 mnesia-4.15.3 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 ssh-4.6.9 ssl-8.2.6 stdlib-3.4.5 syntax_tools-2.1.4 tools-2.11.2 wx-1.8.3 xmerl-1.3.16 :
@@ -33,6 +50,9 @@ OTP-20.0.3 : asn1-5.0.2 compiler-7.1.1 erts-9.0.3 ssh-4.5.1 # common_test-1.15.1
OTP-20.0.2 : asn1-5.0.1 erts-9.0.2 kernel-5.3.1 # common_test-1.15.1 compiler-7.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 inets-6.4 jinterface-1.8 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12.1 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 stdlib-3.4.1 syntax_tools-2.1.2 tools-2.10.1 wx-1.8.1 xmerl-1.3.15 :
OTP-20.0.1 : common_test-1.15.1 erts-9.0.1 runtime_tools-1.12.1 stdlib-3.4.1 tools-2.10.1 # asn1-5.0 compiler-7.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 eldap-1.2.2 erl_docgen-0.7 erl_interface-3.10 et-1.6 eunit-2.3.3 hipe-3.16 ic-4.4.2 inets-6.4 jinterface-1.8 kernel-5.3 megaco-3.18.2 mnesia-4.15 observer-2.4 odbc-2.12 orber-3.8.3 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 syntax_tools-2.1.2 wx-1.8.1 xmerl-1.3.15 :
OTP-20.0 : asn1-5.0 common_test-1.15 compiler-7.1 cosProperty-1.2.2 crypto-4.0 debugger-4.2.2 dialyzer-3.2 diameter-2.0 edoc-0.9 erl_docgen-0.7 erl_interface-3.10 erts-9.0 eunit-2.3.3 hipe-3.16 inets-6.4 jinterface-1.8 kernel-5.3 megaco-3.18.2 mnesia-4.15 observer-2.4 orber-3.8.3 parsetools-2.1.5 public_key-1.4.1 reltool-0.7.4 runtime_tools-1.12 sasl-3.0.4 snmp-5.2.6 ssh-4.5 ssl-8.2 stdlib-3.4 syntax_tools-2.1.2 tools-2.10 wx-1.8.1 xmerl-1.3.15 # cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosTime-1.2.2 cosTransactions-1.3.2 eldap-1.2.2 et-1.6 ic-4.4.2 odbc-2.12 os_mon-2.4.2 otp_mibs-1.1.1 :
+OTP-19.3.6.12 : eldap-1.2.2.1 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.6 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.4 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
+OTP-19.3.6.11 : erts-8.3.5.6 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.4 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
+OTP-19.3.6.10 : erts-8.3.5.5 syntax_tools-2.1.1.1 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.4 ssl-8.1.3.1.1 stdlib-3.3 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.9 : ssh-4.4.2.4 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.8 : ssh-4.4.2.3 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 kernel-5.2.0.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
OTP-19.3.6.7 : kernel-5.2.0.1 # asn1-4.0.4 common_test-1.14 compiler-7.0.4.1 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7.4 debugger-4.2.1 dialyzer-3.1.1 diameter-1.12.2 edoc-0.8.1 eldap-1.2.2 erl_docgen-0.6.1 erl_interface-3.9.3 erts-8.3.5.4 et-1.6 eunit-2.3.2 gs-1.6.2 hipe-3.15.4 ic-4.4.2 inets-6.3.9 jinterface-1.7.1 megaco-3.18.1 mnesia-4.14.3.1 observer-2.3.1 odbc-2.12 orber-3.8.2 os_mon-2.4.2 otp_mibs-1.1.1 parsetools-2.1.4 percept-0.9 public_key-1.4 reltool-0.7.3 runtime_tools-1.11.1 sasl-3.0.3 snmp-5.2.5 ssh-4.4.2.2 ssl-8.1.3.1.1 stdlib-3.3 syntax_tools-2.1.1 tools-2.9.1 typer-0.9.12 wx-1.8 xmerl-1.3.14 :
@@ -70,6 +90,7 @@ OTP-19.0.3 : inets-6.3.2 kernel-5.0.1 ssl-8.0.1 # asn1-4.0.3 common_test-1.12.2
OTP-19.0.2 : compiler-7.0.1 erts-8.0.2 stdlib-3.0.1 # asn1-4.0.3 common_test-1.12.2 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 dialyzer-3.0.1 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 inets-6.3.1 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 observer-2.2.1 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssh-4.3.1 ssl-8.0 syntax_tools-2.0 tools-2.8.5 typer-0.9.11 wx-1.7 xmerl-1.3.11 :
OTP-19.0.1 : dialyzer-3.0.1 erts-8.0.1 inets-6.3.1 observer-2.2.1 ssh-4.3.1 tools-2.8.5 # asn1-4.0.3 common_test-1.12.2 compiler-7.0 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssl-8.0 stdlib-3.0 syntax_tools-2.0 typer-0.9.11 wx-1.7 xmerl-1.3.11 :
OTP-19.0 : asn1-4.0.3 common_test-1.12.2 compiler-7.0 cosEvent-2.2.1 cosEventDomain-1.2.1 cosFileTransfer-1.2.1 cosNotification-1.2.2 cosProperty-1.2.1 cosTime-1.2.2 cosTransactions-1.3.2 crypto-3.7 debugger-4.2 dialyzer-3.0 diameter-1.12 edoc-0.7.19 eldap-1.2.2 erl_docgen-0.5 erl_interface-3.9 erts-8.0 et-1.6 eunit-2.3 gs-1.6.1 hipe-3.15.1 ic-4.4.1 inets-6.3 jinterface-1.7 kernel-5.0 megaco-3.18.1 mnesia-4.14 observer-2.2 odbc-2.11.2 orber-3.8.2 os_mon-2.4.1 otp_mibs-1.1.1 parsetools-2.1.2 percept-0.9 public_key-1.2 reltool-0.7.1 runtime_tools-1.10 sasl-3.0 snmp-5.2.3 ssh-4.3 ssl-8.0 stdlib-3.0 syntax_tools-2.0 tools-2.8.4 typer-0.9.11 wx-1.7 xmerl-1.3.11 # :
+OTP-18.3.4.10 : erts-7.3.1.5 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2.6 ssl-7.3.3.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.9 : ssh-4.2.2.6 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.4 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.8 : ssh-4.2.2.5 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.4 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssl-7.3.3.2 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
OTP-18.3.4.7 : ssl-7.3.3.2 # asn1-4.0.2 common_test-1.12.1.1 compiler-6.0.3.1 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2.1 cosProperty-1.2 cosTime-1.2.1 cosTransactions-1.3.1 crypto-3.6.3.1 debugger-4.1.2 dialyzer-2.9 diameter-1.11.2 edoc-0.7.18 eldap-1.2.1.1 erl_docgen-0.4.2 erl_interface-3.8.2 erts-7.3.1.4 et-1.5.1 eunit-2.2.13 gs-1.6 hipe-3.15 ic-4.4 inets-6.2.4.1 jinterface-1.6.1 kernel-4.2 megaco-3.18 mnesia-4.13.4 observer-2.1.2 odbc-2.11.1 orber-3.8.1 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1.1 percept-0.8.11 public_key-1.1.1 reltool-0.7 runtime_tools-1.9.3 sasl-2.7 snmp-5.2.2 ssh-4.2.2.4 stdlib-2.8 syntax_tools-1.7 test_server-3.10 tools-2.8.3 typer-0.9.10 webtool-0.9.1 wx-1.6.1 xmerl-1.3.10 :
@@ -102,6 +123,7 @@ OTP-18.0.3 : erts-7.0.3 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 co
OTP-18.0.2 : erts-7.0.2 runtime_tools-1.9.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 :
OTP-18.0.1 : erts-7.0.1 # asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 :
OTP-18.0 : asn1-4.0 common_test-1.11 compiler-6.0 cosEvent-2.2 cosEventDomain-1.2 cosFileTransfer-1.2 cosNotification-1.2 cosProperty-1.2 cosTime-1.2 cosTransactions-1.3 crypto-3.6 debugger-4.1 dialyzer-2.8 diameter-1.10 edoc-0.7.17 eldap-1.2 erl_docgen-0.4 erl_interface-3.8 erts-7.0 et-1.5.1 eunit-2.2.10 gs-1.6 hipe-3.12 ic-4.4 inets-6.0 jinterface-1.6 kernel-4.0 megaco-3.18 mnesia-4.13 observer-2.1 odbc-2.11 orber-3.8 os_mon-2.4 ose-1.1 otp_mibs-1.1 parsetools-2.1 percept-0.8.11 public_key-1.0 reltool-0.7 runtime_tools-1.9 sasl-2.5 snmp-5.2 ssh-4.0 ssl-7.0 stdlib-2.5 syntax_tools-1.7 test_server-3.9 tools-2.8 typer-0.9.9 webtool-0.9 wx-1.4 xmerl-1.3.8 # :
+OTP-17.5.6.10 : erts-6.4.1.7 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 diameter-1.9.2.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.2 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.6.9 : diameter-1.9.2.4 erts-6.4.1.6 ssl-6.0.1.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.6.8 : diameter-1.9.2.3 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.5 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
OTP-17.5.6.7 : diameter-1.9.2.2 # asn1-3.0.4 common_test-1.10.1 compiler-5.0.4 cosEvent-2.1.15 cosEventDomain-1.1.14 cosFileTransfer-1.1.16 cosNotification-1.1.21 cosProperty-1.1.17 cosTime-1.1.14 cosTransactions-1.2.14 crypto-3.5 debugger-4.0.3.1 dialyzer-2.7.4 edoc-0.7.16 eldap-1.1.1 erl_docgen-0.3.7 erl_interface-3.7.20 erts-6.4.1.5 et-1.5 eunit-2.2.9 gs-1.5.16 hipe-3.11.3 ic-4.3.6 inets-5.10.9 jinterface-1.5.12 kernel-3.2.0.1 megaco-3.17.3 mnesia-4.12.5 observer-2.0.4 odbc-2.10.22 orber-3.7.1 os_mon-2.3.1 ose-1.0.2 otp_mibs-1.0.10 parsetools-2.0.12 percept-0.8.10 public_key-0.23 reltool-0.6.6 runtime_tools-1.8.16.1 sasl-2.4.1 snmp-5.1.2 ssh-3.2.4 ssl-6.0.1.1 stdlib-2.4 syntax_tools-1.6.18 test_server-3.8.1 tools-2.7.2 typer-0.9.8 webtool-0.8.10 wx-1.3.3 xmerl-1.3.7 :
diff --git a/scripts/bundle-otp b/scripts/bundle-otp
index 0ffe7d8c77..aa1f166732 100755
--- a/scripts/bundle-otp
+++ b/scripts/bundle-otp
@@ -13,6 +13,9 @@ REPOSITORIES="otp,$TRAVIS_TAG corba,.*"
mkdir bundle
+## Turn off * expansion, needed for the .* regexp to work
+set -f
+
for repo in $REPOSITORIES; do
OLD_IFS=$IFS
IFS=','
@@ -22,13 +25,16 @@ for repo in $REPOSITORIES; do
git clone https://github.com/erlang/$1 $1
cd $1
echo $1 $2
- TAG=`git tag -l | grep -P "$2" | sort -V | tail -1`
+ TAG=`git tag -l | grep -P "^$2$" | sort -V | tail -1`
git checkout $TAG
SHA=`git rev-parse --verify HEAD`
rm -rf .git
echo "$1 $TAG $SHA" >> $OTP_META_FILE
done
+## Turn on * expansion
+set +f
+
cd $ERL_TOP/bundle/
tar czf $OTP_FILE *
diff --git a/scripts/diffable b/scripts/diffable
index 6a9792e857..532a7bb5c5 100755
--- a/scripts/diffable
+++ b/scripts/diffable
@@ -3,27 +3,30 @@
-mode(compile).
main(Args0) ->
- {Args,Opts} = opts(Args0, #{format=>asm,no_compile=>false}),
+ DefOpts = #{format=>asm,no_compile=>false,legacy=>false},
+ {Args,Opts} = opts(Args0, DefOpts),
case Args of
[OutDir] ->
do_compile(OutDir, Opts);
_ ->
- usage(),
- halt(1)
+ usage()
end.
usage() ->
S = "usage: otp-diffable-asm [OPTION] DIRECTORY\n\n"
"Options:\n"
" --asm Output to .S files (default)\n"
+ " --legacy-asm Output to legacy .S files\n"
" --dis Output to .dis files\n"
" --no-compile Disassemble from BEAM files (use with --dis)\n"
"\n"
"DESCRIPTION\n"
"\n"
- "Compile some applications from OTP (more than 700 modules) to either\n"
+ "Compile some applications from OTP (about 1000 modules) to either\n"
".S files or .dis files. The files are massaged to make them diff-friendly.\n"
"\n"
+ "The --legacy-asm options forces the output file to be in Latin1 encoding\n"
+ "and adds a latin1 encoding comment to the first line of the file.\n"
"EXAMPLES\n"
"\n"
"This example shows how the effectiveness of a compiler \n"
@@ -42,17 +45,27 @@ usage() ->
"# Hack ops.tab and/or one of the *instr.tab files.\n"
"$ scripts/diffable --dis --no-compile new\n"
"$ diff -u old new\n",
- io:put_chars(S).
-
-opts(["--asm"|Args], Opts) ->
- opts(Args, Opts#{format:=asm});
-opts(["--dis"|Args], Opts) ->
- opts(Args, Opts#{format:=dis});
-opts(["--no-compile"|Args], Opts) ->
- opts(Args, Opts#{format:=dis,no_compile:=true});
+ io:put_chars(S),
+ halt(1).
+
+opts(["--"++Opt|Args], Opts0) ->
+ Opts = opt(Opt, Opts0),
+ opts(Args, Opts);
opts(Args, Opts) ->
{Args,Opts}.
+opt("asm", Opts) ->
+ Opts#{format:=asm};
+opt("dis", Opts) ->
+ Opts#{format:=dis};
+opt("legacy-asm", Opts) ->
+ Opts#{format:=asm,legacy:=true};
+opt("no-compile", Opts) ->
+ Opts#{format:=dis,no_compile:=true};
+opt(Opt, _Opts) ->
+ io:format("Uknown option: --~ts\n\n", [Opt]),
+ usage().
+
do_compile(OutDir, Opts0) ->
Opts1 = Opts0#{outdir=>OutDir},
_ = filelib:ensure_dir(filename:join(OutDir, "dummy")),
@@ -197,109 +210,33 @@ get_beams([]) -> [].
%%% Generate renumbered .S files.
%%%
-compile_to_asm_fun(#{outdir:=OutDir}) ->
+compile_to_asm_fun(#{outdir:=OutDir}=Opts) ->
fun(File) ->
- compile_to_asm(File, OutDir)
+ Legacy = map_get(legacy, Opts),
+ compile_to_asm(File, OutDir, Legacy)
end.
-compile_to_asm({File,Opts}, OutDir) ->
- case compile:file(File, [to_asm,binary,report_errors|Opts]) of
+compile_to_asm({File,Opts}, OutDir, Legacy) ->
+ case compile:file(File, [diffable,{outdir,OutDir},report_errors|Opts]) of
+ {ok,_Mod} ->
+ case Legacy of
+ true ->
+ legacy_asm(OutDir, File);
+ false ->
+ ok
+ end;
error ->
- error;
- {ok,Mod,Asm0} ->
- {ok,Asm1} = beam_a:module(Asm0, []),
- Asm2 = renumber_asm(Asm1),
- {ok,Asm} = beam_z:module(Asm2, []),
- print_asm(Mod, OutDir, Asm)
+ error
end.
-print_asm(Mod, OutDir, Asm) ->
- S = atom_to_list(Mod) ++ ".S",
- Name = filename:join(OutDir, S),
- {ok,Fd} = file:open(Name, [write,raw,delayed_write]),
- ok = beam_listing(Fd, Asm),
- ok = file:close(Fd).
-
-renumber_asm({Mod,Exp,Attr,Fs0,NumLabels}) ->
- EntryLabels = maps:from_list(entry_labels(Fs0)),
- Fs = [fix_func(F, EntryLabels) || F <- Fs0],
- {Mod,Exp,Attr,Fs,NumLabels}.
-
-entry_labels(Fs) ->
- [{Entry,{Name,Arity}} || {function,Name,Arity,Entry,_} <- Fs].
-
-fix_func({function,Name,Arity,Entry0,Is0}, LabelMap0) ->
- Entry = maps:get(Entry0, LabelMap0),
- LabelMap = label_map(Is0, 1, LabelMap0),
- Is = replace(Is0, [], LabelMap),
- {function,Name,Arity,Entry,Is}.
-
-label_map([{label,Old}|Is], New, Map) ->
- case maps:is_key(Old, Map) of
- false ->
- label_map(Is, New+1, Map#{Old=>New});
- true ->
- label_map(Is, New, Map)
- end;
-label_map([_|Is], New, Map) ->
- label_map(Is, New, Map);
-label_map([], _New, Map) ->
- Map.
-
-replace([{label,Lbl}|Is], Acc, D) ->
- replace(Is, [{label,label(Lbl, D)}|Acc], D);
-replace([{test,Test,{f,Lbl},Ops}|Is], Acc, D) ->
- replace(Is, [{test,Test,{f,label(Lbl, D)},Ops}|Acc], D);
-replace([{test,Test,{f,Lbl},Live,Ops,Dst}|Is], Acc, D) ->
- replace(Is, [{test,Test,{f,label(Lbl, D)},Live,Ops,Dst}|Acc], D);
-replace([{select,I,R,{f,Fail0},Vls0}|Is], Acc, D) ->
- Vls = lists:map(fun ({f,L}) -> {f,label(L, D)};
- (Other) -> Other
- end, Vls0),
- Fail = label(Fail0, D),
- replace(Is, [{select,I,R,{f,Fail},Vls}|Acc], D);
-replace([{'try',R,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{'try',R,{f,label(Lbl, D)}}|Acc], D);
-replace([{'catch',R,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{'catch',R,{f,label(Lbl, D)}}|Acc], D);
-replace([{jump,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{jump,{f,label(Lbl, D)}}|Acc], D);
-replace([{loop_rec,{f,Lbl},R}|Is], Acc, D) ->
- replace(Is, [{loop_rec,{f,label(Lbl, D)},R}|Acc], D);
-replace([{loop_rec_end,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{loop_rec_end,{f,label(Lbl, D)}}|Acc], D);
-replace([{wait,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{wait,{f,label(Lbl, D)}}|Acc], D);
-replace([{wait_timeout,{f,Lbl},To}|Is], Acc, D) ->
- replace(Is, [{wait_timeout,{f,label(Lbl, D)},To}|Acc], D);
-replace([{bif,Name,{f,Lbl},As,R}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bif,Name,{f,label(Lbl, D)},As,R}|Acc], D);
-replace([{gc_bif,Name,{f,Lbl},Live,As,R}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{gc_bif,Name,{f,label(Lbl, D)},Live,As,R}|Acc], D);
-replace([{call,Ar,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{call,Ar,{f,label(Lbl,D)}}|Acc], D);
-replace([{make_fun2,{f,Lbl},U1,U2,U3}|Is], Acc, D) ->
- replace(Is, [{make_fun2,{f,label(Lbl, D)},U1,U2,U3}|Acc], D);
-replace([{bs_init,{f,Lbl},Info,Live,Ss,Dst}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_init,{f,label(Lbl, D)},Info,Live,Ss,Dst}|Acc], D);
-replace([{bs_put,{f,Lbl},Info,Ss}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{bs_put,{f,label(Lbl, D)},Info,Ss}|Acc], D);
-replace([{put_map=I,{f,Lbl},Op,Src,Dst,Live,List}|Is], Acc, D)
- when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Op,Src,Dst,Live,List}|Acc], D);
-replace([{get_map_elements=I,{f,Lbl},Src,List}|Is], Acc, D) when Lbl =/= 0 ->
- replace(Is, [{I,{f,label(Lbl, D)},Src,List}|Acc], D);
-replace([{recv_mark=I,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{I,{f,label(Lbl, D)}}|Acc], D);
-replace([{recv_set=I,{f,Lbl}}|Is], Acc, D) ->
- replace(Is, [{I,{f,label(Lbl, D)}}|Acc], D);
-replace([I|Is], Acc, D) ->
- replace(Is, [I|Acc], D);
-replace([], Acc, _) ->
- lists:reverse(Acc).
-
-label(Old, D) when is_integer(Old) ->
- maps:get(Old, D).
+legacy_asm(OutDir, Source) ->
+ ModName = filename:rootname(filename:basename(Source)),
+ File = filename:join(OutDir, ModName),
+ AsmFile = File ++ ".S",
+ {ok,Asm0} = file:read_file(AsmFile),
+ Asm1 = unicode:characters_to_binary(Asm0, utf8, latin1),
+ Asm = [<<"%% -*- encoding:latin-1 -*-\n">>|Asm1],
+ ok = file:write_file(AsmFile, Asm).
%%%
%%% Compile and disassemble the loaded code.
@@ -607,28 +544,3 @@ p_run_loop(Test, List, N, Refs0, Errors0) ->
Refs = Refs0 -- [Ref],
p_run_loop(Test, List, N, Refs, Errors)
end.
-
-%%%
-%%% Borrowed from beam_listing and tweaked.
-%%%
-
-beam_listing(Stream, {Mod,Exp,Attr,Code,NumLabels}) ->
- Head = ["%% -*- encoding:latin-1 -*-\n",
- io_lib:format("{module, ~p}. %% version = ~w\n",
- [Mod, beam_opcodes:format_number()]),
- io_lib:format("\n{exports, ~p}.\n", [Exp]),
- io_lib:format("\n{attributes, ~p}.\n", [Attr]),
- io_lib:format("\n{labels, ~p}.\n", [NumLabels])],
- ok = file:write(Stream, Head),
- lists:foreach(
- fun ({function,Name,Arity,Entry,Asm}) ->
- S = [io_lib:format("\n\n{function, ~w, ~w, ~w}.\n",
- [Name,Arity,Entry])|format_asm(Asm)],
- ok = file:write(Stream, S)
- end, Code).
-
-format_asm([{label,_}=I|Is]) ->
- [io_lib:format(" ~p", [I]),".\n"|format_asm(Is)];
-format_asm([I|Is]) ->
- [io_lib:format(" ~p", [I]),".\n"|format_asm(Is)];
-format_asm([]) -> [].
diff --git a/system/COPYRIGHT b/system/COPYRIGHT
index 5d47e0ca38..91cf0bbfb3 100644
--- a/system/COPYRIGHT
+++ b/system/COPYRIGHT
@@ -5,7 +5,7 @@ This software is subject to the following Copyrights and Licenses:
%CopyrightBegin%
-Copyright Ericsson AB 1997-2017. All Rights Reserved.
+Copyright Ericsson AB 1997-2018. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -41,12 +41,15 @@ PCRE LICENCE
PCRE is a library of functions to support regular expressions whose syntax
and semantics are as close as possible to those of the Perl 5 language.
-Release 7 of PCRE is distributed under the terms of the "BSD" licence, as
+Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
-directory, is distributed under the same terms as the software itself.
+directory, is distributed under the same terms as the software itself. The data
+in the testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
-included in the distribution is a set of C++ wrapper functions.
+included in the distribution is a set of C++ wrapper functions, and a
+just-in-time compiler that can be used to optimize pattern matching. These
+are both optional features that can be omitted when the library is built.
THE BASIC LIBRARY FUNCTIONS
@@ -59,7 +62,29 @@ Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
-Copyright (c) 1997-2008 University of Cambridge
+Copyright (c) 1997-2018 University of Cambridge
+All rights reserved.
+
+
+PCRE JUST-IN-TIME COMPILATION SUPPORT
+-------------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2010-2018 Zoltan Herczeg
+All rights reserved.
+
+
+STACK-LESS JUST-IN-TIME COMPILER
+--------------------------------
+
+Written by: Zoltan Herczeg
+Email local part: hzmester
+Emain domain: freemail.hu
+
+Copyright(c) 2009-2018 Zoltan Herczeg
All rights reserved.
@@ -68,7 +93,7 @@ THE C++ WRAPPER FUNCTIONS
Contributed by: Google Inc.
-Copyright (c) 2007-2008, Google Inc.
+Copyright (c) 2007-2012, Google Inc.
All rights reserved.
diff --git a/system/doc/design_principles/des_princ.xml b/system/doc/design_principles/des_princ.xml
index e21f2a7f4e..2bfb8eb3c7 100644
--- a/system/doc/design_principles/des_princ.xml
+++ b/system/doc/design_principles/des_princ.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -64,7 +64,7 @@
the supervisors are similar in structure. The only difference
between them is which child processes they supervise. Many
of the workers are servers in a server-client relation,
- finite-state machines, or event handlers such as error loggers.</p>
+ finite-state machines, or event handlers.</p>
<p><em>Behaviours</em> are formalizations of these common patterns.
The idea is to divide the code for a process in a generic part
(a behaviour module) and a specific part (a
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 16a901b3a5..07b4284cb8 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -44,28 +44,40 @@
<title>Event-Driven State Machines</title>
<p>
Established Automata Theory does not deal much with
- how a state transition is triggered,
+ how a <em>state transition</em> is triggered,
but assumes that the output is a function
of the input (and the state) and that they are
some kind of values.
</p>
<p>
For an Event-Driven State Machine, the input is an event
- that triggers a state transition and the output
- is actions executed during the state transition.
+ that triggers a <em>state transition</em> and the output
+ is actions executed during the <em>state transition</em>.
It can analogously to the mathematical model of a
- Finite-State Machine be described as
+ Finite State Machine be described as
a set of relations of the following form:
</p>
<pre>
State(S) x Event(E) -> Actions(A), State(S')</pre>
- <p>These relations are interpreted as follows:
+ <p>
+ These relations are interpreted as follows:
if we are in state <c>S</c> and event <c>E</c> occurs, we
are to perform actions <c>A</c> and make a transition to
state <c>S'</c>. Notice that <c>S'</c> can be equal to <c>S</c>
and that <c>A</c> can be empty.
</p>
<p>
+ In <c>gen_statem</c> we define
+ a <em>state change</em> as a <em>state transition</em>
+ in which the new state <c>S'</c> is different from
+ the current state <c>S</c>, where "different" means
+ Erlang's strict inequality: <c>=/=</c>
+ also know as "does not match".
+ During a <em>state changes</em>,
+ <c>gen_statem</c> does more things
+ than during other <em>state transitions</em>.
+ </p>
+ <p>
As <c>A</c> and <c>S'</c> depend only on
<c>S</c> and <c>E</c>, the kind of state machine described
here is a Mealy machine
@@ -95,8 +107,8 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<list type="bulleted">
<item>
Co-located callback code for each state,
- regardless of
- <seealso marker="#Event Types">Event Type</seealso>
+ for all
+ <seealso marker="#Event Types"><em>Event Types</em></seealso>
(such as <em>call</em>, <em>cast</em> and <em>info</em>)
</item>
<item>
@@ -114,13 +126,13 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</item>
<item>
<seealso marker="#State Enter Calls">
- State Enter Calls
+ <em>State Enter Calls</em>
</seealso>
(callback on state entry co-located with the rest
of each state's callback code)
</item>
<item>
- Easy-to-use timeouts
+ Easy-to-use time-outs
(<seealso marker="#State Time-Outs">State Time-Outs</seealso>,
<seealso marker="#Event Time-Outs">Event Time-Outs</seealso>
and
@@ -152,11 +164,11 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<marker id="Callback Module" />
<title>Callback Module</title>
<p>
- The callback module contains functions that implement
+ The <em>callback module</em> contains functions that implement
the state machine.
When an event occurs,
the <c>gen_statem</c> behaviour engine
- calls a function in the callback module with the event,
+ calls a function in the <em>callback module</em> with the event,
current state and server data.
This function performs the actions for this event,
and returns the new state and server data
@@ -166,7 +178,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
The behaviour engine holds the state machine state,
server data, timer references, a queue of posponed messages
and other metadata. It receives all process messages,
- handles the system messages, and calls the callback module
+ handles the system messages, and calls the <em>callback module</em>
with machine specific events.
</p>
</section>
@@ -177,7 +189,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<marker id="Callback Modes" />
<title>Callback Modes</title>
<p>
- The <c>gen_statem</c> behavior supports two callback modes:
+ The <c>gen_statem</c> behavior supports two <em>callback modes</em>:
</p>
<taglist>
<tag>
@@ -202,31 +214,33 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</item>
</taglist>
<p>
- The callback mode is selected at server start
+ The <em>callback mode</em> is selected at server start
and may be changed with a code upgrade/downgrade.
</p>
<p>
See the section
- <seealso marker="#Event Handler">Event Handler</seealso>
+ <seealso marker="#State Callback"><em>State Callback</em></seealso>
that describes the event handling callback function(s).
</p>
<p>
- The callback mode is selected by implementing
+ The <em>callback mode</em> is selected by implementing
a mandatory callback function
<seealso marker="stdlib:gen_statem#Module:callback_mode/0">
<c>Module:callback_mode()</c>
</seealso>
- that returns one of the callback modes.
+ that returns one of the <em>callback modes</em>.
</p>
<p>
The
<seealso marker="stdlib:gen_statem#Module:callback_mode/0">
<c>Module:callback_mode()</c>
</seealso>
- function may also return a list containing the callback mode
+ function may also return a list containing the <em>callback mode</em>
and the atom <c>state_enter</c> in which case
- <seealso marker="#State Enter Calls">State Enter Calls</seealso>
- are activated for the callback mode.
+ <seealso marker="#State Enter Calls">
+ <em>state enter calls</em>
+ </seealso>
+ are activated for the <em>callback mode</em>.
</p>
<section>
@@ -237,11 +251,11 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
it is the one most like <c>gen_fsm</c>.
But if you do not want the restriction that the state
must be an atom, or if you do not want to write
- one event handler function per state; please read on...
+ one <em>state callback</em> function per state; please read on...
</p>
<p>
The two
- <seealso marker="#Callback Modes">Callback Modes</seealso>
+ <seealso marker="#Callback Modes"><em>callback modes</em></seealso>
give different possibilities and restrictions,
with one common goal:
to handle all possible combinations of events and states.
@@ -257,7 +271,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
With <c>state_functions</c>, you are restricted to use
atom-only states, and the <c>gen_statem</c> engine
branches depending on state name for you.
- This encourages the callback module to co-locate
+ This encourages the <em>callback module</em> to co-locate
the implementation of all event actions particular
to one state in the same place in the code,
hence to focus on one state at the time.
@@ -302,11 +316,12 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<!-- =================================================================== -->
<section>
- <marker id="Event Handler" />
- <title>Event Handler</title>
+ <marker id="State Callback" />
+ <title>State Callback</title>
<p>
- Which callback function that handles an event
- depends on the callback mode:
+ The <em>state callback</em> is the callback function
+ that handles an event in the current state,
+ and which function that is depends on the <em>callback mode</em>:
</p>
<taglist>
<tag><c>state_functions</c></tag>
@@ -329,7 +344,9 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
<p>
See section
- <seealso marker="#One Event Handler">One Event Handler</seealso>
+ <seealso marker="#One State Callback">
+ <em>One State Callback</em>
+ </seealso>
for an example.
</p>
</item>
@@ -338,15 +355,17 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
The state is either the name of the function itself or an argument to it.
The other arguments are the <c>EventType</c> described in section
<seealso marker="#Event Types">Event Types</seealso>,
- the event dependent <c>EventContent</c>, and the current server <c>Data</c>.
+ the event dependent <c>EventContent</c>,
+ and the current server <c>Data</c>.
</p>
<p>
- State enter calls are also handled by the event handler and have
- slightly different arguments. See the section
+ <em>State enter calls</em> are also handled by the event handler
+ and have slightly different arguments. See section
<seealso marker="#State Enter Calls">State Enter Calls</seealso>.
</p>
<p>
- The event handler return values are defined in the description of
+ The <em>state callback</em> return values
+ are defined in the description of
<seealso marker="stdlib:gen_statem#Module:StateName/3">
<c>Module:StateName/3</c>
</seealso>
@@ -361,24 +380,29 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<item>
<p>
Set next state and update the server data.
- If the <c>Actions</c> field is used, execute state transition actions.
- An empty <c>Actions</c> list is equivalent to not returning the field.
+ If the <c>Actions</c> field is used,
+ execute <em>transition actions</em>.
+ An empty <c>Actions</c> list is equivalent to
+ not returning the field.
</p>
<p>
See section
- <seealso marker="#State Transition Actions">
- State Transition Actions
+ <seealso marker="#Transition Actions">
+ <em>Transition Actions</em>
</seealso>
for a list of possible
- state transition actions.
+ <em>transition actions</em>.
</p>
<p>
- If <c>NextState =/= State</c> the state machine changes
- to a new state. A
+ If <c>NextState =/= State</c> this is a <em>state change</em>
+ so the extra things <c>gen_statem</c> does are: the event queue
+ is restarted from the oldest
+ <seealso marker="#Postponing Events">postponed event</seealso>,
+ any current
+ <seealso marker="#State Time-Outs">state time-out</seealso>
+ is cancelled, and a
<seealso marker="#State Enter Calls">state enter call</seealso>
- is performed if enabled and all
- <seealso marker="#Postponing Events">postponed events</seealso>
- are retried.
+ is performed, if enabled.
</p>
</item>
<tag>
@@ -388,7 +412,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<item>
<p>
Same as the <c>next_state</c> values with
- <c>NextState =:= State</c>, that is, no state change.
+ <c>NextState =:= State</c>, that is, no <em>state change</em>.
</p>
</item>
<tag>
@@ -414,9 +438,16 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<seealso marker="#State Enter Calls">
State Enter Calls
</seealso>
- are enabled, repeat the state enter call
+ are enabled, repeat the <em>state enter call</em>
as if this state was entered again.
</p>
+ <p>
+ If these return values are used from a
+ <em>state enter call</em> the <c>OldState</c> does not change,
+ but if used from an event handling <em>state callback</em>
+ the new <em>state enter call's</em> <c>OldState</c>
+ will be the current state.
+ </p>
</item>
<tag>
<c>{stop, Reason, NewData}</c><br />
@@ -435,7 +466,10 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<item>
<p>
Same as the <c>stop</c> values, but first execute the given
- state transition actions that may only be reply actions.
+ <seealso marker="#Transition Actions">
+ <em>transition actions</em>
+ </seealso>
+ that may only be reply actions.
</p>
</item>
</taglist>
@@ -449,8 +483,8 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<c>Module:init(Args)</c>
</seealso>
callback function is called before any
- <seealso marker="#Event Handler">Event Handler</seealso>
- is called. This function behaves like an event handler
+ <seealso marker="#State Callback"><em>state callback</em></seealso>
+ is called. This function behaves like an <em>state callback</em>
function, but gets its only argument <c>Args</c> from
the <c>gen_statem</c>
<seealso marker="stdlib:gen_statem#start/3">
@@ -474,8 +508,8 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<!-- =================================================================== -->
<section>
- <marker id="State Transition Actions" />
- <title>State Transition Actions</title>
+ <marker id="Transition Actions" />
+ <title>Transition Actions</title>
<p>
In the first section
<seealso marker="#Event-Driven State Machines">
@@ -483,13 +517,13 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
actions were mentioned as a part of
the general state machine model. These general actions
- are implemented with the code that callback module
+ are implemented with the code that <em>callback module</em>
<c>gen_statem</c> executes in an event-handling
callback function before returning
to the <c>gen_statem</c> engine.
</p>
<p>
- There are more specific state-transition actions
+ There are more specific <em>transition actions</em>
that a callback function can command the <c>gen_statem</c>
engine to do after the callback function return.
These are commanded by returning a list of
@@ -500,7 +534,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
from the
<seealso marker="stdlib:gen_statem#Module:StateName/3">callback function</seealso>.
- These are the possible state transition actions:
+ These are the possible <em>transition actions</em>:
</p>
<taglist>
<tag>
@@ -512,7 +546,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</tag>
<item>
If set postpone the current event, see section
- <seealso marker="#Postponing Events">Postponing Events</seealso>
+ <seealso marker="#Postponing Events">Postponing Events</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-hibernate">
@@ -523,41 +557,44 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</tag>
<item>
If set hibernate the <c>gen_statem</c>, treated in section
- <seealso marker="#Hibernation">Hibernation</seealso>
+ <seealso marker="#Hibernation">Hibernation</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-state_timeout">
- <c>{state_timeout, Time}</c>
+ <c>{state_timeout, EventContent, Time}</c>
</seealso>
<br />
- <c>{state_timeout, Time, Opts}</c>
+ <c>{state_timeout, EventContent, Time, Opts}</c>
</tag>
<item>
- Start a state time-out, read more in section
- <seealso marker="#State Time-Outs">State Time-Outs</seealso>
+ Start a state time-out, read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#State Time-Outs">State Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-generic_timeout">
- <c>{{timeout, Name}, Time}</c>
+ <c>{{timeout, Name}, EventContent, Time}</c>
</seealso>
<br />
- <c>{{timeout, Name}, Time, Opts}</c>
+ <c>{{timeout, Name}, EventContent, Time, Opts}</c>
</tag>
<item>
- Start a generic time-out, read more in section
- <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>
+ Start a generic time-out, read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-event_timeout">
- <c>{timeout, Time}</c>
+ <c>{timeout, EventContent, Time}</c>
</seealso>
<br />
- <c>{timeout, Time, Opts}</c><br />
+ <c>{timeout, EventContent, Time, Opts}</c><br />
<c>Time</c>
</tag>
<item>
- Start an event time-out, see more in section
- <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>
+ Start an event time-out, see more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-reply_action">
@@ -566,7 +603,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</tag>
<item>
Reply to a caller, mentioned at the end of section
- <seealso marker="#All State Events">All State Events</seealso>
+ <seealso marker="#All State Events">All State Events</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-action">
@@ -575,7 +612,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</tag>
<item>
Generate the next event to handle, see section
- <seealso marker="#Inserted Events">Inserted Events</seealso>
+ <seealso marker="#Inserted Events">Inserted Events</seealso>.
</item>
</taglist>
<p>
@@ -596,13 +633,13 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<title>Event Types</title>
<p>
Events are categorized in different
- <seealso marker="stdlib:gen_statem#type-event_type">event types</seealso>.
+ <seealso marker="stdlib:gen_statem#type-event_type"><em>event types</em></seealso>.
Events of all types are for a given state
handled in the same callback function, and that function gets
<c>EventType</c> and <c>EventContent</c> as arguments.
</p>
<p>
- The following is a complete list of event types and where
+ The following is a complete list of <em>event types</em> and where
they come from:
</p>
<taglist>
@@ -624,7 +661,7 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
Generated by
<seealso marker="stdlib:gen_statem#call/2"><c>gen_statem:call</c></seealso>,
where <c>From</c> is the reply address to use
- when replying either through the state transition action
+ when replying either through the <em>transition action</em>
<c>{reply,From,Msg}</c> or by calling
<seealso marker="stdlib:gen_statem#reply/1"><c>gen_statem:reply</c></seealso>.
</item>
@@ -643,11 +680,13 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
</tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-state_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{state_timeout,Time,EventContent}</c>
</seealso>
- state timer timing out.
+ state timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#State Time-Outs">State Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-timeout_event_type">
@@ -655,11 +694,13 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
</tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{{timeout,Name},Time,EventContent}</c>
</seealso>
- generic timer timing out.
+ generic timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-timeout_event_type">
@@ -667,12 +708,14 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
</tag>
<item>
- Generated by state transition action
- <seealso marker="stdlib:gen_statem#type-event_timeout">
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-timeout_action">
<c>{timeout,Time,EventContent}</c>
</seealso>
(or its short form <c>Time</c>)
- event timer timing out.
+ event timer timing out. Read more in sections
+ <seealso marker="#Time-Outs">Time-Outs</seealso> and
+ <seealso marker="#Event Time-Outs">Event Time-Outs</seealso>.
</item>
<tag>
<seealso marker="stdlib:gen_statem#type-event_type">
@@ -680,10 +723,10 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</seealso>
</tag>
<item>
- Generated by state transition
- <seealso marker="stdlib:gen_statem#type-action">action</seealso>
- <c>{next_event,internal,EventContent}</c>.
- All event types above can also be generated using
+ Generated by <em>transition action</em>
+ <seealso marker="stdlib:gen_statem#type-enter_action"><c>{next_event,internal,EventContent}</c></seealso>.
+ All <em>event types</em> above can also be generated using
+ the <c>next_event</c> action:
<c>{next_event,EventType,EventContent}</c>.
</item>
</taglist>
@@ -696,14 +739,14 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
<title>State Enter Calls</title>
<p>
The <c>gen_statem</c> behavior can if this is enabled,
- regardless of callback mode,
+ regardless of <em>callback mode</em>,
automatically
<seealso marker="stdlib:gen_statem#type-state_enter">
call the state callback
</seealso>
with special arguments whenever the state changes
so you can write state enter actions
- near the rest of the state transition rules.
+ near the rest of the <em>state transition</em> rules.
It typically looks like this:
</p>
<pre>
@@ -714,36 +757,140 @@ StateName(EventType, EventContent, Data) ->
... code for actions here ...
{next_state, NewStateName, NewData}.</pre>
<p>
- Since the state enter call is not an event there are restrictions
+ Since the <em>state enter call</em> is not an event there are restrictions
on the allowed return value and
<seealso marker="#State Transition Actions">State Transition Actions</seealso>.
You may not change the state,
<seealso marker="#Postponing Events">postpone</seealso>
this non-event, or
- <seealso marker="#Inserted Events">insert events</seealso>.
+ <seealso marker="#Inserted Events">insert any events</seealso>.
</p>
<p>
- The first state that is entered will get a state enter call
+ The first state that is entered
+ will get a <em>state enter call</em>
with <c>OldState</c> equal to the current state.
</p>
<p>
- You may repeat the state enter call using the <c>{repeat_state,...}</c>
+ You may repeat the <em>state enter call</em>
+ using the <c>{repeat_state,...}</c>
return value from the
- <seealso marker="#Event Handler">Event Handler</seealso>.
+ <seealso marker="#State Callback">state callback</seealso>.
In this case <c>OldState</c> will also be equal to the current state.
</p>
<p>
Depending on how your state machine is specified,
- this can be a very useful feature,
- but it forces you to handle the state enter calls in all states.
+ this can be a very useful feature, but it forces you to handle
+ the <em>state enter calls</em> in all states.
See also the
<seealso marker="#State Enter Actions">
State Enter Actions
</seealso>
- chapter.
+ section.
+ </p>
+ </section>
+
+<!-- =================================================================== -->
+
+ <section>
+ <marker id="Time-Outs" />
+ <title>Time-outs</title>
+ <p>
+ Time-outs in <c>gen_statem</c> are started from a
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
+ during a state transition that is when exiting from the
+ <seealso marker="#State Callback"><em>state callback</em></seealso>.
+ </p>
+ <p>
+ There are 3 types of time-outs in <c>gen_statem</c>:
+ </p>
+ <taglist>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-state_timeout">
+ <c>state_timeout</c>
+ </seealso>
+ </tag>
+ <item>
+ There is one
+ <seealso marker="#State Time-Outs">State Time-Out</seealso>
+ that is automatically cancelled by a <em>state change</em>.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-generic_timeout">
+ <c>{timeout, Name}</c>
+ </seealso>
+ </tag>
+ <item>
+ There are any number of
+ <seealso marker="#Generic Time-Outs">Generic Time-Outs</seealso>
+ differing by their <c>Name</c>.
+ They have no automatic cancelling.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-event_timeout">
+ <c>timeout</c>
+ </seealso>
+ </tag>
+ <item>
+ There is one
+ <seealso marker="#Event Time-Outs">Event Time-Out</seealso>
+ that is automatically cancelled by any event.
+ Note that
+ <seealso marker="#Postponing Events">postponed </seealso>
+ and
+ <seealso marker="#Inserted Events">inserted</seealso>
+ events cancel this timeout just as external events.
+ </item>
+ </taglist>
+ <p>
+ When a time-out is started any running time-out with the same tag,
+ <c>state_timeout</c>, <c>{timeout, Name}</c> or <c>timeout</c>,
+ is cancelled, that is the time-out is restarted with the new time.
+ </p>
+ <p>
+ All time-outs has got an <c>EventContent</c> that is part of the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
+ that starts the time-out.
+ Different <c>EventContent</c>s does not create different time-outs.
+ The <c>EventContent</c> is delivered to the
+ <seealso marker="#State Callback"><em>state callback</em></seealso>
+ when the time-out expires.
</p>
+ <section>
+ <marker id="Cancelling a Time-Out" />
+ <title>Cancelling a Time-Out</title>
+ <p>
+ If a time-out is started with the time <c>infinity</c> it will
+ never time out, in fact it will not even be started, and any
+ running time-out with the same tag will be cancelled.
+ The <c>EventContent</c> will in this case be ignored,
+ so why not set it to <c>undefined</c>.
+ </p>
+ </section>
+ <section>
+ <marker id="Time-Out Zero" />
+ <title>Time-Out Zero</title>
+ <p>
+ If a time-out is started with the time <c>0</c> it will
+ actually not be started. Instead the time-out event will
+ immediately be inserted to be processed after any events
+ already enqueued, and before any not yet received external events.
+ Note that some time-outs are automatically cancelled
+ so if you for example combine
+ <seealso marker="#Postponing Events">postponing</seealso>
+ an event in a <em>state change</em> with starting an
+ <seealso marker="#Event Time-Outs">event time-out</seealso>
+ with time <c>0</c> there will be no timeout event inserted
+ since the event time-out is cancelled by the postponed
+ event that is delivered due to the state change.
+ </p>
+ </section>
</section>
+
<!-- =================================================================== -->
<section>
@@ -765,7 +912,7 @@ StateName(EventType, EventContent, Data) ->
</image>
<p>
This code lock state machine can be implemented using
- <c>gen_statem</c> with the following callback module:
+ <c>gen_statem</c> with the following <em>callback module</em>:
</p>
<code type="erl"><![CDATA[
-module(code_lock).
@@ -868,7 +1015,8 @@ start_link(Code) ->
<item>
<p>
The second argument, <c>?MODULE</c>, is the name of
- the callback module, that is, the module where the callback
+ the <em>callback module</em>, that is,
+ the module where the callback
functions are located, which is this module.
</p>
<p>
@@ -935,7 +1083,7 @@ init(Code) ->
<seealso marker="stdlib:gen_statem#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
selects the
<seealso marker="#Callback Modes"><c>CallbackMode</c></seealso>
- for the callback module, in this case
+ for the <em>callback module</em>, in this case
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>state_functions</c></seealso>.
That is, each state has got its own handler function:
</p>
@@ -1051,11 +1199,11 @@ open(state_timeout, lock, Data) ->
]]></code>
<p>
The timer for a state time-out is automatically cancelled
- when the state machine changes states. You can restart
- a state time-out by setting it to a new time, which cancels
- the running timer and starts a new. This implies that
- you can cancel a state time-out by restarting it with
- time <c>infinity</c>.
+ when the state machine does a <em>state change</em>.
+ You can restart a state time-out by setting it to a new time,
+ which cancels the running timer and starts a new.
+ This implies that you can cancel a state time-out
+ by restarting it with time <c>infinity</c>.
</p>
</section>
@@ -1137,7 +1285,7 @@ open(...) -> ... ;
care about what it is.
</p>
<p>
- If the common event handler needs to know the current state
+ If the common <em>state callback</em> needs to know the current state
a function <c>handle_common/4</c> can be used instead:
</p>
<code type="erl"><![CDATA[
@@ -1149,12 +1297,12 @@ open(...) -> ... ;
<!-- =================================================================== -->
<section>
- <marker id="One Event Handler" />
- <title>One Event Handler</title>
+ <marker id="One State Callback" />
+ <title>One State Callback</title>
<p>
If
<seealso marker="#Callback Modes">
- Callback Mode
+ <em>callback mode</em>
</seealso>
<c>handle_event_function</c> is used,
all events are handled in
@@ -1289,7 +1437,10 @@ stop() ->
You get either an event or a time-out, but not both.
</p>
<p>
- It is ordered by the state transition action
+ It is ordered by the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
+ </seealso>
<c>{timeout,Time,EventContent}</c>, or just an integer <c>Time</c>,
even without the enclosing actions list
(the latter is a form inherited from <c>gen_fsm</c>.
@@ -1315,7 +1466,7 @@ locked(
]]></code>
<p>
Whenever we receive a button event we start an event time-out
- of 30 seconds, and if we get an event type <c>timeout</c>
+ of 30 seconds, and if we get an <em>event type</em> of <c>timeout</c>
we reset the remaining code sequence.
</p>
<p>
@@ -1327,7 +1478,7 @@ locked(
</p>
<p>
Note that an event time-out does not work well with
- when you have for example a status call as in
+ when you have for example a status call as in section
<seealso marker="#All State Events">All State Events</seealso>,
or handle unknown events, since all kinds of events
will cancel the event time-out.
@@ -1383,14 +1534,14 @@ open(cast, {button,_}, Data) ->
]]></code>
<p>
Specific generic time-outs can just as
- <seealso marker="#State Time-Outs">State Time-Outs</seealso>
+ <seealso marker="#State Time-Outs">state time-outs</seealso>
be restarted or cancelled
by setting it to a new time or <c>infinity</c>.
</p>
<p>
- In this particular case we do not need to cancel the timeout
- since the timeout event is the only possible reason to
- change the state from <c>open</c> to <c>locked</c>.
+ In this particular case we do not need to cancel the time-out
+ since the time-out event is the only possible reason to
+ do a <em>state change</em> from <c>open</c> to <c>locked</c>.
</p>
<p>
Instead of bothering with when to cancel a time-out,
@@ -1410,7 +1561,7 @@ open(cast, {button,_}, Data) ->
<seealso marker="erts:erlang#start_timer/4"><c>erlang:start_timer/3,4</c></seealso>.
Most time-out tasks can be performed with the
time-out features in <c>gen_statem</c>,
- but an example of one that can not is if you should need
+ but an example of one that cannot is if you should need
the return value from
<seealso marker="erts:erlang#cancel_timer/2"><c>erlang:cancel_timer(Tref)</c></seealso>, that is; the remaining time of the timer.
</p>
@@ -1442,7 +1593,7 @@ open(cast, {button,_}, Data) ->
]]></code>
<p>
Removing the <c>timer</c> key from the map when we
- change to state <c>locked</c> is not strictly
+ do a <em>state change</em> to <c>locked</c> is not strictly
necessary since we can only get into state <c>open</c>
with an updated <c>timer</c> map value. But it can be nice
to not have outdated values in the state <c>Data</c>!
@@ -1474,13 +1625,13 @@ open(cast, {button,_}, Data) ->
<p>
If you want to ignore a particular event in the current state
and handle it in a future state, you can postpone the event.
- A postponed event is retried after the state has
- changed, that is, <c>OldState =/= NewState</c>.
+ A postponed event is retried after a <em>state change</em>,
+ that is, <c>OldState =/= NewState</c>.
</p>
<p>
- Postponing is ordered by the state transition
- <seealso marker="#State Transition Actions">
- State Transition Action
+ Postponing is ordered by the
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
</seealso>
<c>postpone</c>.
</p>
@@ -1496,7 +1647,8 @@ open(cast, {button,_}, Data) ->
...
]]></code>
<p>
- Since a postponed event is only retried after a state change,
+ Since a postponed event is only retried
+ after a <em>state change</em>,
you have to think about where to keep a state data item.
You can keep it in the server <c>Data</c>
or in the <c>State</c> itself,
@@ -1505,7 +1657,7 @@ open(cast, {button,_}, Data) ->
(see section
<seealso marker="#Complex State">Complex State</seealso>)
with
- <seealso marker="#Callback Modes">Callback Mode</seealso>
+ <seealso marker="#Callback Modes"><em>callback mode</em></seealso>
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>.
If a change in the value changes the set of events that is handled,
then the value should be kept in the State.
@@ -1606,17 +1758,17 @@ do_unlock() ->
<seealso marker="stdlib:sys"><c>sys</c></seealso>
compatible behaviors must respond to system messages and therefore
do that in their engine receive loop,
- passing non-system messages to the callback module.
+ passing non-system messages to the <em>callback module</em>.
</p>
<p>
The
- <seealso marker="#State Transition Actions">
- State Transition Action
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
</seealso>
<c>postpone</c> is designed to model
selective receives. A selective receive implicitly postpones
any not received events, but the <c>postpone</c>
- state transition action explicitly postpones one received event.
+ <em>transition action</em> explicitly postpones one received event.
</p>
<p>
Both mechanisms have the same theoretical
@@ -1638,14 +1790,17 @@ do_unlock() ->
(described in the next section), especially if just
one or a few states has got state enter actions,
this is a perfect use case for the built in
- <seealso marker="#State Enter Calls">State Enter Calls</seealso>.
+ <seealso marker="#State Enter Calls"><em>state enter calls</em></seealso>.
</p>
<p>
You return a list containing <c>state_enter</c> from your
- <seealso marker="stdlib:gen_statem#Module:callback_mode/0"><c>callback_mode/0</c></seealso>
+ <seealso marker="stdlib:gen_statem#Module:callback_mode/0">
+ <c>callback_mode/0</c>
+ </seealso>
function and the <c>gen_statem</c> engine will call your
- state callback once with the arguments
- <c>(enter, OldState, ...)</c> whenever the state changes.
+ <em>state callback</em> once with an event
+ <c>(enter, OldState, ...)</c>
+ whenever it does a <em>state change</em>.
Then you just need to handle these event-like calls in all states.
</p>
<code type="erl"><![CDATA[
@@ -1700,8 +1855,8 @@ open(state_timeout, lock, Data) ->
It can sometimes be beneficial to be able to generate events
to your own state machine.
This can be done with the
- <seealso marker="#State Transition Actions">
- State Transition Action
+ <seealso marker="#Transition Actions">
+ <em>transition action</em>
</seealso>
<c>{next_event,EventType,EventContent}</c>.
</p>
@@ -1731,11 +1886,9 @@ open(state_timeout, lock, Data) ->
</p>
<p>
A variant of this is to use a
- <seealso marker="#Complex State">
- Complex State
- </seealso>
+ <seealso marker="#Complex State">complex state</seealso>
with
- <seealso marker="#One Event Handler">One Event Handler</seealso>.
+ <seealso marker="#One State Callback"><em>one state callback</em></seealso>.
The state is then modeled with for example a tuple
<c>{MainFSMState,SubFSMState}</c>.
</p>
@@ -1795,7 +1948,7 @@ open(internal, {button,_}, Data) ->
<title>Example Revisited</title>
<p>
This section includes the example after most of the mentioned
- modifications and some more using state enter calls,
+ modifications and some more using <em>state enter calls</em>,
which deserves a new state diagram:
</p>
<!-- The image is edited with dia in a .dia file,
@@ -1920,7 +2073,8 @@ terminate(_Reason, State, _Data) ->
This section describes what to change in the example
to use one <c>handle_event/4</c> function.
The previously used approach to first branch depending on event
- does not work that well here because of the state enter calls,
+ does not work that well here
+ because of the <em>state enter calls</em>,
so this example first branches depending on state:
</p>
<code type="erl"><![CDATA[
@@ -2059,7 +2213,7 @@ format_status(Opt, [_PDict,State,Data]) ->
<marker id="Complex State" />
<title>Complex State</title>
<p>
- The callback mode
+ The <em>callback mode</em>
<seealso marker="stdlib:gen_statem#type-callback_mode"><c>handle_event_function</c></seealso>
enables using a non-atom state as described in section
<seealso marker="#Callback Modes">Callback Modes</seealso>,
@@ -2068,7 +2222,7 @@ format_status(Opt, [_PDict,State,Data]) ->
<p>
One reason to use this is when you have a state item
that when changed should cancel the
- <seealso marker="#State Time-Outs">State Time-Out</seealso>,
+ <seealso marker="#State Time-Outs">state time-out</seealso>,
or one that affects the event handling
in combination with postponing events.
We will go for the latter and complicate the previous example
@@ -2104,7 +2258,7 @@ x
so it is not to be recognized as the lock button.
Or we can make the lock button part of the state so
when we then change the lock button in the locked state,
- the change becomes a state change
+ the change becomes a <em>state change</em>
and all postponed events are retried,
therefore the lock is immediately locked!
</p>
@@ -2258,7 +2412,7 @@ handle_event(enter, _OldState, {open,_}, _Data) ->
</p>
<p>
Another not uncommon scenario is to use the
- <seealso marker="#Event Time-Outs">Event Time-Out</seealso>
+ <seealso marker="#Event Time-Outs">event time-out</seealso>
to trigger hibernation after a certain time of inactivity.
There is also a server start option
<seealso marker="stdlib:gen_statem#type-hibernate_after_opt">
diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml
index 06ca44a9f6..321fa41e8d 100644
--- a/system/doc/design_principles/sup_princ.xml
+++ b/system/doc/design_principles/sup_princ.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -312,12 +312,17 @@ child_spec() = #{id => child_id(), % mandatory
signal back. If no exit signal is received within
the specified time, the child process is unconditionally
terminated using <c>exit(Child, kill)</c>.</item>
- <item>If the child process is another supervisor, it is to be
+ <item>If the child process is another supervisor, it must be
set to <c>infinity</c> to give the subtree enough time to
shut down. It is also allowed to set it to <c>infinity</c>,
- if the child process is a worker. See the warning below:</item>
+ if the child process is a worker. See the warning below:</item>
</list>
<warning>
+ <p>Setting the shutdown time to anything other
+ than <c>infinity</c> for a child of type <c>supervisor</c>
+ can cause a race condition where the child in question
+ unlinks its own children, but fails to terminate them
+ before it is killed.</p>
<p>Be careful when setting the shutdown time to
<c>infinity</c> when the child process is a worker. Because, in this
situation, the termination of the supervision tree depends on the
diff --git a/system/doc/efficiency_guide/binaryhandling.xml b/system/doc/efficiency_guide/binaryhandling.xml
index b500329ef9..d92da17390 100644
--- a/system/doc/efficiency_guide/binaryhandling.xml
+++ b/system/doc/efficiency_guide/binaryhandling.xml
@@ -384,8 +384,8 @@ export ERL_COMPILER_OPTIONS=bin_opt_info]]></code>
<p>The warnings look as follows:</p>
<code type="erl"><![CDATA[
-./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: sub binary is used or returned
-./efficiency_guide.erl:62: Warning: OPTIMIZED: creation of sub binary delayed]]></code>
+./efficiency_guide.erl:60: Warning: NOT OPTIMIZED: binary is returned from the function
+./efficiency_guide.erl:62: Warning: OPTIMIZED: match context reused]]></code>
<p>To make it clearer exactly what code the warnings refer to, the
warnings in the following examples are inserted as comments
@@ -393,10 +393,10 @@ export ERL_COMPILER_OPTIONS=bin_opt_info]]></code>
<code type="erl"><![CDATA[
after_zero(<<0,T/binary>>) ->
- %% NOT OPTIMIZED: sub binary is used or returned
+ %% BINARY CREATED: binary is returned from the function
T;
after_zero(<<_,T/binary>>) ->
- %% OPTIMIZED: creation of sub binary delayed
+ %% OPTIMIZED: match context reused
after_zero(T);
after_zero(<<>>) ->
<<>>.]]></code>
diff --git a/system/doc/efficiency_guide/profiling.xml b/system/doc/efficiency_guide/profiling.xml
index cdc80289cf..5ec1f1be6e 100644
--- a/system/doc/efficiency_guide/profiling.xml
+++ b/system/doc/efficiency_guide/profiling.xml
@@ -94,7 +94,7 @@
<p>The above slogan is one of the more common reasons for Erlang to terminate.
For unknown reasons the Erlang Run-Time System failed to allocate memory to
use. When this happens a crash dump is generated that contains information
- about the state of the system as it ran out of mmeory. Use the
+ about the state of the system as it ran out of memory. Use the
<seealso marker="observer:cdv"><c>crashdump_viewer</c></seealso> to get a
view of the memory is being used. Look for processes with large heaps or
many messages, large ets tables, etc.</p>
diff --git a/system/doc/embedded/starting.xml b/system/doc/embedded/starting.xml
index 11bf9b412a..6888f9c959 100644
--- a/system/doc/embedded/starting.xml
+++ b/system/doc/embedded/starting.xml
@@ -231,7 +231,7 @@ exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $* <
<p>If a diskless and/or read-only client node with the SASL
configuration parameter <c>static_emulator</c> set to <c>true</c>
is about to start the <c>-boot</c> and <c>-config</c> flags must be
- changed. As such a client can not read a new <c>start_erl.data</c>
+ changed. As such a client cannot read a new <c>start_erl.data</c>
file (the file is not possible to change dynamically) the boot and
config files is always fetched from the same place (but with a new
contents if a new release has been installed). The
diff --git a/system/doc/oam/oam_intro.xml b/system/doc/oam/oam_intro.xml
index ead8c026b9..3d08a5f3b1 100644
--- a/system/doc/oam/oam_intro.xml
+++ b/system/doc/oam/oam_intro.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2017</year>
+ <year>1997</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -178,7 +178,7 @@
<section>
<title>MIB Structure</title>
<p>The top-level OTP MIB is called <c>OTP-REG</c> and it is
- included in the SASL application. All other OTP MIBs
+ included in the SNMP application. All other OTP MIBs
import some objects from this MIB.</p>
<p>Each MIB is contained in one application. The MIB text
@@ -186,67 +186,44 @@
the application directory. The generated <c>.hrl</c> files
with constant declarations are stored under
<c><![CDATA[include/<MIB>.hrl]]></c>, and the compiled MIBs
- are stored under <c><![CDATA[priv/mibs/<MIB>.bin]]></c>.
- For example, the <c>OTP-MIB</c> is included in the
- SASL application:</p>
+ are stored under <c><![CDATA[priv/mibs/<MIB>.bin]]></c>. </p>
- <code type="none">
-sasl-1.3/mibs/OTP-MIB.mib
-include/OTP-MIB.hrl
-priv/mibs/OTP-MIB.bin</code>
-
- <p>An application that needs to import this MIB into another
+ <p>An application that needs to import an MIB into another
MIB is to use the <c>il</c> option to the SNMP MIB compiler:</p>
<code type="none">
-snmp:c("MY-MIB", [{il, ["sasl/priv/mibs"]}]).</code>
+snmp:c("MY-MIB", [{il, ["snmp/priv/mibs"]}]).</code>
- <p>If the application needs to include the generated
+ <p>If the application needs to include a generated
<c>.hrl</c> file, it is to use the <c>-include_lib</c>
directive to the Erlang compiler:</p>
<code type="none">
-module(my_mib).
--include_lib("sasl/include/OTP-MIB.hrl").</code>
+-include_lib("snmp/include/OTP-REG.hrl").</code>
- <p>The following MIBs are defined in the OTP system:</p>
+ <p>Here is a list of some of the MIBs defined in the OTP system:</p>
<list type="bulleted">
- <item><p><c>OTP-REG</c> (in SASL) contains the top-level
+ <item><p><c>OTP-REG</c> (in SNMP) contains the top-level
OTP registration objects, used by all other MIBs.</p></item>
- <item><p><c>OTP-TC</c> (in SASL) contains the general
+ <item><p><c>OTP-TC</c> (in SNMP) contains the general
Textual Conventions, which can be used by any other MIB.</p></item>
- <item><p><c>OTP-MIB</c> (in SASL) contains objects for
- instrumentation of the Erlang nodes, the Erlang machines,
- and the applications in the system.</p></item>
- <item><p><c>OTP-OS-MON-MIB</c> (in <c>oc_mon</c>) contains
- objects for instrumentation of disk, memory, and CPU use
- of the nodes in the system.</p></item>
<item><p><c>OTP-SNMPEA-MIB</c> (in <c>snmp</c>)
contains objects for instrumentation and control of the extensible
SNMP agent itself. The agent also implements the standard SNMPv2-MIB
(or v1 part of MIB-II, if SNMPv1 is used).</p></item>
- <item><p><c>OTP-EVA-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the events and alarms in
- the system.</p></item>
- <item><p><c>OTP-LOG-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the logs and FTP transfer of
- logs.</p></item>
- <item><p><c>OTP-EVA-LOG-MIB</c> (in <c>eva</c>) contains objects
- for instrumentation and control of the events and alarm logs
- in the system.</p></item>
- <item><p><c>OTP-SNMPEA-LOG-MIB</c> (in <c>eva</c>) contains
- objects for instrumentation and control of the SNMP audit
- trail log in the system.</p></item>
</list>
<p>The different applications use different strategies for
loading the MIBs into the agent. Some MIB implementations are
code-only, while others need a server. One way, used by the
code-only MIB implementations, is for the user to call a
- function such as <c>otp_mib:load(Agent)</c> to load the MIB,
- and <c>otp_mib:unload(Agent)</c> to unload the MIB. See the
- manual page for each application for a description of how
- to load each MIB.</p>
+ function such as
+ <c>snmpa:unload_mibs(Agent, [Mib])</c>
+ to load the MIB, and
+ <c>snmpa:unload_mibs(Agent, [Mib])</c>
+ to unload the MIB. See the manual page for each application for
+ a description of how to load each MIB.</p>
</section>
</section>
</chapter>
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index 94e40dd077..8c47070890 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -567,6 +567,10 @@ Expr1 <input>op</input> Expr2</pre>
order is defined:</p>
<pre>
number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map &lt; nil &lt; list &lt; bit string</pre>
+ <p><c>nil</c> in the previous expression represents the empty list
+ (<c>[]</c>), which is regarded as a separate type from
+ <c>list/0</c>. That is why <c>nil &lt; list</c>.
+ </p>
<p>Lists are compared element by element. Tuples are ordered by
size, two tuples with the same size are compared element by
element.</p>
@@ -574,6 +578,7 @@ number &lt; atom &lt; reference &lt; fun &lt; port &lt; pid &lt; tuple &lt; map
ascending term order and then by values in key order.
In maps key order integers types are considered less than floats types.
</p>
+ <p>Atoms are compared using their string value, codepoint by codepoint.</p>
<p>When comparing an integer to a float, the term with the lesser
precision is converted into the type of the other term, unless the
operator is one of <c>=:=</c> or <c>=/=</c>. A float is more precise than
diff --git a/system/doc/reference_manual/typespec.xml b/system/doc/reference_manual/typespec.xml
index f6a19397c3..27cd0ba83d 100644
--- a/system/doc/reference_manual/typespec.xml
+++ b/system/doc/reference_manual/typespec.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2017</year>
+ <year>2003</year><year>2018</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -113,8 +113,8 @@
| Erlang_Atom %% 'foo', 'bar', ...
Bitstring :: <<>>
- | <<_:M>> %% M is a positive integer
- | <<_:_*N>> %% N is a positive integer
+ | <<_:M>> %% M is an Integer_Value that evaluates to a positive integer
+ | <<_:_*N>> %% N is an Integer_Value that evaluates to a positive integer
| <<_:M, _:_*N>>
Fun :: fun() %% any function
@@ -123,8 +123,17 @@
| fun((TList) -> Type)
Integer :: integer()
- | Erlang_Integer %% ..., -1, 0, 1, ... 42 ...
- | Erlang_Integer..Erlang_Integer %% specifies an integer range
+ | Integer_Value
+ | Integer_Value..Integer_Value %% specifies an integer range
+
+ Integer_Value :: Erlang_Integer %% ..., -1, 0, 1, ... 42 ...
+ | Erlang_Character %% $a, $b ...
+ | Integer_Value BinaryOp Integer_Value
+ | UnaryOp Integer_Value
+
+ BinaryOp :: '*' | 'div' | 'rem' | 'band' | '+' | '-' | 'bor' | 'bxor' | 'bsl' | 'bsr'
+
+ UnaryOp :: '+' | '-' | 'bnot'
List :: list(Type) %% Proper list ([]-terminated)
| maybe_improper_list(Type1, Type2) %% Type1=contents, Type2=termination
@@ -151,8 +160,13 @@
Union :: Type1 | Type2
]]></pre>
<p>
+ Integer values are either integer or character literals or expressions
+ consisting of possibily nested unary or binary operations that evaluate to
+ an integer. Such expressions can also be used in bit strings and ranges.
+ </p>
+ <p>
The general form of bit strings is <c>&lt;&lt;_:M, _:_*N&gt;&gt;</c>,
- where <c>M</c> and <c>N</c> are positive integers. It denotes a
+ where <c>M</c> and <c>N</c> must evaluate to positive integers. It denotes a
bit string that is <c>M + (k*N)</c> bits long (that is, a bit string that
starts with <c>M</c> bits and continues with <c>k</c> segments of
<c>N</c> bits each, where <c>k</c> is also a positive integer).
diff --git a/system/doc/system_principles/versions.xml b/system/doc/system_principles/versions.xml
index 11dc9d5637..fbdcc6b2b0 100644
--- a/system/doc/system_principles/versions.xml
+++ b/system/doc/system_principles/versions.xml
@@ -181,7 +181,7 @@
goes for application versions.</p>
<p>In general, versions can have more than three parts.
The versions are then only partially ordered. Such
- versions are only used in exceptional cases. When an extra
+ versions are only used when branching off from another branch. When an extra
part (out of the normal three parts) is added to a version number,
a new branch of versions is made. The new branch has a linear
order against the base version. However, versions on different
@@ -240,6 +240,33 @@
</section>
<section>
+ <marker id="otp_versions_tree"/>
+ <title>OTP Versions Tree</title>
+ <p>
+ All released OTP versions can be found in the
+ <url href="http://www.erlang.org/download/otp_versions_tree.html">OTP
+ Versions Tree</url> which is automatically updated whenever
+ we release a new OTP version. Note that every version number as
+ such explicitly define its position in the version tree. Nothing
+ more than the version numbers are needed in order to construct
+ the tree. The root of the tree is OTP version 17.0 which is when
+ we introduced the new
+ <seealso marker="#version_scheme">version scheme</seealso>. The
+ green versions are normal versions released on the main track.
+ Old <seealso marker="#releases_and_patches">OTP releases</seealso>
+ will be maintained for a while on <c>maint</c> branches that have
+ branched off from the main track. Old <c>maint</c> branches always
+ branch off from the main track when the next OTP release is
+ introduced into the main track. Versions on these old <c>maint</c>
+ branches are marked blue. Besides the green and blue versions,
+ there are also gray versions. These are versions on branches
+ introduced in order to fix a specific problem for a specific
+ customer on a specific base version. Branches with gray versions
+ will typically become dead ends very quickly if not immediately.
+ </p>
+ </section>
+
+ <section>
<marker id="otp_17_0_app_versions"/>
<title>OTP 17.0 Application Versions</title>
<p>The following list details the application versions that